Java/Data Type/Date

Материал из Java эксперт
Версия от 18:01, 31 мая 2010; (обсуждение)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

A formatter that formats dates to show the elapsed time relative to some base date.

   
/* 
 * JFreeChart : a free chart library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jfreechart/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -----------------------
 * RelativeDateFormat.java
 * -----------------------
 * (C) Copyright 2006-2008, by Object Refinery Limited and Contributors.
 *
 * Original Author:  David Gilbert (for Object Refinery Limited);
 * Contributor(s):   Michael Siemer;
 *
 * Changes:
 * --------
 * 01-Nov-2006 : Version 1 (DG);
 * 23-Nov-2006 : Added argument checks, updated equals(), added clone() and
 *               hashCode() (DG);
 * 15-Feb-2008 : Applied patch 1873328 by Michael Siemer, with minor
 *               modifications (DG);
 * 01-Sep-2008 : Added new fields for hour and minute formatting, based on
 *               patch 2033092 (DG);
 *
 */

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.FieldPosition;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
 * A formatter that formats dates to show the elapsed time relative to some
 * base date.
 *
 * @since 1.0.3
 */
public class RelativeDateFormat extends DateFormat {
    /** The base milliseconds for the elapsed time calculation. */
    private long baseMillis;
    /**
     * A flag that controls whether or not a zero day count is displayed.
     */
    private boolean showZeroDays;
    /**
     * A flag that controls whether or not a zero hour count is displayed.
     *
     * @since 1.0.10
     */
    private boolean showZeroHours;
    /**
     * A formatter for the day count (most likely not critical until the
     * day count exceeds 999).
     */
    private NumberFormat dayFormatter;
    /**
     * A prefix prepended to the start of the format if the relative date is
     * positive.
     *
     * @since 1.0.10
     */
    private String positivePrefix;
    /**
     * A string appended after the day count.
     */
    private String daySuffix;
    /**
     * A formatter for the hours.
     *
     * @since 1.0.11
     */
    private NumberFormat hourFormatter;
    /**
     * A string appended after the hours.
     */
    private String hourSuffix;
    /**
     * A formatter for the minutes.
     *
     * @since 1.0.11
     */
    private NumberFormat minuteFormatter;
    /**
     * A string appended after the minutes.
     */
    private String minuteSuffix;
    /**
     * A formatter for the seconds (and milliseconds).
     */
    private NumberFormat secondFormatter;
    /**
     * A string appended after the seconds.
     */
    private String secondSuffix;
    /**
     * A constant for the number of milliseconds in one hour.
     */
    private static long MILLISECONDS_IN_ONE_HOUR = 60 * 60 * 1000L;
    /**
     * A constant for the number of milliseconds in one day.
     */
    private static long MILLISECONDS_IN_ONE_DAY = 24 * MILLISECONDS_IN_ONE_HOUR;
    /**
     * Creates a new instance with base milliseconds set to zero.
     */
    public RelativeDateFormat() {
        this(0L);
    }
    /**
     * Creates a new instance.
     *
     * @param time  the date/time (<code>null</code> not permitted).
     */
    public RelativeDateFormat(Date time) {
        this(time.getTime());
    }
    /**
     * Creates a new instance.
     *
     * @param baseMillis  the time zone (<code>null</code> not permitted).
     */
    public RelativeDateFormat(long baseMillis) {
        super();
        this.baseMillis = baseMillis;
        this.showZeroDays = false;
        this.showZeroHours = true;
        this.positivePrefix = "";
        this.dayFormatter = NumberFormat.getNumberInstance();
        this.daySuffix = "d";
        this.hourFormatter = NumberFormat.getNumberInstance();
        this.hourSuffix = "h";
        this.minuteFormatter = NumberFormat.getNumberInstance();
        this.minuteSuffix = "m";
        this.secondFormatter = NumberFormat.getNumberInstance();
        this.secondFormatter.setMaximumFractionDigits(3);
        this.secondFormatter.setMinimumFractionDigits(3);
        this.secondSuffix = "s";
        // we don"t use the calendar or numberFormat fields, but equals(Object)
        // is failing without them being non-null
        this.calendar = new GregorianCalendar();
        this.numberFormat = new DecimalFormat("0");
    }
    /**
     * Returns the base date/time used to calculate the elapsed time for
     * display.
     *
     * @return The base date/time in milliseconds since 1-Jan-1970.
     *
     * @see #setBaseMillis(long)
     */
    public long getBaseMillis() {
        return this.baseMillis;
    }
    /**
     * Sets the base date/time used to calculate the elapsed time for display.
     * This should be specified in milliseconds using the same encoding as
     * <code>java.util.Date</code>.
     *
     * @param baseMillis  the base date/time in milliseconds.
     *
     * @see #getBaseMillis()
     */
    public void setBaseMillis(long baseMillis) {
        this.baseMillis = baseMillis;
    }
    /**
     * Returns the flag that controls whether or not zero day counts are
     * shown in the formatted output.
     *
     * @return The flag.
     *
     * @see #setShowZeroDays(boolean)
     */
    public boolean getShowZeroDays() {
        return this.showZeroDays;
    }
    /**
     * Sets the flag that controls whether or not zero day counts are shown
     * in the formatted output.
     *
     * @param show  the flag.
     *
     * @see #getShowZeroDays()
     */
    public void setShowZeroDays(boolean show) {
        this.showZeroDays = show;
    }
    /**
     * Returns the flag that controls whether or not zero hour counts are
     * shown in the formatted output.
     *
     * @return The flag.
     *
     * @see #setShowZeroHours(boolean)
     *
     * @since 1.0.10
     */
    public boolean getShowZeroHours() {
        return this.showZeroHours;
    }
    /**
     * Sets the flag that controls whether or not zero hour counts are shown
     * in the formatted output.
     *
     * @param show  the flag.
     *
     * @see #getShowZeroHours()
     *
     * @since 1.0.10
     */
    public void setShowZeroHours(boolean show) {
        this.showZeroHours = show;
    }
    /**
     * Returns the string that is prepended to the format if the relative time
     * is positive.
     *
     * @return The string (never <code>null</code>).
     *
     * @see #setPositivePrefix(String)
     *
     * @since 1.0.10
     */
    public String getPositivePrefix() {
        return this.positivePrefix;
    }
    /**
     * Sets the string that is prepended to the format if the relative time is
     * positive.
     *
     * @param prefix  the prefix (<code>null</code> not permitted).
     *
     * @see #getPositivePrefix()
     *
     * @since 1.0.10
     */
    public void setPositivePrefix(String prefix) {
        if (prefix == null) {
            throw new IllegalArgumentException("Null "prefix" argument.");
        }
        this.positivePrefix = prefix;
    }
    /**
     * Sets the formatter for the days.
     *
     * @param formatter  the formatter (<code>null</code> not permitted).
     *
     * @since 1.0.11
     */
    public void setDayFormatter(NumberFormat formatter) {
        if (formatter == null) {
            throw new IllegalArgumentException("Null "formatter" argument.");
        }
        this.dayFormatter = formatter;
    }
    /**
     * Returns the string that is appended to the day count.
     *
     * @return The string.
     *
     * @see #setDaySuffix(String)
     */
    public String getDaySuffix() {
        return this.daySuffix;
    }
    /**
     * Sets the string that is appended to the day count.
     *
     * @param suffix  the suffix (<code>null</code> not permitted).
     *
     * @see #getDaySuffix()
     */
    public void setDaySuffix(String suffix) {
        if (suffix == null) {
            throw new IllegalArgumentException("Null "suffix" argument.");
        }
        this.daySuffix = suffix;
    }
    /**
     * Sets the formatter for the hours.
     *
     * @param formatter  the formatter (<code>null</code> not permitted).
     *
     * @since 1.0.11
     */
    public void setHourFormatter(NumberFormat formatter) {
        if (formatter == null) {
            throw new IllegalArgumentException("Null "formatter" argument.");
        }
        this.hourFormatter = formatter;
    }
    /**
     * Returns the string that is appended to the hour count.
     *
     * @return The string.
     *
     * @see #setHourSuffix(String)
     */
    public String getHourSuffix() {
        return this.hourSuffix;
    }
    /**
     * Sets the string that is appended to the hour count.
     *
     * @param suffix  the suffix (<code>null</code> not permitted).
     *
     * @see #getHourSuffix()
     */
    public void setHourSuffix(String suffix) {
        if (suffix == null) {
            throw new IllegalArgumentException("Null "suffix" argument.");
        }
        this.hourSuffix = suffix;
    }
    /**
     * Sets the formatter for the minutes.
     *
     * @param formatter  the formatter (<code>null</code> not permitted).
     *
     * @since 1.0.11
     */
    public void setMinuteFormatter(NumberFormat formatter) {
        if (formatter == null) {
            throw new IllegalArgumentException("Null "formatter" argument.");
        }
        this.minuteFormatter = formatter;
    }
    /**
     * Returns the string that is appended to the minute count.
     *
     * @return The string.
     *
     * @see #setMinuteSuffix(String)
     */
    public String getMinuteSuffix() {
        return this.minuteSuffix;
    }
    /**
     * Sets the string that is appended to the minute count.
     *
     * @param suffix  the suffix (<code>null</code> not permitted).
     *
     * @see #getMinuteSuffix()
     */
    public void setMinuteSuffix(String suffix) {
        if (suffix == null) {
            throw new IllegalArgumentException("Null "suffix" argument.");
        }
        this.minuteSuffix = suffix;
    }
    /**
     * Returns the string that is appended to the second count.
     *
     * @return The string.
     *
     * @see #setSecondSuffix(String)
     */
    public String getSecondSuffix() {
        return this.secondSuffix;
    }
    /**
     * Sets the string that is appended to the second count.
     *
     * @param suffix  the suffix (<code>null</code> not permitted).
     *
     * @see #getSecondSuffix()
     */
    public void setSecondSuffix(String suffix) {
        if (suffix == null) {
            throw new IllegalArgumentException("Null "suffix" argument.");
        }
        this.secondSuffix = suffix;
    }
    /**
     * Sets the formatter for the seconds and milliseconds.
     *
     * @param formatter  the formatter (<code>null</code> not permitted).
     */
    public void setSecondFormatter(NumberFormat formatter) {
        if (formatter == null) {
            throw new IllegalArgumentException("Null "formatter" argument.");
        }
        this.secondFormatter = formatter;
    }
    /**
     * Formats the given date as the amount of elapsed time (relative to the
     * base date specified in the constructor).
     *
     * @param date  the date.
     * @param toAppendTo  the string buffer.
     * @param fieldPosition  the field position.
     *
     * @return The formatted date.
     */
    public StringBuffer format(Date date, StringBuffer toAppendTo,
                               FieldPosition fieldPosition) {
        long currentMillis = date.getTime();
        long elapsed = currentMillis - this.baseMillis;
        String signPrefix;
        if (elapsed < 0) {
            elapsed *= -1L;
            signPrefix = "-";
        }
        else {
            signPrefix = this.positivePrefix;
        }
        long days = elapsed / MILLISECONDS_IN_ONE_DAY;
        elapsed = elapsed - (days * MILLISECONDS_IN_ONE_DAY);
        long hours = elapsed / MILLISECONDS_IN_ONE_HOUR;
        elapsed = elapsed - (hours * MILLISECONDS_IN_ONE_HOUR);
        long minutes = elapsed / 60000L;
        elapsed = elapsed - (minutes * 60000L);
        double seconds = elapsed / 1000.0;
        toAppendTo.append(signPrefix);
        if (days != 0 || this.showZeroDays) {
            toAppendTo.append(this.dayFormatter.format(days) + getDaySuffix());
        }
        if (hours != 0 || this.showZeroHours) {
            toAppendTo.append(this.hourFormatter.format(hours)
                    + getHourSuffix());
        }
        toAppendTo.append(this.minuteFormatter.format(minutes)
                + getMinuteSuffix());
        toAppendTo.append(this.secondFormatter.format(seconds)
                + getSecondSuffix());
        return toAppendTo;
    }
    /**
     * Parses the given string (not implemented).
     *
     * @param source  the date string.
     * @param pos  the parse position.
     *
     * @return <code>null</code>, as this method has not been implemented.
     */
    public Date parse(String source, ParsePosition pos) {
        return null;
    }
    /**
     * Tests this formatter for equality with an arbitrary object.
     *
     * @param obj  the object (<code>null</code> permitted).
     *
     * @return A boolean.
     */
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof RelativeDateFormat)) {
            return false;
        }
        if (!super.equals(obj)) {
            return false;
        }
        RelativeDateFormat that = (RelativeDateFormat) obj;
        if (this.baseMillis != that.baseMillis) {
            return false;
        }
        if (this.showZeroDays != that.showZeroDays) {
            return false;
        }
        if (this.showZeroHours != that.showZeroHours) {
            return false;
        }
        if (!this.positivePrefix.equals(that.positivePrefix)) {
            return false;
        }
        if (!this.daySuffix.equals(that.daySuffix)) {
            return false;
        }
        if (!this.hourSuffix.equals(that.hourSuffix)) {
            return false;
        }
        if (!this.minuteSuffix.equals(that.minuteSuffix)) {
            return false;
        }
        if (!this.secondSuffix.equals(that.secondSuffix)) {
            return false;
        }
        if (!this.dayFormatter.equals(that.dayFormatter)) {
            return false;
        }
        if (!this.hourFormatter.equals(that.hourFormatter)) {
            return false;
        }
        if (!this.minuteFormatter.equals(that.minuteFormatter)) {
            return false;
        }
        if (!this.secondFormatter.equals(that.secondFormatter)) {
            return false;
        }
        return true;
    }
    /**
     * Returns a hash code for this instance.
     *
     * @return A hash code.
     */
    public int hashCode() {
        int result = 193;
        result = 37 * result
                + (int) (this.baseMillis ^ (this.baseMillis >>> 32));
        result = 37 * result + this.positivePrefix.hashCode();
        result = 37 * result + this.daySuffix.hashCode();
        result = 37 * result + this.hourSuffix.hashCode();
        result = 37 * result + this.minuteSuffix.hashCode();
        result = 37 * result + this.secondSuffix.hashCode();
        result = 37 * result + this.secondFormatter.hashCode();
        return result;
    }
    /**
     * Returns a clone of this instance.
     *
     * @return A clone.
     */
    public Object clone() {
        RelativeDateFormat clone = (RelativeDateFormat) super.clone();
        clone.dayFormatter = (NumberFormat) this.dayFormatter.clone();
        clone.secondFormatter = (NumberFormat) this.secondFormatter.clone();
        return clone;
    }
    /**
     * Some test code.
     *
     * @param args  ignored.
     */
    public static void main(String[] args) {
        GregorianCalendar c0 = new GregorianCalendar(2006, 10, 1, 0, 0, 0);
        GregorianCalendar c1 = new GregorianCalendar(2006, 10, 1, 11, 37, 43);
        c1.set(Calendar.MILLISECOND, 123);
        System.out.println("Default: ");
        RelativeDateFormat rdf = new RelativeDateFormat(c0.getTime().getTime());
        System.out.println(rdf.format(c1.getTime()));
        System.out.println();
        System.out.println("Hide milliseconds: ");
        rdf.setSecondFormatter(new DecimalFormat("0"));
        System.out.println(rdf.format(c1.getTime()));
        System.out.println();
        System.out.println("Show zero day output: ");
        rdf.setShowZeroDays(true);
        System.out.println(rdf.format(c1.getTime()));
        System.out.println();
        System.out.println("Alternative suffixes: ");
        rdf.setShowZeroDays(false);
        rdf.setDaySuffix(":");
        rdf.setHourSuffix(":");
        rdf.setMinuteSuffix(":");
        rdf.setSecondSuffix("");
        System.out.println(rdf.format(c1.getTime()));
        System.out.println();
    }
}





Check if a String is a valid date

    
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Main {
  public static boolean isValidDate(String inDate) {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    dateFormat.setLenient(false);
    try {
      dateFormat.parse(inDate.trim());
    } catch (ParseException pe) {
      return false;
    }
    return true;
  }
  public static void main(String[] args) {
    System.out.println(isValidDate("2004-02-29"));
    System.out.println(isValidDate("2005-02-29"));
  }
}
/*
true
false
*/





Collection of useful utilities to work with dates

  
/*
 * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
 * 
 * Project: OpenSubsystems
 * 
 * $Id: DateUtils.java,v 1.7 2007/01/07 06:14:00 bastafidli Exp $
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License. 
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Collection of useful utilities to work with dates. 
 * 
 * @version $Id: DateUtils.java,v 1.7 2007/01/07 06:14:00 bastafidli Exp $
 * @author Miro Halas
 * @code.reviewer Miro Halas
 * @code.reviewed 1.5 2005/09/13 13:23:15 bastafidli
 */
public final class DateUtils
{
   // Constants ////////////////////////////////////////////////////////////////
   
   /**
    * One second in milliseconds.
    */
   public static final long ONE_SECOND = 1000L;
   
   /**
    * One minute in milliseconds.
    */
   public static final long ONE_MINUTE = ONE_SECOND * 60L;
   
   /**
    * One hour in milliseconds.
    */
   public static final long ONE_HOUR = ONE_MINUTE * 60L;
   
   /**
    * One day in milliseconds.
    */
   public static final long ONE_DAY = ONE_HOUR * 24L;
   
   /**
    * Separator we used to separate time from the nanosecond portion of the 
    * timestamp when converted to string.
    */
   public static final char NANO_SEPARATOR = ":";
   
   /**
    * Constant for timing type
    */
   public static final int TIMING_NEVER = 0;
   /**
    * Constant for timing type
    */
   public static final int TIMING_MINUTES = 1;
   /**
    * Constant for timing type
    */
   public static final int TIMING_HOURS = 2;
   /**
    * Constant for timing type
    */
   public static final int TIMING_DAYS = 3;
   /**
    * Constant for timing type
    */
   public static final int TIMING_WEEKS = 4;
   /**
    * Constant for timing type
    */
   public static final int TIMING_MONTHS = 5;
   /**
    * Constant for timing type
    */
   public static final int TIMING_YEARS = 6;
   
   /**
    * Constant for timing type
    */
   public static final int TIMING_NONE = 7;
   /**
    * Constant for current date code used in date/time formulas 
    */
   public static final String CURRENT_DATE_CODE = "now";
   
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char YEAR_CODE = "y";
   
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char MONTH_CODE = "M";
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char WEEK_CODE = "w";
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char DAY_CODE = "d";
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char HOUR_CODE = "h";
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char MINUTE_CODE = "m";
   
   /**
    * Constant for dynamic date code used in date/time formulas
    */
   public static final char SECOND_CODE = "s";
   /**
    * constant for date type DATE
    */
   public static final int DATE_TYPE_DATE = 1;
   /**
    * constant for date type TIME
    */
   public static final int DATE_TYPE_TIME = 2;
   /**
    * constant for date type DATETIME
    */
   public static final int DATE_TYPE_DATETIME = 3;
   
   // Constants for period start types /////////////////////////////////////////
// TODO: For Miro: Remove this code once all the code which referred to these
// constants was fixed
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_NONE = 0;
//
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_CREATION = 1;
//
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_COMPLETION = 2;
//
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_APPROVAL = 3;
//
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_ACTIVATION = 4;
//
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_INACTIVATION = 5;
//   
//   /**
//    * constant for period type
//    */
//   public static final int PERIOD_START_TYPE_DYNAMIC = 6;
//
//   /**
//    * constant for period type code
//    */
//   public static final int PERIOD_TYPE_CODE = 99;
//
//   /**
//    * constant for period type object
//    */
//   public static final Integer PERIOD_TYPE_OBJ = new Integer(PERIOD_TYPE_CODE);
   // Cached variables /////////////////////////////////////////////////////////
   
   /**
    * static SimpleDateFormat for date format to display on UI and in messages.
    */
   public static final SimpleDateFormat DATE_FORMAT 
                          = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT);
   
   /**
    * static SimpleDateFormat for time format to display on UI and in messages.
    */
   public static final SimpleDateFormat TIME_FORMAT 
                          = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.MEDIUM);
   
   /**
    * static SimpleDateFormat for datetime format to display on UI and in messages.
    */
   public static final SimpleDateFormat DATETIME_FORMAT 
                          = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, 
                                                           DateFormat.MEDIUM); 
   /**
    * static SimpleDateFormat for date format to store date as string so that
    * it is stored consistently.
    */
   public static final SimpleDateFormat DATE_STORE_FORMAT
                          = new SimpleDateFormat("MM/dd/yyyy");
   
   /**
    * static SimpleDateFormat for time format to store time as string so that
    * it is stored consistently.
    */
   public static final SimpleDateFormat TIME_STORE_FORMAT 
                          = new SimpleDateFormat("HH:mm:ss");
   
   /**
    * static SimpleDateFormat for datetime format to store date and time as 
    * string so that it is stored consistently.
    */
   public static final SimpleDateFormat DATETIME_STORE_FORMAT 
                          = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");

   /**
    * static SimpleDateFormat for date format for sql date
    */
   public static final SimpleDateFormat DATE_SQL_FORMAT
                          = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
   
   /**
    * static SimpleDateFormat for time format for sql time
    */
   public static final SimpleDateFormat TIME_SQL_FORMAT 
                          = new SimpleDateFormat("1970-01-01 HH:mm:ss");
   
   /**
    * static SimpleDateFormat for datetime format for sql date and time
    */
   public static final SimpleDateFormat DATETIME_SQL_FORMAT 
                          = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   // Constructors /////////////////////////////////////////////////////////////
   
   /** 
    * Private constructor since this class cannot be instantiated
    */
   private DateUtils(
   )
   {
      // Do nothing
   }
   
   // Public methods ///////////////////////////////////////////////////////////
   
   /**
    * Check if two dates equals regardless of the time. Two null dates are equal. 
    * Null and not null dates are not equal.
    * 
    * @param  dtFirst - first date to compare, can be null
    * @param  dtSecond - second date to compare, can be null 
    * @return boolean - true if two dates equals regardless of what the time is 
    */
   public static boolean dateEquals(
      Date dtFirst,
      Date dtSecond
   )
   {
      boolean  bReturn = false;
      
      // If they are the same object, they are equals
      bReturn = (dtFirst == dtSecond);
      if (!bReturn)
      {
         if (dtFirst == null)
         {
            // Two null dates are the same
            bReturn = (dtSecond == null);
         }
         else
         {
            if (dtSecond != null)
            {
               Calendar compCalendar;
               int      iEra;
               int      iYear;
               int      iMonth;
               int      iDay;
               
               compCalendar = Calendar.getInstance();
               compCalendar.setTime(dtFirst);
               iEra   = compCalendar.get(Calendar.ERA);
               iYear  = compCalendar.get(Calendar.YEAR);
               iMonth = compCalendar.get(Calendar.MONTH);
               iDay   = compCalendar.get(Calendar.DATE);
               compCalendar.setTime(dtSecond);
         
               bReturn = ((iEra == compCalendar.get(Calendar.ERA))
                         && (iYear == compCalendar.get(Calendar.YEAR))
                         && (iMonth == compCalendar.get(Calendar.MONTH))
                         && (iDay == compCalendar.get(Calendar.DATE)));
            }
         }
      } 
            
      return bReturn;            
   }
   
   /**
    * Check if two times equals regardless of the date. Two null times are equal. 
    * Null and not null times are not equal.
    * 
    * @param  dtFirst - first time to compare, can be null
    * @param  dtSecond - second time to compare, can be null
    * @param  bIgnoreMilliseconds - if true milliseconds will be ignored in comparison
    * @return boolean - true if two time equals regardless of what the date is 
    */
   public static boolean timeEquals(
      Date    dtFirst,
      Date    dtSecond,
      boolean bIgnoreMilliseconds
   )
   {
      boolean  bReturn = false;
      
      // If they are the same object, they are equals
      bReturn = (dtFirst == dtSecond);
      if (!bReturn)
      {
         if (dtFirst == null)
         {
            // Two null dates are the same
            bReturn = (dtSecond == null);
         }
         else
         {
            if (dtSecond != null)
            {
               Calendar compCalendar;
               int      iHour;
               int      iMinute;
               int      iSecond;
               int      iMili;
               
               compCalendar = Calendar.getInstance();
               compCalendar.setTime(dtFirst);
               iHour   = compCalendar.get(Calendar.HOUR_OF_DAY);
               iMinute = compCalendar.get(Calendar.MINUTE);
               iSecond = compCalendar.get(Calendar.SECOND);
               iMili   = compCalendar.get(Calendar.MILLISECOND);
               compCalendar.setTime(dtSecond);
         
               bReturn = ((iHour == compCalendar.get(Calendar.HOUR_OF_DAY))
                         && (iMinute == compCalendar.get(Calendar.MINUTE))
                         && (iSecond == compCalendar.get(Calendar.SECOND))
                         && ((bIgnoreMilliseconds) 
                            || (iMili == compCalendar.get(Calendar.MILLISECOND))));
            }
         }
      } 
            
      return bReturn;            
   }
   /**
    * Check if two dates and times are equal. Two null dates are equal. Null 
    * and not null dates are not equal.
    * 
    * @param  dtFirst - first date time to compare, can be null
    * @param  dtSecond - second date time to compare, can be null
    * @return boolean - true if two date and times are equal 
    */
   public static boolean dateAndTimeEquals(
      Date dtFirst,
      Date dtSecond
   )
   {
      boolean bReturn = false;
      
      // If they are the same object, they are equals
      bReturn = (dtFirst == dtSecond);
      if (!bReturn)
      {
         if (dtFirst == null)
         {
            // Two null dates are the same
            bReturn = (dtSecond == null);
         }
         else
         {
            if (dtSecond != null)
            {
               // They are both not null so they have to match to millisecond
               // (actually to nanosecond since the getTime takes nanoseconds
               // into account)
               bReturn = (dtFirst.getTime() == dtSecond.getTime());                               
            }
         }
      }
            
      return bReturn;            
   }
   /**
    * Check if String representing date is function or date. Date is a function
    * (formula) if it starts with the current date/time variable which can be 
    * followed by expression describing period from current date.
    *
    * @param strValue - string representation of date or date function
    * @return boolean - date function flag
    */
   public static boolean isFunction(
      String   strValue
   )
   {
      boolean bReturn = false;
      if ((strValue != null) && (strValue.length() > 0) 
         && (strValue.trim().startsWith(CURRENT_DATE_CODE)))
      {
         bReturn = true;
      }
      
      return bReturn;
   }
   
   /**
    * Parse date time value from given string resolving any functions or formulas
    * the string can contain. This method  can be therefore used if the passed 
    * string contains string representation date, time or timestamp or a formula
    * such as now + 3h - 1m + 4d. 
    *
    * @param strValue - string representation of date or date function
    * @param iDateType - date type code, one of the DATE_TYPE_XXX constants
    * @param stored - flag if Date should be parsed using format used for 
    *                 storage or for display
    * @return Timestamp - parsed date or null if date was null
    * @throws OSSInvalidDataException - error during parsing
    */
   public static Timestamp parseDateTime(
      String   strValue,
      int      iDateType,
      boolean  stored
   ) throws Exception
   {
      Timestamp tsReturn = null;
      Calendar workCal = GregorianCalendar.getInstance();
      
      if (strValue != null && strValue.length() > 0)
      {
         strValue = strValue.trim();
         if (strValue.startsWith(CURRENT_DATE_CODE))
         {
            strValue = strValue.replaceAll("[ ]", "");
            // If the user specified "UseCurrent", then substitute the
            // current date/time in the value
            workCal.setTime(new Date());
//            Log.getInstance().debug("Parsing current date " + strValue);
            // Parse the date math
            int iBeginIndex = CURRENT_DATE_CODE.length();
            int iMaxLength = strValue.length();
            int iSign = 1;
            int iNumberIndex;
            int iValue;
            char cChar = " ";
            while (iBeginIndex < iMaxLength)
            {
               // This has to be sign
               if (strValue.charAt(iBeginIndex) == "+")
               {
                  iSign = 1;
               }
               else if (strValue.charAt(iBeginIndex) == "-")
               {
                  iSign = -1;
               }
               else
               {
                  // Incorrect String
                  throw new Exception(
                           "Date function is in incorrect format: "
                           + strValue + " at " + strValue.substring(iBeginIndex));
               }
               iBeginIndex++;
               // Now we have to have number
               iNumberIndex = iBeginIndex;
               
               while (((iBeginIndex == iNumberIndex) || Character.isDigit(cChar)) 
                     && (iBeginIndex < iMaxLength))
               {
                  cChar = strValue.charAt(iBeginIndex++);
               }
               // We have to go one back because we should stop on modifier (e.g 1m)
               iBeginIndex--;
               try
               {
                  iValue = Integer.parseInt(strValue.substring(iNumberIndex, iBeginIndex));
               }
               catch (NumberFormatException nmeExc)
               {
                  // Incorrect String
                  throw new Exception(
                           "Date function is in incorrect format: "
                           + strValue + " at " + strValue.substring(iNumberIndex));
               }
               // This has to be modifier: y - year, M - month, w - week, 
               // d - day, h - hour, m - minute, s - second
               cChar = strValue.charAt(iBeginIndex);
               switch(cChar)
               {
                  case(YEAR_CODE):
                  {
                     if (iDateType == DATE_TYPE_TIME)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used YEAR modifier for TIME type");
                     }
                     workCal.add(Calendar.YEAR, iSign * iValue);
                     break;
                  }
                  case(MONTH_CODE):
                  {
                     if (iDateType == DATE_TYPE_TIME)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used MONTH modifier for TIME type");
                     }
                     workCal.add(Calendar.MONTH, iSign * iValue);
                     break;
                  }
                  case(WEEK_CODE):
                  {
                     if (iDateType == DATE_TYPE_TIME)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used WEEK modifier for TIME type");
                     }
                     workCal.add(Calendar.WEEK_OF_YEAR, iSign * iValue);
                     break;
                  }
                  case(DAY_CODE):
                  {
                     if (iDateType == DATE_TYPE_TIME)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used DAY modifier for TIME type");
                     }
                     workCal.add(Calendar.DATE, iSign * iValue);
                     break;
                  }
                  case(HOUR_CODE):
                  {
                     if (iDateType == DATE_TYPE_DATE)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used HOUR modifier for DATE type");
                     }
                     workCal.add(Calendar.HOUR, iSign * iValue);
                     break;
                  }
                  case(MINUTE_CODE):
                  {
                     if (iDateType == DATE_TYPE_DATE)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used MINUTE modifier for DATE type");
                     }
                     workCal.add(Calendar.MINUTE, iSign * iValue);
                     break;
                  }
                  case(SECOND_CODE):
                  {
                     if (iDateType == DATE_TYPE_DATE)
                     {
                        throw new Exception(
                           "Date function is in incorrect format: " +
                           "used SECOND modifier for DATE type");
                     }
                     workCal.add(Calendar.SECOND, iSign * iValue);
                     break;
                  }
                  default:
                  {
                     // Incorrect String
                     throw new Exception(
                           "Date function is in incorrect format: "
                           + strValue + " at " + strValue.substring(iBeginIndex));
                  }
               }
               iBeginIndex++;
            }
            
            tsReturn = new Timestamp(workCal.getTimeInMillis());
            
         }
         else
         {
            try
            {
               if (stored)
               {
                  switch (iDateType)
                  {
                     case (DATE_TYPE_DATE) :
                     {
                        tsReturn = new Timestamp(DATE_STORE_FORMAT.parse(strValue).getTime());
                        break;   
                     }
                     case (DATE_TYPE_TIME) :
                     {
                        tsReturn = new Timestamp(TIME_STORE_FORMAT.parse(strValue).getTime());
                        break;   
                     }
                     case (DATE_TYPE_DATETIME) :
                     {
                        tsReturn = new Timestamp(DATETIME_STORE_FORMAT.parse(strValue).getTime());
                        break;   
                     }
                     default:
                     {
                        assert false : "Unknown date type " + iDateType;
                     }
                  }                  
               }
               else
               {
                  switch (iDateType)
                  {
                     case (DATE_TYPE_DATE) :
                     {
                        tsReturn = new Timestamp(DATE_FORMAT.parse(strValue).getTime());
                        break;   
                     }
                     case (DATE_TYPE_TIME) :
                     {
                        tsReturn = new Timestamp(TIME_FORMAT.parse(strValue).getTime());
                        break;   
                     }
                     case (DATE_TYPE_DATETIME) :
                     {
                        tsReturn = new Timestamp(DATETIME_FORMAT.parse(strValue).getTime());
                        break;   
                     }
                     default:
                     {
                        assert false : "Unknown date type " + iDateType;
                     }                  
                  }                  
               }
            }
            catch (ParseException peExc)
            {
               throw new Exception(
                     "Date is in incorrect format. Problems with parsing.",
                     peExc);
            }
         }
      }
      return tsReturn;
   }
   
   /**
    * Parse the specified period into string displaying number of days the 
    * period represents. 
    * 
    * @param lPeriod - period in miliseconds
    * @return String - period in format "x day(s)" or "" if not valid period
    */
   public static String parseDayPeriod(
      long lPeriod
   )
   {
      StringBuffer sbReturn = new StringBuffer();
      long lDays = 0L;
      
      if (lPeriod > 0)
      {
         // we will count each started day as counted day 
         lPeriod = lPeriod + DateUtils.ONE_DAY - 1;
         
         lDays = lPeriod / DateUtils.ONE_DAY;
         sbReturn.append(lDays);
         if (lDays == 1L)
         {
            sbReturn.append(" day");
         }
         else
         {
            sbReturn.append(" days");
         }
      }
      else
      {
         sbReturn.append("0 days");
      }
      return sbReturn.toString();
   }
   
   /**
    * Parse the specified period into string displaying date and time the 
    * period represents. 
    * 
    * @param lPeriod - preiod in miliseconds
    * @return String - period in format "x day(s) y hour(s) z minute(s)" 
    *                  or "" if not valid period
    */
   public static String parseDayTimePeriod(
      long lPeriod
   )
   {
      StringBuffer sbReturn = new StringBuffer();
      long lHelp = 0L;
      
      
      if (lPeriod > 0)
      {
         lPeriod = lPeriod + DateUtils.ONE_MINUTE - 1;
         // we will count each started day as counted day 
         lHelp = lPeriod / DateUtils.ONE_DAY;
         if (lHelp > 0)
         {
            sbReturn.append(lHelp);
            if (lHelp == 1L)
            {
               sbReturn.append(" d ");
            }
            else
            {
               sbReturn.append(" d ");
            }
         }
         lPeriod = lPeriod % DateUtils.ONE_DAY;
         lHelp = lPeriod / DateUtils.ONE_HOUR;
         if (lHelp > 0 || sbReturn.length() > 0)
         {
            sbReturn.append(lHelp);
            if (lHelp == 1L)
            {
               sbReturn.append(" h ");
            }
            else
            {
               sbReturn.append(" h ");
            }
         }
         lPeriod = lPeriod % DateUtils.ONE_HOUR;
         lHelp = lPeriod / DateUtils.ONE_MINUTE;
         if (lHelp > 0 || sbReturn.length() > 0)
         {
            sbReturn.append(lHelp);
            if (lHelp == 1L)
            {
               sbReturn.append(" min");
            }
            else
            {
               sbReturn.append(" min");
            }
         }
      }
      else
      {
         sbReturn.append("0 min");
      }
      return sbReturn.toString();
   }
   
// TODO: For Miro: Remove this code once all the code which referred to these
// was fixed. These should be moved to a GUI related class.
//   /**
//    * Method for list of timing types.
//    * 
//    * @return List - list of timing types
//    */
//   public static List getTimingTypes(
//   )
//   { 
//      List lstTimingTypes = new ArrayList();
//      
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_MINUTES), 
//                                                           "Minute(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_HOURS), "Hour(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_DAYS), "Day(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_WEEKS), "Week(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_MONTHS), "Month(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_YEARS), "Year(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_NEVER), "Never"));
//      
//      return lstTimingTypes;
//   }
//   /**
//    * Method for list of timing types with None option.
//    * 
//    * @return List - list of timing types
//    */
//   public static List getTimingTypesWithNone(
//   )
//   { 
//      List lstTimingTypes = new ArrayList();
//      
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_NONE), "None"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_MINUTES), 
//                         "Minute(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_HOURS), "Hour(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_DAYS), "Day(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_WEEKS), "Week(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_MONTHS), "Month(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_YEARS), "Year(s)"));
//      lstTimingTypes.add(new SelectOption(Integer.toString(DateUtils.TIMING_NEVER), "Never"));
//      
//      return lstTimingTypes;
//   }
//   /**
//    * Method for getting string name of the timing type.
//    * 
//    * @param iTimingType - timing type constant
//    * @return String - string name of timing type
//    */
//   public static String getTimingTypeName(
//      int iTimingType
//   )
//   {
//      String outTimingTypeName = "Never"; 
//      switch (iTimingType)      
//      {
//         case (DateUtils.TIMING_NEVER):
//         {
//            outTimingTypeName = "Never";
//            break;
//         }
//         case (DateUtils.TIMING_MINUTES):
//         {
//            outTimingTypeName = "Minute(s)";
//            break;
//         }
//         case (DateUtils.TIMING_HOURS):
//         {
//            outTimingTypeName = "Hour(s)";
//            break;
//         }
//         case (DateUtils.TIMING_DAYS):
//         {
//            outTimingTypeName = "Day(s)";
//            break;
//         }
//         case (DateUtils.TIMING_WEEKS):
//         {
//            outTimingTypeName = "Week(s)";
//            break;
//         }
//         case (DateUtils.TIMING_MONTHS):
//         {
//            outTimingTypeName = "Month(s)";
//            break;
//         }
//         case (DateUtils.TIMING_YEARS):
//         {
//            outTimingTypeName = "Year(s)";
//            break;
//         }
//         case (DateUtils.TIMING_NONE):
//         {
//            outTimingTypeName = "None";
//            break;
//         }
//      }
//
//      return outTimingTypeName;
//   }
   
   /**
    * Get expiration timestamp from start date, period type and duration. For 
    * example if the start date is now, period type is hour and duration is 2
    * then the result will be timestamp representing now + 2 hours.  
    * 
    * @param tsStartDate - start date of period counting
    * @param iPeriodType - one of the period type constant TIMING_XXX 
    * @param iPeriodDuration - period duration, number of time units specified 
    *                          by period type
    * @return Timestamp - date of period expiration or null if any problem
    */
   public static Timestamp getPeriodExpiration(
      Timestamp tsStartDate,
      int       iPeriodType,
      int       iPeriodDuration
   )
   {
      Timestamp tsReturn = null;
      Calendar calHelp;
      if (tsStartDate != null && iPeriodDuration > 0 
            && iPeriodType > TIMING_NEVER && iPeriodType < TIMING_NONE)
      {
         calHelp = Calendar.getInstance();
         calHelp.setTime(tsStartDate);
         
         switch (iPeriodType)
         {
            case (TIMING_MINUTES) :
            {
               calHelp.add(Calendar.MINUTE, iPeriodDuration);
               break;
            }
            case (TIMING_HOURS) :
            {
               calHelp.add(Calendar.HOUR, iPeriodDuration);
               break;
            }
            case (TIMING_DAYS) :
            {
               calHelp.add(Calendar.DATE, iPeriodDuration);
               break;
            }
            case (TIMING_WEEKS) :
            {
               calHelp.add(Calendar.WEEK_OF_YEAR, iPeriodDuration);
               break;
            }
            case (TIMING_MONTHS) :
            {
               calHelp.add(Calendar.MONTH, iPeriodDuration);
               break;
            }
            case (TIMING_YEARS) :
            {
               calHelp.add(Calendar.YEAR, iPeriodDuration);
               break;
            }
            default :
            {
               assert false : "Not supported Timing type " + iPeriodType;
            } 
         }
         tsReturn = new Timestamp(calHelp.getTimeInMillis());
      }
      
      return tsReturn;
   }
   
   /**
    * Method to compare time periods
    * 
    * @param iPeriodType1 - first period type, one of the period type constant 
    *                       TIMING_XXX
    * @param iPeriodDuration1 - first period duration
    * @param iPeriodType2 - second period type, one of the period type constant 
    *                       TIMING_XXX
    * @param iPeriodDuration2 - second period duration
    * @return int - 1 - first period is longer
    *               0 - periods are same
    *              -1 - first period is shorter
    */
   public static int comparePeriods(
      int iPeriodType1,
      int iPeriodDuration1,
      int iPeriodType2,
      int iPeriodDuration2
   )
   {
      int iReturn = 0;
      
      if ((iPeriodType1 != TIMING_NEVER) && (iPeriodType1 != TIMING_NONE) 
         && (iPeriodType2 != TIMING_NEVER) && (iPeriodType2 != TIMING_NONE))
      {
         Timestamp tsTimestamp1 = getPeriodExpiration(
               new Timestamp(0), iPeriodType1, iPeriodDuration1);
         Timestamp tsTimestamp2 = getPeriodExpiration(
               new Timestamp(0), iPeriodType2, iPeriodDuration2);
         
         // TODO: Improve: When would any of these be null?
         if ((tsTimestamp1 != null) && (tsTimestamp2 != null))
         {
            if (tsTimestamp1.after(tsTimestamp2))
            {
               iReturn = 1;
            }
            else if (tsTimestamp2.after(tsTimestamp1))
            {
               iReturn = -1;
            }
         }
      }
      else
      {
         if (iPeriodType1 != iPeriodType2)
         {
            if (iPeriodType1 == TIMING_NEVER)
            {
               iReturn = 1;
            }
            else if (iPeriodType1 == TIMING_NONE)
            {
               iReturn = -1;
            }
            else if (iPeriodType2 == TIMING_NEVER)
            {
               iReturn = -1;
            }
            else if (iPeriodType2 == TIMING_NONE)
            {
               iReturn = 1;
            }
         }
      }
      return iReturn;      
   }
   
   /**
    * Convert timestamp to string including it"s nanosecond portion so that it 
    * can be safely stored in variable of web page.
    * 
    * @param tsTimestamp - timestamp to convert
    * @return String - text containing time and nanosecond portion of timestamp
    */
   public static String getTimestampAsString(
      Timestamp tsTimestamp
   )
   {
      StringBuffer sbTimestamp = new StringBuffer();
      
      sbTimestamp.append(tsTimestamp.getTime());
      sbTimestamp.append(NANO_SEPARATOR);
      sbTimestamp.append(tsTimestamp.getNanos());
      
      return sbTimestamp.toString();
   }
   
   /**
    * Convert string to timestamp including if available it"s nanosecond portion 
    * so that it can be safely restored from variable in web page.
    * 
    * @param strTimestamp - timestamp to convert
    * @return Timestamp - restored timestamp
    * @throws NumberFormatException - problem parsing the string
    */
   public static Timestamp parseTimestamp(
      String strTimestamp
   ) throws NumberFormatException
   {
      long      lTime;
      int       iNanos;
      if ("0".equals(strTimestamp))
      {
         lTime = 0L;
         iNanos = 0;
      }
      else
      {
         int       iIndex;
         
         iIndex = strTimestamp.indexOf(NANO_SEPARATOR);
         if (iIndex == -1)
         {
            throw new NumberFormatException(
                         "The timestamp string doesn"t contain nanosecond separator: "
                         + strTimestamp);
         }
         
         lTime = Long.parseLong(strTimestamp.substring(0, iIndex));
         iNanos = Integer.parseInt(strTimestamp.substring(iIndex + 1));
      }
      
      return new TimestampCopy(lTime, iNanos);
   }
   /**
    * Function returns time string in the form MM:SS.MS from the input specified in miliseconds. 
    * 
    * @param lTimeInMiliseconds - time in miliseconds
    * @return String - string representation of miliseconds in the form MM:SS.MS
    */
   public static String getStringTime(
      long lTimeInMiliseconds
   )
   {
      long lTotalMS   = lTimeInMiliseconds;
      long lMS        = lTotalMS % 1000;
      long lTotalSecs = lTotalMS / 1000;
      long lSecs      = lTotalSecs % 60;
      long lTotalMins = lTotalSecs / 60;
      long lMinutes   = lTotalMins % 60;
      long lHours     = lTotalMins / 60;
      StringBuffer sbBuffer = new StringBuffer();
      if (lHours > 0)
      {
         sbBuffer.append(lHours);
         sbBuffer.append(":");
         sbBuffer.append(lMinutes);
         sbBuffer.append(":");
         sbBuffer.append(lSecs);
         sbBuffer.append(".");
         sbBuffer.append(lMS);
      }
      else if (lMinutes > 0)
      {
         sbBuffer.append(lMinutes);
         sbBuffer.append(":");
         sbBuffer.append(lSecs);
         sbBuffer.append(".");
         sbBuffer.append(lMS);
      }
      else if (lSecs > 0)
      {
         sbBuffer.append(lSecs);
         sbBuffer.append(".");
         sbBuffer.append(lMS);
         sbBuffer.append(" seconds");
      }
      else
      {
         sbBuffer.append(lMS);
         sbBuffer.append(" ms");
      }
      
      return sbBuffer.toString();
   }
// TODO: For Miro: Remove this code once all the code which referred to these
// was fixed. These should be moved to a GUI or business logic related class.
//   /**
//    * Method to check if valid period settings
//    * 
//    * @param iPeriod - period length
//    * @param iPeriodType - period type
//    * @param iPeriodStartType - period start type
//    * @param iAttributeId - attribute ID for dynamic period start type
//    * @param bPeriodException - period exception flag
//    * @param strPeriodName - period name used for exception message
//    * @param bAdvancePeriodType - flag if advanced period type (includes also start type)
//    * @param bfideException - invalid data exception
//    */
//   public static void validatePeriod(
//      int iPeriod,
//      int iPeriodType,
//      int iPeriodStartType,
//      int iAttributeId,
//      boolean bPeriodException,
//      String strPeriodName,
//      boolean bAdvancePeriodType,
//      OSSInvalidDataException messageException
//   ) 
//   {
//      if ((iPeriod > 0) 
//         || ((iPeriodType != TIMING_NONE) && (iPeriodType != TIMING_NEVER)) 
//         || (bPeriodException) || (iPeriodStartType != PERIOD_START_TYPE_NONE))
//      {
//         if (iPeriod <= 0)
//         {
//            if (messageException == null)
//            {
//               messageException = new OSSInvalidDataException();
//            }
//            messageException.getErrorMessages().addMessage(
//               PERIOD_TYPE_OBJ, 
//               "You have to set valid period length for " + strPeriodName + " type."
//            );
//         }
//         else if ((iPeriodType == TIMING_NONE) || (iPeriodType == TIMING_NEVER))
//         {
//            if (messageException == null)
//            {
//               messageException = new OSSInvalidDataException();
//            }
//            messageException.getErrorMessages().addMessage(
//               PERIOD_TYPE_OBJ, 
//               "You have to set valid period type for " + strPeriodName + " type."
//            );
//         }
//         else if ((bAdvancePeriodType) && (iPeriodStartType == PERIOD_START_TYPE_NONE))
//         {
//            if (messageException == null)
//            {
//               messageException = new OSSInvalidDataException();
//            }
//            messageException.getErrorMessages().addMessage(
//               PERIOD_TYPE_OBJ, 
//               "You have to set valid period start type for " + strPeriodName + " type."
//            );
//         }
//         else if ((bAdvancePeriodType) 
//                 && (iPeriodStartType == PERIOD_START_TYPE_DYNAMIC) 
//                 && (iAttributeId == DataObject.NEW_ID))
//         {
//            if (messageException == null)
//            {
//               messageException = new OSSInvalidDataException();
//            }
//            messageException.getErrorMessages().addMessage(
//               PERIOD_TYPE_OBJ, 
//               "You have to set valid period dynamic start attribute for " 
//               + strPeriodName + " type."
//            );
//         }
//      }
//   }
}
/*
 * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
 * 
 * Project: OpenSubsystems
 * 
 * $Id: TimestampCopy.java,v 1.5 2007/01/07 06:14:01 bastafidli Exp $
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License. 
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

/**
 * Timestamp which adds copy constructor which correctly copies nanosecond 
 * portion of the original timestamp. 
 * 
 * @version $Id: TimestampCopy.java,v 1.5 2007/01/07 06:14:01 bastafidli Exp $
 * @author Miro Halas
 * @code.reviewer Miro Halas
 * @code.reviewed 1.3 2006/02/17 06:54:53 bastafidli
 */
class TimestampCopy extends Timestamp
{
   // Attributes ///////////////////////////////////////////////////////////////
   
   /**
    * Generated serial version id for this class.
    */
   private static final long serialVersionUID = 135570135998694876L;
   // Constructors /////////////////////////////////////////////////////////////
   
   /**
    * Copy constructor which will create exact copy of the timestamp including
    * the nanosecond portion.
    * 
    * @param original - original timestamp to copy
    */
   public TimestampCopy(
      Timestamp original
   )
   {
      // Pass the time portion here
      super(original.getTime());
      // And now set the correct nanoseconds since it is required.
      setNanos(original.getNanos());
   }
   /**
    * Constructor which will create exact copy of the timestamp including
    * the nanosecond portion.
    * 
    * @param lTime - time portion of the timestamp
    * @param iNanos - nanosecond portion of the timestamp
    */
   public TimestampCopy(
      long lTime,
      int  iNanos
   )
   {
      // Pass the time portion here
      super(lTime);
      // And now set the correct nanoseconds since it is required.
      setNanos(iNanos);
   }
}





Compare two Java Date objects using after method example

    
import java.util.Date;
public class Main {
  public static void main(String[] args) {
    Date d1 = new Date();
    Date d2 = new Date();
    System.out.println("First Date : " + d1);
    System.out.println("Second Date : " + d2);
    System.out.println("Is second date after first ? : " + d2.after(d1));
  }
}





Compare two Java Date objects using before method example

    
import java.util.Date;
public class Main {
  public static void main(String[] args) {
    Date d1 = new Date();
    Date d2 = new Date();
    System.out.println("First Date : " + d1);
    System.out.println("Second Date : " + d2);
    System.out.println("Is first date before second ? : " + d1.before(d2));
  }
}





Compare two Java Date objects using compareTo method example

    
import java.util.Date;
public class Main {
  public static void main(String[] args) {
    Date d1 = new Date();
    Date d2 = new Date();
    System.out.println("First Date : " + d1);
    System.out.println("Second Date : " + d2);
    int results = d1.rupareTo(d2);
    if (results > 0) {
      System.out.println("after");
    } else if (results < 0) {
      System.out.println("before");
    } else {
      System.out.println("Both dates are equal");
    }
  }
}





Convert a String to Date

    
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
  public static void main(String[] args) throws Exception {
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
    Date theDate = dateFormat.parse("01/01/2009");
    System.out.println(dateFormat.format(theDate));
  }
}
//01/01/2009





Convert Date into milliseconds example

    
import java.util.Date;
public class Main {
  public static void main(String args[]) {
    Date date = new Date();
    System.out.println("Date is : " + date);
    System.out.println("Milliseconds since January 1, 1970, 00:00:00 GMT : " + date.getTime());
  }
}





Convert date string from one format to another format using SimpleDateFormat

    
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
  public static void main(String[] args) throws Exception {
    SimpleDateFormat sdfSource = new SimpleDateFormat("dd/MM/yy");
    Date date = sdfSource.parse("12/11/09");
    SimpleDateFormat sdfDestination = new SimpleDateFormat("MM-dd-yyyy hh:mm:ss");
    System.out.println(sdfDestination.format(date));
  }
}





Convert string of time to time object

    
 
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
  public static void main(String[] args) throws Exception {
    String time = "15:30:18";
    DateFormat sdf = new SimpleDateFormat("hh:mm:ss");
    Date date = sdf.parse(time);
    System.out.println("Date and Time: " + date);
  }
}





Convert String to Date object

    
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Main {
  public static void main(String[] args) throws Exception{
    DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
    Date today = df.parse("20/12/2005");
    System.out.println("Today = " + df.format(today));
  }
}





Create instance of java.sql.Date from Calendar.getTimeInMillis()

    
    
import java.util.Calendar;
public class Main {
  public static void main(String[] args) {
    int year = 2009;
    int month = 0; // January
    int date = 1;
    Calendar cal = Calendar.getInstance();
    cal.clear();
    cal.set(Calendar.YEAR, year);
    cal.set(Calendar.MONTH, month);
    cal.set(Calendar.DATE, date);
    java.sql.Date sqlDate = new java.sql.Date(cal.getTimeInMillis());
    System.out.println(sqlDate);
  }
}
//2009-01-01





Create java Date from specific time example

    
import java.util.Date;
public class Main {
  public static void main(String[] args) {
    Date d = new Date(365L * 24L * 60L * 60L * 1000L);
    System.out.println(d);
  }
}





Creating a Date Object for a Particular Date

    
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
public class Main {
  public static void main(String[] argv) throws Exception {
    Calendar xmas = new GregorianCalendar(1998, Calendar.DECEMBER, 25);
    Date date = xmas.getTime();
  }
}





Date utility class

  
/* 
 *    D E E P B L A C K    B L O G    L I C E N S E
 * 
 *
 * Copyright (c) 2001-2003 Timothy J. Kettering  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The names "deepBlack" must not be used to endorse or promote 
 *    products derived from this software without prior written 
 *    permission. For written permission, please contact 
 *    the copyright holder at tim@blackcore.ru.
 *
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 */
import java.util.Date;
import java.util.TimeZone;
import java.util.GregorianCalendar;
import java.util.Calendar;
/**
 * Date utility class file.
 * @author timster@blackcore.ru
 * Nov 17, 2002
 *
 * @todo - Only the timestamp parameter methods have been tested somewhat
 * extensively to be sure they return correct timestamps.  The string
 * and integer parameter methods need to be refined for accurate behavior, and
 * better failsafes.
 * 
 */
public class DateUtility
{
  /**
   * Returns a primitive long which represents the timestamp of the first millisecond
   * of the month matching the supplied parameters.  This method assumes the
   * default timezone.
   * @param year
   * @param month
   * @return long
   */
  static public long getFirstMilliOfMonth(String year, String month)
  {
    return getFirstMilliOfMonth(year, month, TimeZone.getDefault());
  }
  /**
   * Returns a primitive long which represents the timestamp of the last millisecond
   * of the month matching the supplied parameters.  This method assumes the
   * default timezone.
   * @param year
   * @param month
   * @return long
   */ 
  static public long getLastMilliOfMonth(String year, String month)
  {
    return getLastMilliOfMonth(year, month, TimeZone.getDefault());
  } 
  /**
   * This utility returns the first millsecond 
   * of the month, and year, and timezone supplied as arguments.
   *
   * @param String month
   * @param String year
   * @param TimeZone tz
   * @return long
   */
  static public long getFirstMilliOfMonth(String year, String month, TimeZone tz)
  {
    return getFirstMilliOfMonth(Integer.parseInt(year), Integer.parseInt(month), tz);
  }
  /**
   * This utility returns the first millsecond 
   * of the month, and year, and timezone supplied as arguments.
   *
   * @param int month
   * @param int year
   * @param TimeZone tz
   * @return long
   */
  static public long getFirstMilliOfMonth(int year, int month, TimeZone tz)
  {
    GregorianCalendar cal = new GregorianCalendar(year, (month - 1), 1);
    cal.setTimeZone(tz);
    return cal.getTime().getTime();
  }
  
  /**
   * This will retun the first millisecond of the month 
   * that contains the timestamp provided
   * @param timestamp
   * @return long
   */
  static public long getFirstMilliOfMonth(long timestamp, TimeZone tz)
  {
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTimeZone(tz);
    cal.setTime(new Date(timestamp));
    cal.set(Calendar.DAY_OF_MONTH, 1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    
    Date date = cal.getTime();
    
    return date.getTime();
  }
  
  /**
   * Gets the last millsecond of the month, according to the timestamp and 
   * timezone arguments.
   * @param timestamp
   * @param tz
   * @return long
   */
  static public long getLastMilliOfMonth(long timestamp, TimeZone tz)
  {
    timestamp = getFirstMilliOfMonth(timestamp, tz);
    
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTimeZone(tz);
    cal.setTime(new Date(timestamp));
    // now we"ll roll the calendar forward one month.
    // in the case of december, we need to roll forward the year too    
    if(cal.get(GregorianCalendar.MONTH) == GregorianCalendar.DECEMBER)
    {
      cal.roll(GregorianCalendar.YEAR, true);
    }
    
    cal.roll(GregorianCalendar.MONTH, true);
    
    long date = cal.getTime().getTime();
    
    date = date - 1L;
    return date;
  }
  
  /**
   * This utility returns the last millsecond 
   * of the month, and year, and timezone supplied as arguments.
   *
   * @param String month
   * @param String year
   * @param TimeZone tz
   * @return long
   */
  static public long getLastMilliOfMonth(String year, String month, TimeZone tz)
  {
    long time = getLastMilliOfMonth(Integer.parseInt(year), Integer.parseInt(month), tz);
    return time;
  } 
  
  /**
   * This utility returns the last millsecond 
   * of the month, and year, and timezone supplied as arguments.
   *
   * @param int month
   * @param int year
   * @param TimeZone tz
   * @return long
   */
  static public long getLastMilliOfMonth(int year, int month, TimeZone tz)
  {     
    GregorianCalendar cal = new GregorianCalendar(year, (month - 1), 1);
    cal.setTimeZone(tz);
    
    // set the maximum last day
    int lastday = cal.getActualMaximum(GregorianCalendar.DAY_OF_MONTH);
    cal.set(GregorianCalendar.DAY_OF_MONTH, lastday);
    // set other calendar maximums.  - we should do this programatically
    // too but i"m too lazy, and i dont think they"re gonna change the gregorian
    // calendar anytime soon.. eh?
    cal.set(GregorianCalendar.HOUR_OF_DAY, 23);
    cal.set(GregorianCalendar.MINUTE, 59);
    cal.set(GregorianCalendar.SECOND, 59);
    cal.set(GregorianCalendar.MILLISECOND, 999);
    long time = cal.getTime().getTime();
    return time;
  } 
}





Date Utils

  
/*
** Caramel - Non-GUI Java Addons
** Copyright (c) 2001, 2002, 2003 by Gerald Bauer
**
** This program is free software.
**
** You may redistribute it and/or modify it under the terms of the GNU
** Lesser General Public License as published by the Free Software Foundation.
** Version 2.1 of the license should be included with this distribution in
** the file LICENSE, as well as License.html. If the license is not
** included with this distribution, you may find a copy at the FSF web
** site at "www.gnu.org" or "www.fsf.org", or you may write to the
** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
**
** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
** REDISTRIBUTION OF THIS SOFTWARE.
**
*/

import java.text.*;
import java.util.*;
public class DateUtils
{
   /**
    *  RFC 1123 date format example: Mon, 06 May 1996 04:57:00 GMT - days: Mon,
    *  Tue, Wed, Thu, Fri, Sat, Sun - months: Jan, Feb, Mar, Apr, May, Jun, Jul,
    *  Aug, Sep, Oct, Nov, Dec
    */
   private static SimpleDateFormat _df;
   public static String getDate()
   {
      Calendar cal = Calendar.getInstance();
      cal.setTime( new Date() );
      int year = cal.get( Calendar.YEAR );
      int month = cal.get( Calendar.MONTH ) + 1;
      int day = cal.get( Calendar.DAY_OF_MONTH );
      return "" + year
             + "-" + month
             + "-" + day;
   }
   /**
    *  convienence method returns current timestamp
    */
   public static String getHttpDate()
   {
      return getHttpDate( new Date() );
   }
   public static String getHttpDate( long timestamp )
   {
      return getHttpDate( new Date( timestamp ) );
   }
   public static String getHttpDate( Date date )
   {
      return _df.format( date );
   }
   public static String getTime()
   {
      Calendar cal = Calendar.getInstance();
      cal.setTime( new Date() );
      int hours = cal.get( Calendar.HOUR_OF_DAY );
      // use 24 hour clock
      int minutes = cal.get( Calendar.MINUTE );
      int seconds = cal.get( Calendar.SECOND );
      int milli = cal.get( Calendar.MILLISECOND );
      return formatTime( hours, minutes, seconds, milli );
   }
   public static String getTimestamp()
   {
      Calendar cal = Calendar.getInstance();
      cal.setTime( new Date() );
      int year = cal.get( Calendar.YEAR );
      int month = cal.get( Calendar.MONTH ) + 1;
      int day = cal.get( Calendar.DAY_OF_MONTH );
      int hours = cal.get( Calendar.HOUR_OF_DAY );
      // use 24 hour clock
      int minutes = cal.get( Calendar.MINUTE );
      int seconds = cal.get( Calendar.SECOND );
      int milli = cal.get( Calendar.MILLISECOND );
      return "" + year
             + "-" + month
             + "-" + day
             + "_" + formatTime( hours, minutes, seconds, milli );
   }
   private static String formatTime( int hours, int minutes, int seconds, int milli )
   {
      StringBuffer buf = new StringBuffer();
      buf.append( "" + hours );
      buf.append( "." );
      if( minutes < 10 )
         buf.append( "0" + minutes );
      else
         buf.append( "" + minutes );
      buf.append( "." );
      if( seconds < 10 )
         buf.append( "0" + seconds );
      else
         buf.append( "" + seconds );
      buf.append( "-" );
      if( milli < 10 )
         buf.append( "00" + milli );
      else if( milli < 100 )
         buf.append( "0" + milli );
      else
         buf.append( "" + milli );
      return buf.toString();
   }
   static
   {
      _df = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US );
      _df.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
   }
}





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;
  }
}





Return now as a string

  
/*
 * This file is part of JGAP.
 *
 * JGAP offers a dual license model containing the LGPL as well as the MPL.
 *
 * For licensing information please see the file license.txt included with JGAP
 * or have a look at the top of class org.jgap.Chromosome which representatively
 * includes the JGAP license policy applicable for any file delivered with JGAP.
 */
import java.text.*;
import java.util.*;
/**
 * Utility functions related to date and time.
 *
 * @author Klaus Meffert
 * @since 3.3.3
 */
public class DateKit {
  /** String containing the CVS revision. Read out via reflection!*/
  private final static String CVS_REVISION = "$Revision: 1.4 $";
  private static Calendar m_cal = Calendar.getInstance();
  public final static String DATEFORMAT_FULL_0 = "yyyyMMddHHmmssSSS";
  public final static String DATEFORMAT_FULL_1 = "yyyy/MM/dd HH:mm:ss:SSS";
  public final static String DATEFORMAT_NORMAL = "yyyy/MM/dd";
  private static SimpleDateFormat m_sdfNow = new SimpleDateFormat(DATEFORMAT_FULL_0);

  private static SimpleDateFormat m_sdfToday = new SimpleDateFormat("yyyyMMdd");
  /**
   * @return now as a string, including milliseconds
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public static String getNowAsString() {
    return m_sdfNow.format(m_cal.getTime());
  }
  /**
   * @return today as a string
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public static String getTodayAsString() {
    return m_sdfToday.format(m_cal.getTime());
  }
  /**
   * @param a_date the date to be returned in a specific format
   * @param a_dateFormat the desired format of the date
   *
   * @return date in given format
   *
   * @author Klaus Meffert
   * @since 3.3.4
   */
  public static String dateToString(Date a_date, String a_dateFormat) {
    SimpleDateFormat sdf = new SimpleDateFormat(a_dateFormat);
    return sdf.format(a_date);
  }
  /**
   * @return now
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public static Date now() {
    return new Date();
  }
}





Return today as a string

  
/*
 * This file is part of JGAP.
 *
 * JGAP offers a dual license model containing the LGPL as well as the MPL.
 *
 * For licensing information please see the file license.txt included with JGAP
 * or have a look at the top of class org.jgap.Chromosome which representatively
 * includes the JGAP license policy applicable for any file delivered with JGAP.
 */
import java.text.*;
import java.util.*;
/**
 * Utility functions related to date and time.
 *
 * @author Klaus Meffert
 * @since 3.3.3
 */
public class DateKit {
  /** String containing the CVS revision. Read out via reflection!*/
  private final static String CVS_REVISION = "$Revision: 1.4 $";
  private static Calendar m_cal = Calendar.getInstance();
  public final static String DATEFORMAT_FULL_0 = "yyyyMMddHHmmssSSS";
  public final static String DATEFORMAT_FULL_1 = "yyyy/MM/dd HH:mm:ss:SSS";
  public final static String DATEFORMAT_NORMAL = "yyyy/MM/dd";
  private static SimpleDateFormat m_sdfNow = new SimpleDateFormat(DATEFORMAT_FULL_0);

  private static SimpleDateFormat m_sdfToday = new SimpleDateFormat("yyyyMMdd");
  /**
   * @return now as a string, including milliseconds
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public static String getNowAsString() {
    return m_sdfNow.format(m_cal.getTime());
  }
  /**
   * @return today as a string
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public static String getTodayAsString() {
    return m_sdfToday.format(m_cal.getTime());
  }
  /**
   * @param a_date the date to be returned in a specific format
   * @param a_dateFormat the desired format of the date
   *
   * @return date in given format
   *
   * @author Klaus Meffert
   * @since 3.3.4
   */
  public static String dateToString(Date a_date, String a_dateFormat) {
    SimpleDateFormat sdf = new SimpleDateFormat(a_dateFormat);
    return sdf.format(a_date);
  }
  /**
   * @return now
   *
   * @author Klaus Meffert
   * @since 3.3.3
   */
  public static Date now() {
    return new Date();
  }
}





Sets the day of month field to a date returning a new object.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  //-----------------------------------------------------------------------
  /**
   * Sets the day of month field to a date returning a new object.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  public static Date setDays(Date date, int amount) {
      return set(date, Calendar.DAY_OF_MONTH, amount);
  }

  //-----------------------------------------------------------------------
  /**
   * Sets the specified field to a date returning a new object.  
   * This does not use a lenient calendar.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param calendarField  the calendar field to set the amount to
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  private static Date set(Date date, int calendarField, int amount) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      // getInstance() returns a new object, so this method is thread safe.
      Calendar c = Calendar.getInstance();
      c.setLenient(false);
      c.setTime(date);
      c.set(calendarField, amount);
      return c.getTime();
  }   
}





Sets the hours field to a date returning a new object. Hours range from 0-23.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  //-----------------------------------------------------------------------
  /**
   * Sets the hours field to a date returning a new object.  Hours range 
   * from  0-23.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  public static Date setHours(Date date, int amount) {
      return set(date, Calendar.HOUR_OF_DAY, amount);
  }
  //-----------------------------------------------------------------------
  /**
   * Sets the specified field to a date returning a new object.  
   * This does not use a lenient calendar.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param calendarField  the calendar field to set the amount to
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  private static Date set(Date date, int calendarField, int amount) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      // getInstance() returns a new object, so this method is thread safe.
      Calendar c = Calendar.getInstance();
      c.setLenient(false);
      c.setTime(date);
      c.set(calendarField, amount);
      return c.getTime();
  }   
}





Sets the miliseconds field to a date returning a new object.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  //-----------------------------------------------------------------------
  /**
   * Sets the miliseconds field to a date returning a new object.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  public static Date setMilliseconds(Date date, int amount) {
      return set(date, Calendar.MILLISECOND, amount);
  } 
  //-----------------------------------------------------------------------
  /**
   * Sets the specified field to a date returning a new object.  
   * This does not use a lenient calendar.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param calendarField  the calendar field to set the amount to
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  private static Date set(Date date, int calendarField, int amount) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      // getInstance() returns a new object, so this method is thread safe.
      Calendar c = Calendar.getInstance();
      c.setLenient(false);
      c.setTime(date);
      c.set(calendarField, amount);
      return c.getTime();
  }   
}





Sets the minute field to a date returning a new object.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  //-----------------------------------------------------------------------
  /**
   * Sets the minute field to a date returning a new object.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  public static Date setMinutes(Date date, int amount) {
      return set(date, Calendar.MINUTE, amount);
  }
  //-----------------------------------------------------------------------
  /**
   * Sets the specified field to a date returning a new object.  
   * This does not use a lenient calendar.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param calendarField  the calendar field to set the amount to
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  private static Date set(Date date, int calendarField, int amount) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      // getInstance() returns a new object, so this method is thread safe.
      Calendar c = Calendar.getInstance();
      c.setLenient(false);
      c.setTime(date);
      c.set(calendarField, amount);
      return c.getTime();
  }   
}





Sets the seconds field to a date returning a new object.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  
  //-----------------------------------------------------------------------
  /**
   * Sets the seconds field to a date returning a new object.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  public static Date setSeconds(Date date, int amount) {
      return set(date, Calendar.SECOND, amount);
  }
  //-----------------------------------------------------------------------
  /**
   * Sets the specified field to a date returning a new object.  
   * This does not use a lenient calendar.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param calendarField  the calendar field to set the amount to
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  private static Date set(Date date, int calendarField, int amount) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      // getInstance() returns a new object, so this method is thread safe.
      Calendar c = Calendar.getInstance();
      c.setLenient(false);
      c.setTime(date);
      c.set(calendarField, amount);
      return c.getTime();
  }   
}





Sets the years field to a date returning a new object.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  //-----------------------------------------------------------------------
  /**
   * Sets the years field to a date returning a new object.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  public static Date setYears(Date date, int amount) {
      return set(date, Calendar.YEAR, amount);
  }
  //-----------------------------------------------------------------------
  /**
   * Sets the specified field to a date returning a new object.  
   * This does not use a lenient calendar.
   * The original date object is unchanged.
   *
   * @param date  the date, not null
   * @param calendarField  the calendar field to set the amount to
   * @param amount the amount to set
   * @return a new Date object set with the specified value
   * @throws IllegalArgumentException if the date is null
   * @since 2.4
   */
  private static Date set(Date date, int calendarField, int amount) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      // getInstance() returns a new object, so this method is thread safe.
      Calendar c = Calendar.getInstance();
      c.setLenient(false);
      c.setTime(date);
      c.set(calendarField, amount);
      return c.getTime();
  }   
}





Truncate this date(Calendar), leaving the field specified as the most significant field.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  private static final int[][] fields = {
    {Calendar.MILLISECOND},
    {Calendar.SECOND},
    {Calendar.MINUTE},
    {Calendar.HOUR_OF_DAY, Calendar.HOUR},
    {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM 
        /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
    },
    {Calendar.MONTH, DateUtils.SEMI_MONTH},
    {Calendar.YEAR},
    {Calendar.ERA}};

  /**
   * <p>Truncate this date, leaving the field specified as the most
   * significant field.</p>
   *
   * <p>For example, if you had the datetime of 28 Mar 2002
   * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
   * 2002 13:00:00.000.  If this was passed with MONTH, it would
   * return 1 Mar 2002 0:00:00.000.</p>
   * 
   * @param date  the date to work with
   * @param field  the field from <code>Calendar</code>
   *  or <code>SEMI_MONTH</code>
   * @return the rounded date (a different object)
   * @throws IllegalArgumentException if the date is <code>null</code>
   * @throws ArithmeticException if the year is over 280 million
   */
  public static Calendar truncate(Calendar date, int field) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      Calendar truncated = (Calendar) date.clone();
      modify(truncated, field, false);
      return truncated;
  }
  //-----------------------------------------------------------------------
  /**
   * <p>Internal calculation method.</p>
   * 
   * @param val  the calendar
   * @param field  the field constant
   * @param round  true to round, false to truncate
   * @throws ArithmeticException if the year is over 280 million
   */
  private static void modify(Calendar val, int field, boolean round) {
      if (val.get(Calendar.YEAR) > 280000000) {
          throw new ArithmeticException("Calendar value too large for accurate calculations");
      }
      
      if (field == Calendar.MILLISECOND) {
          return;
      }
      // ----------------- Fix for LANG-59 ---------------------- START ---------------
      // see http://issues.apache.org/jira/browse/LANG-59
      //
      // Manually truncate milliseconds, seconds and minutes, rather than using
      // Calendar methods.
      Date date = val.getTime();
      long time = date.getTime();
      boolean done = false;
      // truncate milliseconds
      int millisecs = val.get(Calendar.MILLISECOND);
      if (!round || millisecs < 500) {
          time = time - millisecs;
      }
      if (field == Calendar.SECOND) {
          done = true;
      }
      // truncate seconds
      int seconds = val.get(Calendar.SECOND);
      if (!done && (!round || seconds < 30)) {
          time = time - (seconds * 1000L);
      }
      if (field == Calendar.MINUTE) {
          done = true;
      }
      // truncate minutes
      int minutes = val.get(Calendar.MINUTE);
      if (!done && (!round || minutes < 30)) {
          time = time - (minutes * 60000L);
      }
      // reset time
      if (date.getTime() != time) {
          date.setTime(time);
          val.setTime(date);
      }
      // ----------------- Fix for LANG-59 ----------------------- END ----------------
      boolean roundUp = false;
      for (int i = 0; i < fields.length; i++) {
          for (int j = 0; j < fields[i].length; j++) {
              if (fields[i][j] == field) {
                  //This is our field... we stop looping
                  if (round && roundUp) {
                      if (field == DateUtils.SEMI_MONTH) {
                          //This is a special case that"s hard to generalize
                          //If the date is 1, we round up to 16, otherwise
                          //  we subtract 15 days and add 1 month
                          if (val.get(Calendar.DATE) == 1) {
                              val.add(Calendar.DATE, 15);
                          } else {
                              val.add(Calendar.DATE, -15);
                              val.add(Calendar.MONTH, 1);
                          }
                      } else {
                          //We need at add one to this field since the
                          //  last number causes us to round up
                          val.add(fields[i][0], 1);
                      }
                  }
                  return;
              }
          }
          //We have various fields that are not easy roundings
          int offset = 0;
          boolean offsetSet = false;
          //These are special types of fields that require different rounding rules
          switch (field) {
              case DateUtils.SEMI_MONTH:
                  if (fields[i][0] == Calendar.DATE) {
                      //If we"re going to drop the DATE field"s value,
                      //  we want to do this our own way.
                      //We need to subtrace 1 since the date has a minimum of 1
                      offset = val.get(Calendar.DATE) - 1;
                      //If we"re above 15 days adjustment, that means we"re in the
                      //  bottom half of the month and should stay accordingly.
                      if (offset >= 15) {
                          offset -= 15;
                      }
                      //Record whether we"re in the top or bottom half of that range
                      roundUp = offset > 7;
                      offsetSet = true;
                  }
                  break;
              case Calendar.AM_PM:
                  if (fields[i][0] == Calendar.HOUR_OF_DAY) {
                      //If we"re going to drop the HOUR field"s value,
                      //  we want to do this our own way.
                      offset = val.get(Calendar.HOUR_OF_DAY);
                      if (offset >= 12) {
                          offset -= 12;
                      }
                      roundUp = offset > 6;
                      offsetSet = true;
                  }
                  break;
          }
          if (!offsetSet) {
              int min = val.getActualMinimum(fields[i][0]);
              int max = val.getActualMaximum(fields[i][0]);
              //Calculate the offset from the minimum allowed value
              offset = val.get(fields[i][0]) - min;
              //Set roundUp if this is more than half way between the minimum and maximum
              roundUp = offset > ((max - min) / 2);
          }
          //We need to remove this field
          if (offset != 0) {
              val.set(fields[i][0], val.get(fields[i][0]) - offset);
          }
      }
      throw new IllegalArgumentException("The field " + field + " is not supported");
  }
}





Truncate this date, leaving the field specified as the most significant field.

  
import java.util.Calendar;
import java.util.Date;
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */


/**
 * <p>A suite of utilities surrounding the use of the
 * {@link java.util.Calendar} and {@link java.util.Date} object.</p>
 * 
 * <p>DateUtils contains a lot of common methods considering manipulations
 * of Dates or Calendars. Some methods require some extra explanation.
 * The truncate and round methods could be considered the Math.floor(),
 * Math.ceil() or Math.round versions for dates
 * This way date-fields will be ignored in bottom-up order.
 * As a complement to these methods we"ve introduced some fragment-methods.
 * With these methods the Date-fields will be ignored in top-down order.
 * Since a date without a year is not a valid date, you have to decide in what
 * kind of date-field you want your result, for instance milliseconds or days.
 * </p>
 *   
 *   
 *
 * @author 
 * @author Phil Steitz
 * @author Robert Scholte
 * @since 2.0
 * @version $Id: DateUtils.java 634096 2008-03-06 00:58:11Z niallp $
 */
public class Main {
  private static final int[][] fields = {
    {Calendar.MILLISECOND},
    {Calendar.SECOND},
    {Calendar.MINUTE},
    {Calendar.HOUR_OF_DAY, Calendar.HOUR},
    {Calendar.DATE, Calendar.DAY_OF_MONTH, Calendar.AM_PM 
        /* Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK, Calendar.DAY_OF_WEEK_IN_MONTH */
    },
    {Calendar.MONTH, DateUtils.SEMI_MONTH},
    {Calendar.YEAR},
    {Calendar.ERA}};

  //-----------------------------------------------------------------------
  /**
   * <p>Truncate this date, leaving the field specified as the most
   * significant field.</p>
   *
   * <p>For example, if you had the datetime of 28 Mar 2002
   * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
   * 2002 13:00:00.000.  If this was passed with MONTH, it would
   * return 1 Mar 2002 0:00:00.000.</p>
   * 
   * @param date  the date to work with
   * @param field  the field from <code>Calendar</code>
   *  or <code>SEMI_MONTH</code>
   * @return the rounded date
   * @throws IllegalArgumentException if the date is <code>null</code>
   * @throws ArithmeticException if the year is over 280 million
   */
  public static Date truncate(Date date, int field) {
      if (date == null) {
          throw new IllegalArgumentException("The date must not be null");
      }
      Calendar gval = Calendar.getInstance();
      gval.setTime(date);
      modify(gval, field, false);
      return gval.getTime();
  }
  //-----------------------------------------------------------------------
  /**
   * <p>Internal calculation method.</p>
   * 
   * @param val  the calendar
   * @param field  the field constant
   * @param round  true to round, false to truncate
   * @throws ArithmeticException if the year is over 280 million
   */
  private static void modify(Calendar val, int field, boolean round) {
      if (val.get(Calendar.YEAR) > 280000000) {
          throw new ArithmeticException("Calendar value too large for accurate calculations");
      }
      
      if (field == Calendar.MILLISECOND) {
          return;
      }
      // ----------------- Fix for LANG-59 ---------------------- START ---------------
      // see http://issues.apache.org/jira/browse/LANG-59
      //
      // Manually truncate milliseconds, seconds and minutes, rather than using
      // Calendar methods.
      Date date = val.getTime();
      long time = date.getTime();
      boolean done = false;
      // truncate milliseconds
      int millisecs = val.get(Calendar.MILLISECOND);
      if (!round || millisecs < 500) {
          time = time - millisecs;
      }
      if (field == Calendar.SECOND) {
          done = true;
      }
      // truncate seconds
      int seconds = val.get(Calendar.SECOND);
      if (!done && (!round || seconds < 30)) {
          time = time - (seconds * 1000L);
      }
      if (field == Calendar.MINUTE) {
          done = true;
      }
      // truncate minutes
      int minutes = val.get(Calendar.MINUTE);
      if (!done && (!round || minutes < 30)) {
          time = time - (minutes * 60000L);
      }
      // reset time
      if (date.getTime() != time) {
          date.setTime(time);
          val.setTime(date);
      }
      // ----------------- Fix for LANG-59 ----------------------- END ----------------
      boolean roundUp = false;
      for (int i = 0; i < fields.length; i++) {
          for (int j = 0; j < fields[i].length; j++) {
              if (fields[i][j] == field) {
                  //This is our field... we stop looping
                  if (round && roundUp) {
                      if (field == DateUtils.SEMI_MONTH) {
                          //This is a special case that"s hard to generalize
                          //If the date is 1, we round up to 16, otherwise
                          //  we subtract 15 days and add 1 month
                          if (val.get(Calendar.DATE) == 1) {
                              val.add(Calendar.DATE, 15);
                          } else {
                              val.add(Calendar.DATE, -15);
                              val.add(Calendar.MONTH, 1);
                          }
                      } else {
                          //We need at add one to this field since the
                          //  last number causes us to round up
                          val.add(fields[i][0], 1);
                      }
                  }
                  return;
              }
          }
          //We have various fields that are not easy roundings
          int offset = 0;
          boolean offsetSet = false;
          //These are special types of fields that require different rounding rules
          switch (field) {
              case DateUtils.SEMI_MONTH:
                  if (fields[i][0] == Calendar.DATE) {
                      //If we"re going to drop the DATE field"s value,
                      //  we want to do this our own way.
                      //We need to subtrace 1 since the date has a minimum of 1
                      offset = val.get(Calendar.DATE) - 1;
                      //If we"re above 15 days adjustment, that means we"re in the
                      //  bottom half of the month and should stay accordingly.
                      if (offset >= 15) {
                          offset -= 15;
                      }
                      //Record whether we"re in the top or bottom half of that range
                      roundUp = offset > 7;
                      offsetSet = true;
                  }
                  break;
              case Calendar.AM_PM:
                  if (fields[i][0] == Calendar.HOUR_OF_DAY) {
                      //If we"re going to drop the HOUR field"s value,
                      //  we want to do this our own way.
                      offset = val.get(Calendar.HOUR_OF_DAY);
                      if (offset >= 12) {
                          offset -= 12;
                      }
                      roundUp = offset > 6;
                      offsetSet = true;
                  }
                  break;
          }
          if (!offsetSet) {
              int min = val.getActualMinimum(fields[i][0]);
              int max = val.getActualMaximum(fields[i][0]);
              //Calculate the offset from the minimum allowed value
              offset = val.get(fields[i][0]) - min;
              //Set roundUp if this is more than half way between the minimum and maximum
              roundUp = offset > ((max - min) / 2);
          }
          //We need to remove this field
          if (offset != 0) {
              val.set(fields[i][0], val.get(fields[i][0]) - offset);
          }
      }
      throw new IllegalArgumentException("The field " + field + " is not supported");
  }
}