Development Class Java

/*  Dates.java
 {{IS_NOTE
 Purpose:
 Description:
 History:
 2001/12/3, Henri Chen: Created.
 }}IS_NOTE
 Copyright (C) 2001 Potix Corporation. All Rights Reserved.
 {{IS_RIGHT
 This program is distributed under GPL Version 3.0 in the hope that
 it will be useful, but WITHOUT ANY WARRANTY.
 }}IS_RIGHT
 */
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
 * Utilities for java.util.Date
 * 
 * @author henrichen
 * @author tomyeh
 */
public class Dates {
  /**
   * Truncates date to the nearest precision milliseconds. MS SQLServer2000 with
   * only the maximum accuracy of 1/300 seconds would not be able to store up to
   * one millisecond accurarcy. That is, User must round the millisecond to some
   * less precisions; or the data in that db would be inconsistence with that in
   * memory. It is useful to store a Date object in a database. Without
   * rounding, if you want to get it back and compare with the one in the
   * memory. See {@link #now} for details.
   * 
   * @param precision
   *          the divider of the precision(e.g. 10 for precision of 10
   *          milliseconds;i.e. all millisecond less than 10 would be truncated)
   * @see #now
   * @see #round(long, int)
   */
  public static final Date round(Date date, int precision) {
    date.setTime(round(date.getTime(), precision));
    return date;
  }
  /**
   * Rounds a date represented in long to the specified precision of
   * milliseconds.
   * 
   * @param time
   *          the date represented in long.
   * @param precision
   *          the divider of the precision(e.g. 10 for precision of 10
   *          milliseconds;i.e. all millisecond less than 10 would be truncated)
   * @see #now
   * @see #round(Date, int)
   */
  public static final long round(long time, int precision) {
    return time - (time % precision);
  }
  /**
   * Tests whether a date is rounded. It is mainly used for debugging.
   */
  public static final boolean isRounded(Date date, int precision) {
    return (date.getTime() % precision) == 0;
  }
  /**
   * Returns the current time but rounding to the specified precision of
   * milliseconds. It is useful if you want to create the current time which
   * will be stored in the database and want to compare it with something with
   * what you store in the database. Otherwise, that you get back the one you
   * store might be different, because the resolution of database timestamp is
   * usually less than one milisecond, e.g., MS SQL: 0.003 second.
   * 
   * 


   * If you don't cache it in the memory (remember entity beans always cache by
   * the container), you don't need to round. If you are not sure, round it.
   * 
   * @see #round(Date, int)
   */
  public static final Date now(int precision) {
    return new Date(round(System.currentTimeMillis(), precision));
  }
  /**
   * Returns the current time without rounding.
   */
  public static final Date now() {
    return new Date();
  }
  /**
   * Returns today by setting time to 0:0:0.
   */
  public static final Date today() {
    return beginOfDate(new Date(), null);
  }
  /**
   * Given a date, return the previouse date of the given date (24 hrs before).
   */
  final public static Date previousDate(Date when) {
    long time = when.getTime() - 24 * 60 * 60 * 1000;
    return new Date(time);
  }
  /**
   * Return the beginning date of this month.
   */
  final public static Date beginOfMonth() {
    return beginOfMonth(new Date(), null);
  }
  /**
   * Given a date, a proper TimeZone, return the beginning date of the month of
   * the specified date and TimeZone. If TimeZone is null, meaning use default
   * TimeZone of the JVM.
   */
  final public static Date beginOfMonth(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int year = cal.get(Calendar.YEAR);
    final int month = cal.get(Calendar.MONTH);
    cal.clear();
    cal.set(year, month, 1);
    return cal.getTime();
  }
  /**
   * Return the ending date of this month.
   */
  final public static Date endOfMonth() {
    return endOfMonth(new Date(), null);
  }
  /**
   * Given a date, a proper TimeZone, return the ending date of the month of the
   * specified date and TimeZone. If TimeZone is null, meaning use default
   * TimeZone of the JVM.
   */
  final public static Date endOfMonth(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int year = cal.get(Calendar.YEAR);
    final int month = cal.get(Calendar.MONTH);
    final int monthDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    cal.clear();
    cal.set(year, month, monthDays + 1);
    cal.setTimeInMillis(cal.getTimeInMillis() - 1);
    return cal.getTime();
  }
  /**
   * Whether the given date in the specified TimeZone is the last day of that
   * month. If TimeZone is null, meaning use default TimeZone of the JVM.
   */
  final public static boolean isEndOfMonth(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int day = cal.get(Calendar.DAY_OF_MONTH);
    final int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    return day == maxDay;
  }
  /**
   * Whether the given date in the specified TimeZone is the first day of that
   * month. If TimeZone is null, meaning use default TimeZone of the JVM.
   */
  final public static boolean isBeginOfMonth(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int day = cal.get(Calendar.DAY_OF_MONTH);
    return day == 1;
  }
  /**
   * Given a date, a proper TimeZone, return the beginning date of the specified
   * date and TimeZone. If TimeZone is null, meaning use Defult TimeZone of the
   * JVM.
   */
  final public static Date beginOfDate(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime());// don't call cal.setTime(Date) which
                                        // will reset the TimeZone.
    final int day = cal.get(Calendar.DAY_OF_MONTH);
    final int year = cal.get(Calendar.YEAR);
    final int month = cal.get(Calendar.MONTH);
    cal.clear();
    cal.set(year, month, day);
    return cal.getTime();
  }
  /**
   * Given a date, a proper TimeZone, return the last millisecond date of the
   * specified date and TimeZone. If TimeZone is null, meaning use Defult
   * TimeZone of the JVM.
   */
  final public static Date endOfDate(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime());// don't call cal.setTime(Date) which
                                        // will reset the TimeZone.
    final int day = cal.get(Calendar.DAY_OF_MONTH);
    final int year = cal.get(Calendar.YEAR);
    final int month = cal.get(Calendar.MONTH);
    cal.clear();
    cal.set(year, month, day + 1);
    cal.setTimeInMillis(cal.getTimeInMillis() - 1);
    return cal.getTime();
  }
  /**
   * Return the beginning date of this year.
   */
  final public static Date beginOfYear() {
    return beginOfYear(new Date(), null);
  }
  /**
   * Given a date, a proper TimeZone, return the beginning date of the month of
   * the specified date and TimeZone. If TimeZone is null, meaning use default
   * TimeZone of the JVM.
   */
  final public static Date beginOfYear(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int year = cal.get(Calendar.YEAR);
    cal.clear();
    cal.set(year, Calendar.JANUARY, 1);
    return cal.getTime();
  }
  /**
   * Return the ending date of this year.
   */
  final public static Date endOfYear() {
    return endOfYear(new Date(), null);
  }
  /**
   * Given a date, a proper TimeZone, return the ending date of the month of the
   * specified date and TimeZone. If TimeZone is null, meaning use default
   * TimeZone of the JVM.
   */
  final public static Date endOfYear(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int year = cal.get(Calendar.YEAR);
    cal.clear();
    cal.set(year + 1, Calendar.JANUARY, 1);
    cal.setTimeInMillis(cal.getTimeInMillis() - 1);
    return cal.getTime();
  }
  /**
   * Return the ending date of this year.
   */
  final public static short twoMonthShort() {
    return twoMonthShort(new Date(), null);
  }
  /**
   * Given a date, a proper TimeZone, return the two month int. eg. 1, 3, 5, 7,
   * 9, 11. If TimeZone is null, meaning use default TimeZone of the JVM.
   */
  final public static short twoMonthShort(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final int month = (cal.get(Calendar.MONTH) / 2) * 2 + 1;
    return (short) month;
  }
  /**
   * Get the year of a date.
   * 
   * @param when
   *          The date.
   * @param tz
   *          The time zone; if null, the current time zone is assumed.
   * @see #localizedYearOfDate
   */
  public static final int yearOfDate(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    return cal.get(Calendar.YEAR);
  }
  /**
   * Get the year of a date in the specified locale.
   * 
   * 


   * Currenty, only Locale.ZH_TW is supported, i.e., "year - 1911" and it's may
   * be less than 0. Otherwise, it is the same as {@link #yearOfDate}.
   * 
   * @param when
   *          The date.
   * @param locale
   *          the locale; if null, the current locale is assumed.
   * @param tz
   *          The time zone; if null, the current time zone is assumed.
   * @see #yearOfDate
   */
  public static final int localizedYearOfDate(Date when, Locale locale, TimeZone tz) {
    final int year = yearOfDate(when, tz);
    if (locale.equals(Locale.TAIWAN))
      return year - 1911;
    return year;
  }
  /**
   * Get the month of a date. The first month of the year is JANUARY which is 0.
   * 
   * @param when
   *          The date.
   * @param tz
   *          The time zone; if null, the current time zone is assumed.
   */
  public static final int monthOfDate(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    return cal.get(Calendar.MONTH);
  }
  /**
   * Get the month of a date. The first month of the year is JANUARY which is 1.
   * 
   * @param when
   *          The date.
   * @param tz
   *          The time zone; if null, the current time zone is assumed.
   */
  public static final int monthOfDatePlus1(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    return cal.get(Calendar.MONTH) + 1;
  }
  /**
   * Get the day of month of a date. The first day of the month has value 1.
   * 
   * @param when
   *          The date.
   * @param tz
   *          The time zone; if null, the current time zone is assumed.
   */
  public static final int dayMonthOfDate(Date when, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime()); // don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    return cal.get(Calendar.DAY_OF_MONTH);
  }
  /**
   * Date Arithmetic function. Adds the specified (signed) amount of time to the
   * given date, based on the calendar's rules.
   * 
   * @param when
   *          The based date.
   * @param tz
   *          The time zone; if null, the current time zone is assumed.
   * @param field
   *          The time field.
   * @param amount
   *          The amount of date or time to be added to the field.
   */
  public static final Date add(Date when, TimeZone tz, int field, int amount) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(when.getTime());// don't call cal.setTime(Date) which
                                        // will reset the TimeZone.
    cal.add(field, amount);
    return cal.getTime();
  }
  /**
   * Date Arithmetic function (date2 - date1). subtract a date from another
   * date, return the difference as the required fields. E.g. if specified
   * Calendar.Date, the smaller range of fields is ignored and this method
   * return the difference of days.
   * 
   * @param date2
   *          The date2.
   * @param tz
   *          The time zone.
   * @param field
   *          The time field; e.g., Calendar.DATE, Calendar.YEAR, it's default
   *          value is Calendar.DATE
   * @param date1
   *          The date1.
   */
  public static final long subtract(Date date2, TimeZone tz, int field, Date date1) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    boolean negative = false;
    if (date1.after(date2)) {
      negative = true;
      final Date d = date1;
      date1 = date2;
      date2 = d;
    }
    final Calendar cal1 = Calendar.getInstance(tz);
    cal1.setTimeInMillis(date1.getTime());// don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    final Calendar cal2 = Calendar.getInstance(tz);
    cal2.setTimeInMillis(date2.getTime());// don't call cal.setTime(Date) which
                                          // will reset the TimeZone.
    int year1 = cal1.get(Calendar.YEAR);
    int year2 = cal2.get(Calendar.YEAR);
    switch (field) {
    case Calendar.YEAR: {
      return negative ? (year1 - year2) : (year2 - year1);
    }
    case Calendar.MONTH: {
      int month1 = cal1.get(Calendar.MONTH);
      int month2 = cal2.get(Calendar.MONTH);
      int months = 12 * (year2 - year1) + month2 - month1;
      return negative ? -months : months;
    }
    case Calendar.HOUR: {
      long time1 = date1.getTime();
      long time2 = date2.getTime();
      long min1 = (time1 < 0 ? (time1 - (1000 * 60 * 60 - 1)) : time1) / (1000 * 60 * 60);
      long min2 = (time2 < 0 ? (time2 - (1000 * 60 * 60 - 1)) : time2) / (1000 * 60 * 60);
      return negative ? (min1 - min2) : (min2 - min1);
    }
    case Calendar.MINUTE: {
      long time1 = date1.getTime();
      long time2 = date2.getTime();
      long min1 = (time1 < 0 ? (time1 - (1000 * 60 - 1)) : time1) / (1000 * 60);
      long min2 = (time2 < 0 ? (time2 - (1000 * 60 - 1)) : time2) / (1000 * 60);
      return negative ? (min1 - min2) : (min2 - min1);
    }
    case Calendar.SECOND: {
      long time1 = date1.getTime();
      long time2 = date2.getTime();
      long sec1 = (time1 < 0 ? (time1 - (1000 - 1)) : time1) / 1000;
      long sec2 = (time2 < 0 ? (time2 - (1000 - 1)) : time2) / 1000;
      return negative ? (sec1 - sec2) : (sec2 - sec1);
    }
    case Calendar.MILLISECOND: {
      return negative ? (date1.getTime() - date2.getTime()) : (date2.getTime() - date1.getTime());
    }
    case Calendar.DATE:
    default: /* default, like -1 */
    {
      int day1 = cal1.get(Calendar.DAY_OF_YEAR);
      int day2 = cal2.get(Calendar.DAY_OF_YEAR);
      int maxDay1 = year1 == year2 ? 0 : cal1.getActualMaximum(Calendar.DAY_OF_YEAR);
      int days = maxDay1 - day1 + day2;
      final Calendar cal = Calendar.getInstance(tz);
      for (int year = year1 + 1; year < year2; year++) {
        cal.set(Calendar.YEAR, year);
        days += cal.getActualMaximum(Calendar.DAY_OF_YEAR);
      }
      return negative ? -days : days;
    }
    }
  }
  /**
   * merge the date part and time part of two specified dates into a date.
   * 
   * @param datePart
   *          The date part date.
   * @param timePart
   *          The time part date.
   * @param tz
   *          The time zone.
   */
  public static final Date merge(Date datePart, Date timePart, TimeZone tz) {
    if (tz == null)
      tz = TimeZones.getCurrent();
    final Calendar dateCal = Calendar.getInstance(tz);
    dateCal.setTimeInMillis(datePart.getTime());// don't call cal.setTime(Date)
                                                // which will reset the
                                                // TimeZone.
    final Calendar timeCal = Calendar.getInstance(tz);
    timeCal.setTimeInMillis(timePart.getTime());// don't call cal.setTime(Date)
                                                // which will reset the
                                                // TimeZone.
    final int hour = timeCal.get(Calendar.HOUR);
    final int minute = timeCal.get(Calendar.MINUTE);
    final int second = timeCal.get(Calendar.SECOND);
    final int msillisecond = timeCal.get(Calendar.MILLISECOND);
    dateCal.set(Calendar.HOUR, hour);
    dateCal.set(Calendar.MINUTE, minute);
    dateCal.set(Calendar.SECOND, second);
    dateCal.set(Calendar.MILLISECOND, msillisecond);
    return dateCal.getTime();
  }
}
/*
 * TimeZones.java
 * 
 * {{IS_NOTE Purpose:
 * 
 * Description:
 * 
 * History: Mon Jun 12 12:17:03 2006, Created by tomyeh }}IS_NOTE
 * 
 * Copyright (C) 2006 Potix Corporation. All Rights Reserved.
 * 
 * {{IS_RIGHT }}IS_RIGHT
 */
/**
 * Utilities to access time-zone.
 * 
 * @author tomyeh
 */
class TimeZones {
  private static final InheritableThreadLocal _thdTZone = new InheritableThreadLocal();
  /**
   * Returns the current time zone; never null. This is the time zone that every
   * other objects shall use, unless they have special consideration.
   * 
   * 


   * Default: If {@link #setThreadLocal} was called with non-null, the value is
   * returned. Otherwise, TimeZone.getDefault() is returned,
   */
  public static final TimeZone getCurrent() {
    final TimeZone l = (TimeZone) _thdTZone.get();
    return l != null ? l : TimeZone.getDefault();
  }
  /**
   * Sets the time-zone for the current thread only.
   * 
   * 


   * Each thread could have an independent time zone, called the thread time
   * zone.
   * 
   * 


   * When Invoking this method under a thread that serves requests, remember to
   * clean up the setting upon completing each request.
   * 
   * 


   * TimeZone old = TimeZones.setThreadLocal(newValue);
   * try { 
   *   ...
   * } finally {
   *   TimeZones.setThreadLocal(old);
   * }
   * 

   * 
   * @param timezone
   *          the thread time zone; null to denote no thread time zone (and the
   *          system's timezone will be used instead)
   * @return the previous thread time zone, or null if no previous time zone
   */
  public static final TimeZone setThreadLocal(TimeZone timezone) {
    final TimeZone old = (TimeZone) _thdTZone.get();
    _thdTZone.set(timezone);
    return old;
  }
  /**
   * Returns the time zone defined by {@link #setThreadLocal}.
   * 
   * @since 3.0.0
   * @see #getCurrent
   */
  public static final TimeZone getThreadLocal() {
    return (TimeZone) _thdTZone.get();
  }
  /**
   * Returns the time by specifying the offset in minutes.
   * 
   * 


   * For example, the following are equivalent.
   * 
   * 


   * TimeZone.getTimeZone("GMT+8");
   * TimeZones.getTimeZone(480);
   * 

   * 
   * @param ofsmins
   *          the offset in minutes.
   */
  public static final TimeZone getTimeZone(int ofsmins) {
    final StringBuffer sb = new StringBuffer(8).append("GMT");
    if (ofsmins >= 0) {
      sb.append('+');
    } else {
      sb.append('-');
      ofsmins = -ofsmins;
    }
    final int hr = ofsmins / 60, min = ofsmins % 60;
    if (min == 0) {
      sb.append(hr);
    } else {
      if (hr < 10)
        sb.append('0');
      sb.append(hr).append(':');
      if (min < 10)
        sb.append('0');
      sb.append(min);
    }
    return TimeZone.getTimeZone(sb.toString());
  }
}