Encapsulates a truck-load of commonly used date functions : Date « Data Type « Java






Encapsulates a truck-load of commonly used date functions

  
/*
 * Copyright (C) 2007 The Android Open Source Project
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */


import java.util.Calendar;

/**
 * Encapsulates a truck-load of commonly used date functions.
 * 
 * @author barclay
 */
public final class DateUtil {
  private Calendar mCal;
  private DateUtil.Period mSpan;
  private int mSpanOffset = 0;
  private boolean mUnitChange = false;

  /** Number of milliseconds in a second */
  public static final long SECOND_MS = 1000;
  /** Number of milliseconds in a minute */
  public static final long MINUTE_MS = SECOND_MS * 60;
  /** Number of milliseconds in an hour */
  public static final long HOUR_MS = MINUTE_MS * 60;
  /** Number of milliseconds in a morning or evening (1/2 day) */
  public static final long AMPM_MS = HOUR_MS * 12;
  /** Number of milliseconds in a day */
  public static final long DAY_MS = HOUR_MS * 24;
  /** Number of milliseconds in a week */
  public static final long WEEK_MS = DAY_MS * 7;
  /** Number of milliseconds in a year */
  public static final long YEAR_MS = WEEK_MS * 52;
  /** Number of milliseconds in a quarter (as defined by 1/4 of a year) */
  public static final long QUARTER_MS = WEEK_MS * 13;
  /** Number of milliseconds in a month (as defined by 1/12 of a year) */
  public static final long MONTH_MS = YEAR_MS / 12;

  /**
   * Encapsulation of a date broken down by both milliseconds since epoch (as
   * defined by the system), and year, month, day, hour, minute, and second. The
   * reason for storing both is essentially to cache information and glue the
   * variable together into a single item. Purely convenience.
   * 
   * @author barclay
   */
  public static class DateItem {
    public int mYear = 0;
    public int mMonth = 0;
    public int mDay = 0;
    public int mHour = 0;
    public int mMinute = 0;
    public int mSecond = 0;
    public long mMillis = 0;

    /**
     * Set all the fields of the DateItem to the date/time represented by the
     * current value of the Calendar passed in.
     * 
     * @param c
     *          The Calendar that's the source data.
     */
    public void setTo(Calendar c) {
      mYear = c.get(Calendar.YEAR);
      mMonth = c.get(Calendar.MONTH);
      mDay = c.get(Calendar.DAY_OF_MONTH);
      mHour = c.get(Calendar.HOUR_OF_DAY);
      mMinute = c.get(Calendar.MINUTE);
      mSecond = c.get(Calendar.SECOND);
      mMillis = c.getTimeInMillis();
    }

    /**
     * Compares all the fields of the DateItem to another DateItem. All fields
     * are compared, instead of just the millisecond field, in the event that
     * all the fields are not in sync for some reason.
     * 
     * @param other
     * @return true if the two DateItems are equal in all fields, else false.
     */
    public boolean isEqual(DateItem other) {
      if (this.mYear == other.mYear && this.mMonth == other.mMonth
          && this.mDay == other.mDay && this.mHour == other.mHour
          && this.mMinute == other.mMinute && this.mSecond == other.mSecond
          && this.mMillis == other.mMillis)
        return true;
      return false;
    }
  }

  private DateItem mBase;
  private DateItem mCursor;

  /**
   * Code shoulder reference these Periods when refering to spans of time
   * instead of Calendar.*, as Calendar doesn't support the notion of a strict
   * QUARTER, and we use WEEK slightly differently.
   * 
   * @author barclay
   */
  public enum Period {
    MINUTE, HOUR, AMPM, DAY, WEEK, MONTH, QUARTER, YEAR
  }

  public Period[] PERIODS = { Period.MINUTE, Period.HOUR, Period.AMPM,
      Period.DAY, Period.WEEK, Period.MONTH, Period.QUARTER, Period.YEAR };

  public static final String[] MONTHS = { "Jan", "Feb", "Mar", "Apr", "May",
      "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };

  public static final String[] DAYS = { "Sun", "M", "Tu", "W", "Th", "F",
      "Sat", };

  public static final String[] QUARTERS = { "Q1", "Q2", "Q3", "Q4", };

  /**
   * Constructor. Instantiates a Calendar member variable to prevent having to
   * continually fetch an instance, which is moderately expensive, and create
   * cursor used to walk a timeline.
   */
  public DateUtil() {
    mCal = Calendar.getInstance();
    mBase = new DateItem();
    mCursor = new DateItem();
  }

  /**
   * Returns the internal Calendar object in it's current state.
   * 
   * @return The Calendar.
   */
  public Calendar getCalendar() {
    return mCal;
  }

  /**
   * Used when going to stride along a timeline. This sets the start time of the
   * walk.
   * 
   * @param ms
   *          The start time in milliseconds since epoch.
   */
  public void setBaseTime(long ms) {
    mBase.mMillis = ms;
    millisToComponent(mBase);
    copyDate(mBase, mCursor);
  }

  /**
   * Returns the milliseconds until the next Period, as based on the difference
   * between the current cursor and the Period. If the current cursor is at the
   * start of a Period, ignoring milliseconds, 0 is returned.
   * 
   * @param u
   * @return milliseconds until next period.
   */
  public long msToNextPeriod(Period u) {
    long ms = 0;

    switch (u) {
      case YEAR:
        mCal.set(mCursor.mYear + 1, 0, 0, 0, 0, 0);
        ms = mCal.getTimeInMillis() - mCursor.mMillis;
        if (ms == YEAR_MS)
          ms = 0;
        break;
      case QUARTER:
        if (mCursor.mMonth >= 9)
          mCal.set(mCursor.mYear + 1, 0, 0, 0, 0, 0);
        else if (mCursor.mMonth >= 6)
          mCal.set(mCursor.mYear, 9, 0, 0, 0, 0);
        else if (mCursor.mMonth >= 3)
          mCal.set(mCursor.mYear, 6, 0, 0, 0, 0);
        else
          mCal.set(mCursor.mYear, 3, 0, 0, 0, 0);
        ms = mCal.getTimeInMillis() - mCursor.mMillis;
        if (ms == QUARTER_MS)
          ms = 0;
        break;
      case MONTH:
        if (mCursor.mMonth == 11)
          mCal.set(mCursor.mYear + 1, 0, 0, 0, 0, 0);
        else
          mCal.set(mCursor.mYear, mCursor.mMonth + 1, 0, 0, 0, 0);
        ms = mCal.getTimeInMillis() - mCursor.mMillis;
        if (ms == MONTH_MS)
          ms = 0;
        break;
      case WEEK:
        mCal.setTimeInMillis(mCursor.mMillis);

        int first = mCal.getFirstDayOfWeek();

        mCal.add(Calendar.WEEK_OF_YEAR, 1);
        mCal.set(Calendar.DAY_OF_WEEK, first);
        mCal.set(Calendar.HOUR_OF_DAY, 0);
        mCal.set(Calendar.MINUTE, 0);
        mCal.set(Calendar.SECOND, 0);
        mCal.set(Calendar.MILLISECOND, 0);
        ms = mCal.getTimeInMillis() - mCursor.mMillis;
        if (ms == WEEK_MS)
          ms = 0;
        break;
      case DAY:
        if (mCursor.mMinute == 0 && mCursor.mHour == 0)
          return 0;
        ms = ((60 - mCursor.mMinute) + (60 * (24 - mCursor.mHour))) * MINUTE_MS;
        break;
      case AMPM:
        if (mCursor.mMinute == 0 && (mCursor.mHour == 0 || mCursor.mHour == 12))
          return 0;
        ms = ((60 - mCursor.mMinute) + (60 * (24 - (mCursor.mHour % 12))))
            * MINUTE_MS;
        break;
      case HOUR:
        if (mCursor.mMinute == 0)
          return 0;
        ms = (60 - mCursor.mMinute) * MINUTE_MS;
        break;
      case MINUTE:
      default:
        if (mCursor.mSecond == 0)
          return 0;
        ms = (60 - mCursor.mSecond) * SECOND_MS;
        break;
    }

    return ms;
  }

  /**
   * Sets an offset of the internal marker recording the class of time spanned
   * (as a Period). This offset is indexes into the Period enum, e.g., if the
   * span is calculated to be Period.YEAR with an offset of 0, then it will be
   * calculated to be Period.MONTH with an offset of -2.
   * 
   * @param milliStart
   *          The milliseconds since epoch in start time, inclusive.
   * @param milliEnd
   *          The milliseconds since epoch in end time, inclusive.
   */
  public void setSpanOffset(int offset) {
    mSpanOffset = offset;
  }

  /**
   * Sets the internal marker recording the class of time spanned (as a Period)
   * for the range of time specified. This is used to determine how to generate
   * labels while striding through time. If milliStart == milliEnd, the span
   * will be set to the smallest known span.
   * 
   * @param milliStart
   *          The milliseconds since epoch in start time, inclusive.
   * @param milliEnd
   *          The milliseconds since epoch in end time, inclusive.
   */
  public void setSpan(long milliStart, long milliEnd) {
    int index = 0;
    long range = milliEnd - milliStart;
    if (range == 0)
      range = 1;
    if (range < 0)
      range = -range;

    if (range > (long) (DateUtil.YEAR_MS * 3)) {
      index = DateUtil.Period.YEAR.ordinal();
    } else if (range > (long) (DateUtil.QUARTER_MS * 6)) {
      index = DateUtil.Period.QUARTER.ordinal();
    } else if (range > (long) (DateUtil.MONTH_MS * 6)) {
      index = DateUtil.Period.MONTH.ordinal();
    } else if (range > (long) (DateUtil.WEEK_MS * 4)) {
      index = DateUtil.Period.WEEK.ordinal();
    } else if (range > (long) (DateUtil.DAY_MS * 5)) {
      index = DateUtil.Period.DAY.ordinal();
    } else if (range > (long) (DateUtil.HOUR_MS * 24)) {
      index = DateUtil.Period.AMPM.ordinal();
    } else if (range > (long) (DateUtil.HOUR_MS * 5)) {
      index = DateUtil.Period.HOUR.ordinal();
    } else {
      index = DateUtil.Period.MINUTE.ordinal();
    }

    index += mSpanOffset;
    if (index < 0)
      index = 0;
    else if (index >= PERIODS.length)
      index = PERIODS.length - 1;

    mSpan = PERIODS[index];
    return;
  }

  /**
   * Returns the span calculated by {@link #setSpan(long, long)}
   * 
   * @return The span as a DateUtil.Period
   * @see DateUtil#Period
   */
  public DateUtil.Period getSpan() {
    return mSpan;
  }

  /**
   * Returns the selected Calendar.* field of the time under the current cursor
   * when striding.
   * 
   * @param p
   *          The Period in which to format the output.
   * @return The field datum.
   */
  public int get(int field) {
    return mCal.get(field);
  }

  /**
   * Returns an array of two strings yielding a textual representation of the
   * time under the current cursor when striding. Neither string will be null,
   * but either may be the empty ("") string. Typically, the second string will
   * be empty rather than the first, and will contain additional information
   * about the label, such as the the month when the days roll over into the
   * next month, or the day of the week. This method sets an internal marker
   * recording if current label has rolled past a period boundary, such as from
   * one week to the next or one year to the next, which is queryable via
   * {@link #isUnitChanged()}
   * 
   * @param p
   *          The Period in which to format the output.
   * @return String[2], containing two description strings of the date/time. The
   *         first string will be withing the Period <code>p</code>, and the
   *         second is typically auxiliary information.
   */
  public String[] getLabel(Period p) {
    String[] strings = new String[2];
    int minute;
    int hour;
    int day;
    int month;
    int year;
    int dow;

    mUnitChange = false;

    switch (p) {
      case YEAR:
        strings[0] = "" + mCal.get(Calendar.YEAR);
        strings[1] = "";
        break;
      case QUARTER:
        year = mCal.get(Calendar.YEAR);
        month = mCal.get(Calendar.MONTH);
        if (month >= 9)
          strings[0] = QUARTERS[3];
        else if (month >= 6)
          strings[0] = QUARTERS[2];
        else if (month >= 3)
          strings[0] = QUARTERS[1];
        else
          strings[0] = QUARTERS[0];
        strings[1] = "";
        if (year != mBase.mYear) {
          strings[1] = "" + mCal.get(Calendar.YEAR);
          mUnitChange = true;
        }
        break;
      case MONTH:
        year = mCal.get(Calendar.YEAR);
        month = mCal.get(Calendar.MONTH);
        strings[0] = MONTHS[month];
        if (year != mBase.mYear) {
          strings[1] = "" + mCal.get(Calendar.YEAR);
          mUnitChange = true;
        } else {
          strings[1] = "";
        }
        break;
      case WEEK:
      case DAY:
        month = mCal.get(Calendar.MONTH);
        day = mCal.get(Calendar.DAY_OF_MONTH);
        strings[0] = "" + day;
        if (month != mBase.mMonth) {
          strings[1] = MONTHS[month];
          mUnitChange = true;
        } else {
          dow = mCal.get(Calendar.DAY_OF_WEEK);
          strings[1] = DAYS[dow - 1];
          if (dow == 1)
            mUnitChange = true;
        }
        break;
      case AMPM:
      case HOUR:
        day = mCal.get(Calendar.DAY_OF_MONTH);
        hour = mCal.get(Calendar.HOUR_OF_DAY);
        if (hour == 0) {
          strings[0] = "12a";
          strings[1] = "midnight";
        } else if (hour == 12) {
          strings[0] = "12p";
          strings[1] = "noon";
        } else if (hour > 11) {
          strings[0] = (hour - 12) + "p";
          strings[1] = "";
        } else {
          strings[0] = hour + "a";
          strings[1] = "";
        }

        if (day != mBase.mDay) {
          dow = mCal.get(Calendar.DAY_OF_WEEK);
          strings[0] = mCal.get(Calendar.MONTH) + 1 + "/" + day;
          strings[1] = DAYS[dow - 1];
          mUnitChange = true;
        }
        break;
      case MINUTE:
      default:
        minute = mCal.get(Calendar.MINUTE);
        hour = mCal.get(Calendar.HOUR_OF_DAY);
        strings[0] = l2pad(minute);
        strings[1] = "";
        if (hour != mBase.mHour) {
          if (hour == 0) {
            day = mCal.get(Calendar.DAY_OF_MONTH);
            dow = mCal.get(Calendar.DAY_OF_WEEK);
            strings[0] = mCal.get(Calendar.MONTH) + 1 + "/" + day;
            strings[1] = DAYS[dow - 1];
          } else if (hour == 12) {
            strings[0] = "12";
            strings[1] = "noon";
          } else if (hour > 11) {
            strings[0] = (hour - 12) + "p";
          } else {
            strings[0] = hour + "a";
          }
          mUnitChange = true;
        } else
          break;
    }

    return strings;
  }

  /**
   * Advances the internal cursor <code>milliseconds</code> in time.
   * 
   * @param milliseconds
   *          The number of milliseconds to advance.
   */
  public void advanceInMs(long milliseconds) {
    copyDate(mCursor, mBase);
    mCal.setTimeInMillis(mCursor.mMillis);
    mCal.add(Calendar.MILLISECOND, (int) milliseconds);
    mCursor.mMillis = mCal.getTimeInMillis();
  }

  /**
   * Advances the internal cursor <code>step</code> units of Period
   * <code>p</code> in time. Note that for MONTH and QUARTER, this works out to
   * 1 and 3 months respectively, as defined by the Calendar class and based on
   * the current cursor, not precisely MONTH_MS or QUARTER_MS milliseconds.
   * 
   * @param p
   *          The DateUtil.Period unit.
   * @param step
   *          The number of Period units to advance.
   */
  public void advance(Period p, int step) {
    copyDate(mCursor, mBase);

    switch (p) {
      case YEAR:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.YEAR, step);
        break;
      case QUARTER:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.MONTH, step * 3);
        break;
      case MONTH:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.MONTH, step);
        break;
      case WEEK:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.WEEK_OF_YEAR, step);
        break;
      case DAY:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.DAY_OF_MONTH, step);
        break;
      case HOUR:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.HOUR_OF_DAY, step);
        break;
      case MINUTE:
      default:
        mCal.setTimeInMillis(mCursor.mMillis);
        mCal.add(Calendar.MINUTE, step);
        break;
    }

    mCursor.mMillis = mCal.getTimeInMillis();
    millisToComponent(mCursor);

    return;
  }

  /**
   * Return whether or not the last getLabel() noted a rollover from one period
   * to another, as determine by the Period passed to getLabel().
   * 
   * @return boolean
   * @see #getLabel(Period)
   */
  public boolean isUnitChanged() {
    return mUnitChange;
  }

  /**
   * Returns the average number of milliseconds in a Period. These are constant.
   * 
   * @param u
   * @return the number of millseconds
   * @see #YEAR_MS
   * @see #QUARTER_MS
   * @see #MONTH_MS
   * @see #DAY_MS
   * @see #HOUR_MS
   * @see #MINUTE_MS
   */
  public long msInPeriod(Period u) {
    long ms = 0;
    switch (u) {
      case YEAR:
        ms = YEAR_MS;
        break;
      case QUARTER:
        ms = QUARTER_MS;
        break;
      case MONTH:
        ms = MONTH_MS;
        break;
      case WEEK:
        ms = WEEK_MS;
        break;
      case DAY:
        ms = DAY_MS;
        break;
      case AMPM:
        ms = AMPM_MS;
        break;
      case HOUR:
        ms = HOUR_MS;
        break;
      case MINUTE:
      default:
        ms = MINUTE_MS;
        break;
    }

    return ms;
  }

  /**
   * Some external entities still use Calendar.* fields to do some of their own
   * date calculations, so this provides a mapping from DateUtil.*_MS to the
   * closest Calendar.* field. Note that if the milliseconds is not one of the
   * DateUtil constants, the smallest known field will be returned.
   * 
   * @param millis
   *          The DateUtil.*_MS field to map from.
   * @return The int representing the closest Calendar.* field.
   */
  public static int mapLongToCal(long millis) {
    if (millis == YEAR_MS)
      return Calendar.YEAR;
    else if (millis == QUARTER_MS)
      return Calendar.MONTH; // There is no Calendar.QUARTER, return MONTH
    else if (millis == MONTH_MS)
      return Calendar.MONTH;
    else if (millis == WEEK_MS)
      return Calendar.WEEK_OF_YEAR;
    else if (millis == DAY_MS)
      return Calendar.DAY_OF_MONTH;
    else if (millis == AMPM_MS)
      return Calendar.AM_PM;
    else if (millis == HOUR_MS)
      return Calendar.HOUR_OF_DAY;
    return Calendar.MINUTE;
  }

  /**
   * Provide a mapping from number of millisecond (DateUtil.*_MS) to a
   * DateUtil.Period. Note that if the milliseconds is not one of the DateUtil
   * constants, the smallest known field will be returned.
   * 
   * @param millis
   *          The DateUtil.*_MS field to map from.
   * @return The Period enum representing the associated DateUtil.Period.
   */
  public static Period mapLongToPeriod(long millis) {
    if (millis == YEAR_MS)
      return Period.YEAR;
    else if (millis == QUARTER_MS)
      return Period.QUARTER;
    else if (millis == MONTH_MS)
      return Period.MONTH;
    else if (millis == WEEK_MS)
      return Period.WEEK;
    else if (millis == DAY_MS)
      return Period.DAY;
    else if (millis == AMPM_MS)
      return Period.AMPM;
    else if (millis == HOUR_MS)
      return Period.HOUR;
    return Period.MINUTE;
  }

  /**
   * Provide a mapping from a Period to the number of millisecond
   * (DateUtil.*_MS)
   * 
   * @param The
   *          Period enum representing the associated DateUtil.Period.
   * @return A String describing the period..
   */
  public static String mapPeriodToString(Period p) {
    if (p == Period.YEAR)
      return "year";
    if (p == Period.QUARTER)
      return "quarter";
    if (p == Period.MONTH)
      return "month";
    if (p == Period.WEEK)
      return "week";
    if (p == Period.DAY)
      return "day";
    if (p == Period.AMPM)
      return "am/pm";
    if (p == Period.HOUR)
      return "hour";
    return "minute";
  }

  /**
   * Provide a mapping from string to a Period.
   * 
   * @param s
   *          The string to map from. Case insensitive.
   * @return The associated DateUtil.Period
   */
  public static Period mapStringToPeriod(String s) {
    if (s.toLowerCase().equals("year"))
      return Period.YEAR;
    if (s.toLowerCase().equals("quarter"))
      return Period.QUARTER;
    if (s.toLowerCase().equals("month"))
      return Period.MONTH;
    if (s.toLowerCase().equals("week"))
      return Period.WEEK;
    if (s.toLowerCase().equals("day"))
      return Period.DAY;
    if (s.toLowerCase().equals("am/pm"))
      return Period.AMPM;
    if (s.toLowerCase().equals("hour"))
      return Period.HOUR;
    return Period.MINUTE;
  }

  /**
   * Provide a mapping from a Period to the number of millisecond
   * (DateUtil.*_MS)
   * 
   * @param millis
   *          The DateUtil.*_MS field to map from.
   * @param The
   *          Period enum representing the associated DateUtil.Period.
   * @return the DateUtil.*_MS constant representing the number of milliseconds
   *         in the period.
   */
  public static long mapPeriodToLong(Period p) {
    if (p == Period.YEAR)
      return YEAR_MS;
    if (p == Period.QUARTER)
      return QUARTER_MS;
    if (p == Period.MONTH)
      return MONTH_MS;
    if (p == Period.WEEK)
      return WEEK_MS;
    if (p == Period.DAY)
      return DAY_MS;
    if (p == Period.AMPM)
      return AMPM_MS;
    if (p == Period.HOUR)
      return HOUR_MS;
    return MINUTE_MS;
  }

  /**
   * Returns a description of the milliseconds, scaled to the largest unit and
   * rounded to the default number of decimal places, with the associated label
   * (e.g., "years", "weeks", etc.)
   * 
   * @param millis
   *          The milliseconds since epoch to format.
   * @return The descriptive string.
   */
  public static String toString(float millis) {
    if (millis > YEAR_MS) {
      return Round(millis / YEAR_MS) + " years";
    } else if (millis > QUARTER_MS) {
      return Round(millis / QUARTER_MS) + " quarters";
    } else if (millis > MONTH_MS) {
      return Round(millis / MONTH_MS) + " months";
    } else if (millis > WEEK_MS) {
      return Round(millis / WEEK_MS) + " weeks";
    } else if (millis > DAY_MS) {
      return Round(millis / DAY_MS) + " days";
    } else if (millis > HOUR_MS) {
      return Round(millis / HOUR_MS) + " hours";
    } else { // if (millis > MINUTE_MS) {
      return Round(millis / MINUTE_MS) + " minutes";
    }
  }

  /**
   * Returns a description of the square root of the milliseconds, scaled to the
   * largest unit and rounded to the default number of decimal places, with the
   * associated label (e.g., "years", "weeks", etc.). Note this is only used for
   * displaying the variance, as the variance the a squared value, so this tests
   * (millis > (unit^2)) ? and displays the value (millis/(unit^2)). Otherwise
   * it is identical to {@link #toString(float)}.
   * 
   * @param millis
   *          The (squared) milliseconds since epoch to format.
   * @return The descriptive string.
   */
  public static String toStringSquared(float millis) {
    if (millis > (float) YEAR_MS * (float) YEAR_MS) {
      return Round(millis / ((float) YEAR_MS * (float) YEAR_MS))
          + " years";
    } else if (millis > (float) QUARTER_MS * (float) QUARTER_MS) {
      return Round(millis / ((float) QUARTER_MS * (float) QUARTER_MS))
          + " quarters";
    } else if (millis > (float) MONTH_MS * (float) MONTH_MS) {
      return Round(millis / ((float) MONTH_MS * (float) MONTH_MS))
          + " months";
    } else if (millis > (float) WEEK_MS * (float) WEEK_MS) {
      return Round(millis / ((float) WEEK_MS * (float) WEEK_MS))
          + " weeks";
    } else if (millis > (float) DAY_MS * (float) DAY_MS) {
      return Round(millis / ((float) DAY_MS * (float) DAY_MS)) + " days";
    } else if (millis > (float) HOUR_MS * (float) HOUR_MS) {
      return Round(millis / ((float) HOUR_MS * (float) HOUR_MS))
          + " hours";
    } else { // if (millis > MINUTE_MS) {
      return Round(millis / ((float) MINUTE_MS * (float) MINUTE_MS))
          + " minutes";
    }
  }
  /**
   * Default number of decimal places to round to:
   */
  public static final int DECIMAL_PLACES = 2;

  /**
   * Round a float to the default number of decimal places.
   * 
   * @param value
   *          The value to round.
   * @return The rounded value as a float.
   * @see #DECIMAL_PLACES
   */
  public static float Round(float value) {
    return Round(value, DECIMAL_PLACES);
  }

  /**
   * Round a float to the specified number of decimal places.
   * 
   * @param value
   *          The value to round.
   * @param places
   *          The number of decimal points.
   * @return The rounded value as a float.
   */
  public static float Round(float value, int places) {
    float p = (float) Math.pow(10, places);
    value = value * p;
    float tmp = Math.round(value);
    return (float) tmp / p;
  }
  /**
   * Returns the "timestamp" string representation of the time in milliseconds:
   * yyyy/mm/dd HH:MM:SS
   * 
   * @param millis
   *          The milliseconds since epoch to format.
   * @return The timestamp string.
   */
  public static String toTimestamp(long millis) {
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(millis);
    return DateUtil.toTimestamp(c);
  }

  /**
   * Returns the "short timestamp" string representation of the time in
   * milliseconds: HH:MM:SS
   * 
   * @param millis
   *          The milliseconds since epoch to format.
   * @return The short timestamp string.
   */
  public static String toShortTimestamp(long millis) {
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(millis);
    return DateUtil.toShortTimestamp(c);
  }

  /**
   * Utility routine for padding zeros on the left side of an integer out to two
   * digits, since string concatenations this small are much more efficient that
   * using String.format("%02d",foo).
   * 
   * @param i
   *          The integer to format.
   * @return A zero-padded string representation of the integer.
   */
  private static String l2pad(int i) {
    if (i < 10)
      return "0" + i;
    return "" + i;
  }

  /**
   * Returns a "timestamp" formated string representing the time:
   * "yyyy/mm/dd HH:MM:SS"
   * 
   * @param d
   *          The DateItem to format.
   * @return The timestamp string.
   */
  public static String toTimestamp(DateItem d) {
    return d.mYear + "/" + l2pad(d.mMonth + 1) + "/" + l2pad(d.mDay) + " "
        + l2pad(d.mHour) + ":" + l2pad(d.mMinute) + ":" + l2pad(d.mSecond);
  }

  /**
   * Returns a "timestamp" formated string representing the time:
   * "yyyy/mm/dd HH:MM:SS"
   * 
   * @param d
   *          The Calendar to format.
   * @return The timestamp string.
   */
  public static String toTimestamp(Calendar cal) {
    return cal.get(Calendar.YEAR) + "/" + l2pad(cal.get(Calendar.MONTH) + 1)
        + "/" + l2pad(cal.get(Calendar.DAY_OF_MONTH)) + " "
        + l2pad(cal.get(Calendar.HOUR_OF_DAY)) + ":"
        + l2pad(cal.get(Calendar.MINUTE)) + ":"
        + l2pad(cal.get(Calendar.SECOND));
  }

  /**
   * Returns a "short timestamp" formated string representing the time:
   * "HH:MM:SS"
   * 
   * @param d
   *          The Calendar to format.
   * @return The timestamp string.
   */
  public static String toShortTimestamp(Calendar cal) {
    return l2pad(cal.get(Calendar.HOUR_OF_DAY)) + ":"
        + l2pad(cal.get(Calendar.MINUTE)) + ":"
        + l2pad(cal.get(Calendar.SECOND));
  }

  /**
   * Returns a (generally) filesystem-safe formated string representing the
   * time: "yyyy-mm-dd_HH.MM.SS"
   * 
   * @param d
   *          The Calendar to format.
   * @return The timestamp string.
   */
  public static String toFSTimestamp(Calendar cal) {
    return cal.get(Calendar.YEAR) + "-" + l2pad(cal.get(Calendar.MONTH) + 1)
        + "-" + l2pad(cal.get(Calendar.DAY_OF_MONTH)) + "_"
        + l2pad(cal.get(Calendar.HOUR_OF_DAY)) + "."
        + l2pad(cal.get(Calendar.MINUTE)) + "."
        + l2pad(cal.get(Calendar.SECOND));
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * year, else false.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameYear(Calendar c1, Calendar c2) {
    if (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR))
      return true;
    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * quarter, else false. A quarter here is defined as the each group of three
   * consecutive months, starting with the month designated as the first month
   * by the Calendar package. Thus, it is not defined as the average number of
   * milliseconds in a quarter, which would be {@link #YEAR_MS}/4.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameQuarter(Calendar c1, Calendar c2) {
    if (inSameYear(c1, c2)) {
      int m1 = c1.get(Calendar.MONTH);
      int m2 = c2.get(Calendar.MONTH);
      if (m1 >= 9 && m2 >= 9)
        return true;
      if (m1 >= 6 && m1 < 9 && m2 >= 6 && m2 < 9)
        return true;
      if (m1 >= 3 && m1 < 6 && m2 >= 3 && m2 < 6)
        return true;
      if (m1 >= 0 && m1 < 3 && m2 >= 0 && m2 < 3)
        return true;
    }
    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * month, else false.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameMonth(Calendar c1, Calendar c2) {
    if (inSameYear(c1, c2)
        && (c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH)))
      return true;
    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * week, else false. A week here is defined by the Calendar.WEEK_OF_YEAR
   * package. Special provisions have been made to test weeks than may span the
   * end/beginning of a year, and returning true if the two calendars are
   * specifying dates within such a week, despite Calendar.WEEK_OF_YEAR being
   * unequal for the two Calendars.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameWeek(Calendar c1, Calendar c2) {
    if (inSameYear(c1, c2)
        && (c1.get(Calendar.WEEK_OF_YEAR) == c2.get(Calendar.WEEK_OF_YEAR)))
      return true;

    Calendar tmp;
    if (c1.before(c2)) {
      tmp = c2;
      c2 = c1;
      c1 = tmp;
    }

    int c1week = c1.get(Calendar.WEEK_OF_YEAR);
    int c2week = c1.get(Calendar.WEEK_OF_YEAR);

    if (c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR) + 1) {
      if (c1week == c1.getActualMinimum(Calendar.WEEK_OF_YEAR)
          && c2week == c2.getActualMaximum(Calendar.WEEK_OF_YEAR)) {
        tmp = (Calendar) c2.clone();
        tmp.add(Calendar.DAY_OF_YEAR, 7);
        if (tmp.get(Calendar.WEEK_OF_YEAR) > c1week)
          return true;
      }
    }

    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * day, else false.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameDay(Calendar c1, Calendar c2) {
    if (inSameYear(c1, c2)
        && (c1.get(Calendar.DAY_OF_YEAR) == c2.get(Calendar.DAY_OF_YEAR)))
      return true;
    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * morning or evening, as defined by [midnight,noon) and [noon,midnight), else
   * false.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameAMPM(Calendar c1, Calendar c2) {
    if (inSameDay(c1, c2) && (c1.get(Calendar.AM_PM) == c2.get(Calendar.AM_PM)))
      return true;
    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * hour, else false.
   * 
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSameHour(Calendar c1, Calendar c2) {
    if (inSameDay(c1, c2)
        && (c1.get(Calendar.HOUR_OF_DAY) == c2.get(Calendar.HOUR_OF_DAY)))
      return true;
    return false;
  }

  /**
   * Returns true if the two calendars represent dates that fall in the same
   * period, else false.
   * 
   * @param aggregationMillis
   *          The period as specified in milliseconds, e.g., DateUtil.YEAR_MS
   * @param c1
   *          Calendar one.
   * @param c2
   *          Calendar two.
   * @return boolean.
   */
  public static boolean inSamePeriod(Calendar c1, Calendar c2,
      long aggregationMillis) {
    if (aggregationMillis == 0)
      return false;

    if ((aggregationMillis == YEAR_MS && inSameYear(c1, c2))
        || (aggregationMillis == QUARTER_MS && inSameQuarter(c1, c2))
        || (aggregationMillis == MONTH_MS && inSameMonth(c1, c2))
        || (aggregationMillis == WEEK_MS && inSameWeek(c1, c2))
        || (aggregationMillis == DAY_MS && inSameDay(c1, c2))
        || (aggregationMillis == AMPM_MS && inSameAMPM(c1, c2))
        || (aggregationMillis == HOUR_MS && inSameHour(c1, c2))) {
      return true;
    }

    return false;
  }

  /**
   * Sets the date/time of the Calendar object to the beginning of the Period by
   * setting all fields smaller than the specified period to the minimum value.
   * 
   * @param c
   *          The calendar to set.
   * @param p
   *          The DateUtil.Period to set.
   */
  public static void setToPeriodStart(Calendar c, Period p) {
    switch (p) {
      case YEAR:
        c.set(Calendar.MONTH, 0);
      case MONTH:
        c.set(Calendar.DAY_OF_MONTH, 1);
      case DAY:
        c.set(Calendar.HOUR_OF_DAY, 0);
      case HOUR:
        c.set(Calendar.MINUTE, 0);
      case MINUTE:
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        break;
      case WEEK:
        c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek());
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        break;
      case AMPM:
        if (c.get(Calendar.AM_PM) == Calendar.AM)
          c.set(Calendar.HOUR_OF_DAY, 0);
        else
          c.set(Calendar.HOUR_OF_DAY, 12);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        break;
      case QUARTER:
        int month = c.get(Calendar.MONTH);
        if (month >= 9)
          c.set(Calendar.MONTH, 9);
        else if (month >= 9)
          c.set(Calendar.MONTH, 6);
        else if (month >= 9)
          c.set(Calendar.MONTH, 3);
        else
          c.set(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 0);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        break;
    }
    return;
  }

  /**
   * Utility routine to set each DateTime component field to that specified by
   * the DateItem's millisecond field.
   * 
   * @param d
   *          The DateItem to modify.
   */
  private void millisToComponent(DateItem d) {
    mCal.setTimeInMillis(d.mMillis);
    d.mYear = mCal.get(Calendar.YEAR);
    d.mMonth = mCal.get(Calendar.MONTH);
    d.mDay = mCal.get(Calendar.DAY_OF_MONTH);
    d.mHour = mCal.get(Calendar.HOUR_OF_DAY);
    d.mMinute = mCal.get(Calendar.MINUTE);
  }

  /**
   * Copy all member variable of one DateItem to that of another DateItem.
   * 
   * @param src
   *          The DateItem to copy from.
   * @param dst
   *          The DateItem to copy to.
   */
  private void copyDate(DateItem src, DateItem dst) {
    dst.mYear = src.mYear;
    dst.mMonth = src.mMonth;
    dst.mDay = src.mDay;
    dst.mHour = src.mHour;
    dst.mMinute = src.mMinute;
    dst.mMillis = src.mMillis;
  }
}

   
    
  








Related examples in the same category

1.Create instance of java.sql.Date from Calendar.getTimeInMillis()
2.Creating a Date Object for a Particular Date
3.Create java Date from specific time example
4.Convert string of time to time object
5.Convert String to Date object
6.Convert a String to Date
7.Check if a String is a valid date
8.Compare two Java Date objects using after method example
9.Compare two Java Date objects using before method example
10.Compare two Java Date objects using compareTo method example
11.Sets the day of month field to a date returning a new object.
12.Sets the hours field to a date returning a new object. Hours range from 0-23.
13.Sets the miliseconds field to a date returning a new object.
14.Sets the minute field to a date returning a new object.
15.Sets the seconds field to a date returning a new object.
16.Sets the years field to a date returning a new object.
17.Truncate this date(Calendar), leaving the field specified as the most significant field.
18.Truncate this date, leaving the field specified as the most significant field.
19.Convert date string from one format to another format using SimpleDateFormat
20.Convert Date into milliseconds example
21.A formatter that formats dates to show the elapsed time relative to some base date.
22.Return now as a string
23.Return today as a string
24.Date Utils
25.Collection of useful utilities to work with dates
26.Date utility class