package ilarkesto.base.time; import ilarkesto.base.Str; import ilarkesto.base.Tm; import ilarkesto.base.Utl; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Locale; import java.util.StringTokenizer; public final class Date implements Comparable<Date> { public static final transient SimpleDateFormat FORMAT_DAY_MONTH_SHORTYEAR = new SimpleDateFormat("dd.MM.yy"); public static final transient SimpleDateFormat FORMAT_DAY_MONTH_YEAR = new SimpleDateFormat("dd.MM.yyyy"); public static final transient SimpleDateFormat FORMAT_LONGMONTH_DAY_YEAR = new SimpleDateFormat("MMMM d, yyyy"); public static final transient SimpleDateFormat FORMAT_DAY_MONTH = new SimpleDateFormat("dd.MM."); public static final transient SimpleDateFormat FORMAT_WEEKDAY_DAY_MONTH = new SimpleDateFormat("EEEE, dd.MM."); public static final transient SimpleDateFormat FORMAT_DAY_LONGMONTH_YEAR = new SimpleDateFormat("dd. MMMM yyyy"); public static final transient SimpleDateFormat FORMAT_WEEKDAY_DAY_LONGMONTH_YEAR = new SimpleDateFormat( "EEEE, dd. MMMM yyyy"); public static final transient SimpleDateFormat FORMAT_SHORTWEEKDAY_DAY_MONTH_YEAR = new SimpleDateFormat( "EE, dd.MM.yyyy"); public static final transient SimpleDateFormat FORMAT_LONGMONTH = new SimpleDateFormat("MMMM"); public static final transient SimpleDateFormat FORMAT_LONGMONTH_YEAR = new SimpleDateFormat("MMMM yyyy"); public static final transient SimpleDateFormat FORMAT_YEAR_MONTH_DAY = new SimpleDateFormat("yyyy-MM-dd"); public static final transient SimpleDateFormat FORMAT_YEAR_MONTH_DAY_NOSEP = new SimpleDateFormat("yyyyMMdd"); public static final transient SimpleDateFormat FORMAT_WEEKDAY = new SimpleDateFormat("EEEE"); private int year; private int month; private int day; public Date() { this(System.currentTimeMillis()); } public Date(GregorianCalendar calendar) { set(calendar); } public Date(java.util.Date date) { set(date); } public Date(long millis) { set(new java.util.Date(millis)); } public Date(int year, int month, int day) { set(year, month, day); } public Date(String date) { try { parse(date); } catch (ParseException ex) { throw new RuntimeException(ex); } } private void set(java.util.Date date) { GregorianCalendar calendar = new GregorianCalendar(); calendar.setTime(date); set(calendar); } private void set(GregorianCalendar calendar) { set(calendar.get(GregorianCalendar.YEAR), calendar.get(GregorianCalendar.MONTH) + 1, calendar.get(GregorianCalendar.DAY_OF_MONTH)); } private void set(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } private void parse(String date) throws ParseException { StringTokenizer tokenizer = new StringTokenizer(date.trim(), "-"); if (!tokenizer.hasMoreTokens()) throw new ParseException(date, 0); int y = Integer.parseInt(tokenizer.nextToken()); int m = 1; if (tokenizer.hasMoreTokens()) m = Integer.parseInt(tokenizer.nextToken()); int d = 1; if (tokenizer.hasMoreTokens()) d = Integer.parseInt(tokenizer.nextToken()); set(y, m, d); } public int getDay() { return day; } public int getMonth() { return month; } public int getYear() { return year; } public GregorianCalendar getGregorianCalendar() { return new GregorianCalendar(year, month - 1, day); } public Date addDays(int count) { GregorianCalendar c = new GregorianCalendar(); c.setTime(toJavaDate()); c.add(GregorianCalendar.DAY_OF_YEAR, count); return new Date(c); } public Date getFirstDateOfMonth() { GregorianCalendar c = new GregorianCalendar(); c.setTime(toJavaDate()); c.set(GregorianCalendar.DAY_OF_MONTH, 1); return new Date(c); } public Date getLastDateOfMonth() { GregorianCalendar c = new GregorianCalendar(); c.setTime(toJavaDate()); c.set(GregorianCalendar.DAY_OF_MONTH, c.getActualMaximum(GregorianCalendar.DAY_OF_MONTH)); return new Date(c); } public Date addMonths(int count) { GregorianCalendar c = new GregorianCalendar(); c.setTime(toJavaDate()); c.add(GregorianCalendar.MONTH, count); return new Date(c); } public Date addYears(int count) { GregorianCalendar c = new GregorianCalendar(); c.setTime(toJavaDate()); c.add(GregorianCalendar.YEAR, count); return new Date(c); } public Weekday getWeekday() { return Weekday.get(getGregorianCalendar().get(Calendar.DAY_OF_WEEK)); } public int getWeek() { return getGregorianCalendar().get(GregorianCalendar.WEEK_OF_YEAR); } public int getDaysInMonth() { return getGregorianCalendar().getActualMaximum(GregorianCalendar.DAY_OF_MONTH); } public TimePeriod getPeriodTo(Date other) { return new TimePeriod(other.toMillis() - toMillis()); } public TimePeriod getPeriodToNow() { return getPeriodTo(today()); } public int getPeriodToInMonths(Date other) { int years = other.year - year; int months = other.month - month; return (years * 12) + months; } public int getPeriodToNowInMonths() { return getPeriodToInMonths(today()); } private String toDe() { StringBuilder sb = new StringBuilder(); if (day < 10) sb.append('0'); sb.append(day); sb.append("."); if (month < 10) sb.append('0'); sb.append(month); sb.append("."); sb.append(year); return sb.toString(); } public String toLongDe() { StringBuilder sb = new StringBuilder(); sb.append(Tm.WEEKDAYS_DE[getGregorianCalendar().get(GregorianCalendar.DAY_OF_WEEK) - 1]); sb.append(", der "); sb.append(toDe()); return sb.toString(); } private String toInt() { StringBuilder sb = new StringBuilder(); sb.append(year); sb.append("-"); if (month < 10) sb.append('0'); sb.append(month); sb.append("-"); if (day < 10) sb.append('0'); sb.append(day); return sb.toString(); } public String toLongInt() { StringBuilder sb = new StringBuilder(); sb.append(Tm.WEEKDAYS[getGregorianCalendar().get(GregorianCalendar.DAY_OF_WEEK) - 1]); sb.append(", the "); sb.append(toInt()); return sb.toString(); } public String toString(DateFormat format) { return format.format(toJavaDate()); } public String toString(Locale locale) { if (locale.equals(Locale.GERMANY)) return toDe(); return toInt(); } public String toLongString(Locale locale) { if (locale.equals(Locale.GERMANY)) return toLongDe(); return toLongInt(); } public java.util.Date toJavaDate() { return getGregorianCalendar().getTime(); } public long toMillis() { return getGregorianCalendar().getTimeInMillis(); } public Date nextDay() { GregorianCalendar gc = (GregorianCalendar) getGregorianCalendar().clone(); gc.add(GregorianCalendar.DAY_OF_YEAR, 1); return new Date(gc); } // --- static --- private static transient Date today; private static transient long todayInvalidTime; public static Date latest(Date... dates) { Date latest = null; for (Date date : dates) { if (latest == null || date.isAfter(latest)) latest = date; } return latest; } public static Date earliest(Date... dates) { Date earliest = null; for (Date date : dates) { if (earliest == null || date.isBefore(earliest)) earliest = date; } return earliest; } public static Date today() { if (today == null || System.currentTimeMillis() > todayInvalidTime) { today = new Date(); todayInvalidTime = tomorrow().toJavaDate().getTime() - 1; } return today; } public static Date tomorrow() { return new Date(System.currentTimeMillis() + Tm.DAY); } public static Date inDays(int numberOfDays) { return new Date(System.currentTimeMillis() + (Tm.DAY * numberOfDays)); } public static Date beforeDays(int numberOfDays) { return new Date(System.currentTimeMillis() - (Tm.DAY * numberOfDays)); } public static Date randomPast(int beforeMaxDays) { return Date.beforeDays(Utl.randomInt(0, beforeMaxDays)); } public static Date parseTolerant(String s) throws ParseException { s = s.trim(); String[] sa = Str.tokenize(s, ".,- "); if (sa.length == 0) throw new ParseException("Not a Date: " + s, -1); if (sa.length > 3) throw new ParseException("Not a Date: " + s, -1); int[] ia = new int[sa.length]; for (int i = 0; i < ia.length; i++) { try { ia[i] = Integer.parseInt(sa[i]); } catch (NumberFormatException e) { throw new ParseException("Not a Date: " + s, -1); } } if (ia.length == 3) return new Date(Tm.year(ia[2]), ia[1], ia[0]); Date today = today(); if (ia.length == 2) { if (ia[1] > 12) return new Date(Tm.year(ia[1]), ia[0], today.day); return new Date(today.year, ia[1], ia[0]); } if (ia[0] > 31) return new Date(Tm.year(ia[0]), today.month, today.day); return new Date(today.year, today.month, ia[0]); } // --- Object --- @Override public String toString() { return toInt(); } private transient int hashCode; @Override public int hashCode() { if (hashCode == 0) { hashCode = 23; hashCode = hashCode * 37 + year; hashCode = hashCode * 37 + month; hashCode = hashCode * 37 + day; } return hashCode; } @Override public boolean equals(Object obj) { if (obj == null) return false; Date other = (Date) obj; return other.day == day && other.month == month && other.year == year; } public boolean equalsIgnoreYear(Date d) { if (d == null) return false; return d.day == day && d.month == month; } public boolean equalsIgnoreDay(Date d) { if (d == null) return false; return d.year == year && d.month == month; } public boolean isBefore(Date other) { return compareTo(other) < 0; } public boolean isBeforeOrSame(Date other) { return compareTo(other) <= 0; } public boolean isAfter(Date other) { return compareTo(other) > 0; } public boolean isAfterOrSame(Date other) { return compareTo(other) >= 0; } public boolean isWeekend() { return getWeekday() == Weekday.SATURDAY || getWeekday() == Weekday.SUNDAY; } public boolean isToday() { return equals(today()); } public boolean isTomorrow() { return equals(today().addDays(1)); } public boolean isYesterday() { return equals(today().addDays(-1)); } public boolean isFuture() { return isAfter(today()); } public boolean isFutureOrToday() { return isAfterOrSame(today()); } public boolean isPast() { return isBefore(today()); } public boolean isPastOrToday() { return isBeforeOrSame(today()); } // --- Comparable --- public int compareTo(Date other) { if (other == null) return 1; if (year > other.year) return 1; if (year < other.year) return -1; if (month > other.month) return 1; if (month < other.month) return -1; if (day > other.day) return 1; if (day < other.day) return -1; return 0; } }