package chatty.util;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
/**
* Stuff to do with dates/time.
*
* @author tduva
*/
public class DateTime {
private static final SimpleDateFormat FULL_DATETIME = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZ");
private static final SimpleDateFormat SDF = new SimpleDateFormat("HH:mm:ss");
private static final SimpleDateFormat SDF2 = new SimpleDateFormat("HH:mm");
public static final long MINUTE = 60;
public static final long HOUR = MINUTE * 60;
public static final long DAY = HOUR * 24;
public static final long YEAR = DAY * 365;
public static int currentHour12Hour() {
Calendar cal = Calendar.getInstance();
return cal.get(Calendar.HOUR);
}
public static String currentTime(SimpleDateFormat sdf) {
synchronized(sdf) {
Calendar cal = Calendar.getInstance();
return sdf.format(cal.getTime());
}
}
public static String fullDateTime() {
return currentTime(FULL_DATETIME);
}
public static String currentTime() {
return currentTime(SDF);
}
public static String currentTime(String format) {
return currentTime(new SimpleDateFormat(format));
}
public static String format(long time, SimpleDateFormat sdf) {
synchronized(sdf) {
return sdf.format(new Date(time));
}
}
public static String format(long time) {
return format(time, SDF);
}
public static String formatFullDatetime(long time) {
return format(time, FULL_DATETIME);
}
public static String format2(long time) {
return format(time, SDF2);
}
public static String formatAccountAge(long time, Formatting... options) {
if (System.currentTimeMillis() - time > DAY*1000) {
return ago(time, 0, 2, DateTime.H, options);
}
return ago(time, 0, 1, 0, options);
}
public static String agoText(long time) {
long seconds = (System.currentTimeMillis() - time) / 1000;
if (seconds < MINUTE*10) {
return "just now";
}
if (seconds < HOUR) {
return "recently";
}
if (seconds < DAY) {
long hours = seconds / HOUR;
return hours+" "+(hours == 1 ? "hour" : "hours")+" ago";
}
if (seconds < YEAR) {
long days = seconds / DAY;
return days + " " + (days == 1 ? "day" : "days") + " ago";
}
long years = seconds / YEAR;
return years+" "+(years == 1 ? "year" : "years")+" ago";
}
public static String agoClock(long time, boolean showSeconds) {
long timePassed = System.currentTimeMillis() - time;
long seconds = timePassed / 1000;
return durationClock(seconds, showSeconds);
}
public static String durationClock(long seconds, boolean showSeconds) {
long hours = seconds / HOUR;
seconds = seconds % HOUR;
long minutes = seconds / MINUTE;
seconds = seconds % MINUTE;
if (showSeconds)
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
return String.format("%02d:%02d", hours, minutes, seconds);
}
public static String agoSingleCompact(long time) {
return DateTime.ago(time, 0, 1, 0);
}
public static String agoSingleVerbose(long time) {
return duration(System.currentTimeMillis() - time, 1, 0,
Formatting.VERBOSE);
}
public static String agoUptimeCompact(long time) {
long ago = System.currentTimeMillis() - time;
if (ago < (1000*HOUR)) {
return duration(ago, 0, 0, S);
}
return duration(ago, H, 0, M, Formatting.LAST_ONE_EXACT);
}
public static String agoUptimeCompact2(long time) {
long seconds = (System.currentTimeMillis() - time)/1000;
long hours = seconds/HOUR;
long minutes = (seconds%HOUR) / MINUTE;
if (hours > 0) {
return String.format("%dh %dm", hours, minutes);
}
return String.format("%dm", minutes);
}
public static enum Formatting {
COMPACT, VERBOSE, LEADING_ZERO_VALUES, NO_ZERO_VALUES, NO_SPACES,
LAST_ONE_EXACT
}
private static final String[] TIMENAMES_COMPACT = {"y", "d", "h", "m", "s"};
private static final String[] TIMENAMES_VERBOSE = {" years", " days", " hours", " minutes", " seconds"};
public static final int S = 1;
public static final int M = 2;
public static final int H = 3;
public static final int D = 4;
public static final int N = 0;
public static String ago(long time, Formatting... options) {
return duration(System.currentTimeMillis() - time, options);
}
public static String ago(long milliseconds, int upperLimit, int max,
int lowerLimit, Formatting... options) {
return duration(System.currentTimeMillis() - milliseconds, upperLimit,
max, lowerLimit, options);
}
public static String duration(long milliseconds, Formatting... options) {
return duration(milliseconds, 0, 0, options);
}
public static String duration(long milliseconds, int max, int lowerLimit, Formatting... options) {
return duration(milliseconds, 0, max, lowerLimit, options);
}
public static String duration(long milliseconds, int upperLimit, int max,
int lowerLimit, Formatting... options) {
return duration(milliseconds, upperLimit, max, lowerLimit, 1, options);
}
public static String duration(long seconds, int upperLimit, int max,
int lowerLimit, int min, Formatting... options) {
List<Formatting> options2 = Arrays.asList(options);
boolean leadingZeroValues = options2.contains(Formatting.LEADING_ZERO_VALUES);
boolean noZeroValues = options2.contains(Formatting.NO_ZERO_VALUES);
boolean verbose = options2.contains(Formatting.VERBOSE);
boolean lastOneExact = options2.contains(Formatting.LAST_ONE_EXACT);
String sep = " ";
if (options2.contains(Formatting.NO_SPACES)) {
sep = "";
}
boolean negative = false;
if (seconds < 0) {
seconds = -seconds;
negative = true;
}
double[] times = getTimes(seconds, TIME_DEF, upperLimit);
String[] timeNames = verbose ? TIMENAMES_VERBOSE : TIMENAMES_COMPACT;
StringBuilder b = new StringBuilder();
int shown = 0;
int shownNonzero = 0;
for (int i=0;i<times.length;i++) {
int left = times.length - i;
int time = (int)times[i];
// if (shown >= max && max > 0) {
// break;
// }
// if (left <= lowerLimit && shown > 0) {
// break;
// }
if (time == 0) {
if ((left > lowerLimit+min) || shown >= min) {
if (noZeroValues) {
continue;
} else if (!leadingZeroValues && shownNonzero == 0) {
continue;
}
}
}
if (shown > 0) {
b.append(sep);
} else if (negative) {
b.append("-");
}
/**
* Now considered shown
*/
shown++;
boolean lastOne = shown >= max && max > 0
|| left-1 <= lowerLimit && shown > 0;
String timeName = timeNames[i+timeNames.length-times.length];
if (time == 1 && verbose) {
timeName = timeName.substring(0, timeName.length() - 1);
}
if (lastOne && lastOneExact) {
// Substract for rounding down with one digit precision
double exact = times[i] - 0.05;
b.append(String.format(Locale.ENGLISH, "%.1f", exact));
} else {
b.append(time);
}
b.append(timeName);
if (time > 0) {
shownNonzero++;
}
if (lastOne) {
break;
}
}
return b.toString();
}
private static final long[] TIME_DEF = {YEAR, DAY, HOUR, MINUTE, 1};
public static double[] getTimes(long input, long[] timeDef, int upperLimit) {
double seconds = (double)(input / 1000);
if (upperLimit <= 0 || upperLimit > timeDef.length) {
upperLimit = timeDef.length;
}
double[] result = new double[upperLimit];
int offset = timeDef.length - upperLimit;
for (int i=0;i<result.length;i++) {
long def = timeDef[i+offset];
result[i] = seconds / def;
seconds = seconds % def;
}
return result;
}
public static boolean isAprilFirst() {
Calendar cal = Calendar.getInstance();
return cal.get(Calendar.MONTH) == Calendar.APRIL
&& cal.get(Calendar.DAY_OF_MONTH) == 1;
}
/**
* Parses the time returned from the Twitch API.
*
* http://stackoverflow.com/a/2202300/2375667
*
* Switched to java.time now because DatatypeConverter isn't visible by
* default in Java 9 anymore.
*
* @param time The time string
* @return The timestamp
* @throws IllegalArgumentException if the time could not be parsed
*/
public static long parseDatetime(String time) {
OffsetDateTime odt = OffsetDateTime.parse(time);
return odt.toInstant().toEpochMilli();
}
public static final void main(String[] args) {
// System.out.println("'"+dur(HOUR*2+1, Formatting.COMPACT, 0, -2, 2, 2, 2)+"'");
// System.out.println("'"+duration(1000*MINUTE*1+1000, Formatting.COMPACT, N, 0, 0, 0, 2)+"'");
//System.out.println(agoSingleVerbose(System.currentTimeMillis() ));
//System.out.println(ago(System.currentTimeMillis() - 1000*60*60*25));
// System.out.println(duration(1000*(HOUR*2), 0, 0, 0, 1, Formatting.LAST_ONE_EXACT));
System.out.println(agoUptimeCompact(System.currentTimeMillis() - 1000*(MINUTE*110)));
int a = 1 << 4;
int b = 1 << 5;
int c = 1 << 1;
int v = a | b;
//System.out.println(v ^ c);
// System.out.println("'"+duration(1000*1, 1, 2)+"'");
// System.out.println((long)1000*DAY*3000+1);
// System.out.println(durationFull(269467, false));
// System.out.println(formatFullDatetime((long)1427846400*1000));
// System.out.println(System.currentTimeMillis());
// try {
// long time = chatty.util.api.Util.parseTime("2015-04-01T00:00:00Z");
// System.out.println(time);
// System.out.println(formatFullDatetime(time));
// System.out.println(time / 1000);
// } catch (ParseException ex) {
// Logger.getLogger(DateTime.class.getName()).log(Level.SEVERE, null, ex);
// }
System.out.println(TimeUnit.HOURS.toMillis(1));
System.out.println(formatAccountAge(System.currentTimeMillis() - 2500*1000));
}
}