/* * Copyright (c) 1993-1996 Sun Microsystems, Inc. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and without * fee is hereby granted provided that this copyright notice * appears in all copies. Please refer to the file "copyright.html" * for further important copyright and licensing information. * * The Java source code is the confidential and proprietary information * of Sun Microsystems, Inc. ("Confidential Information"). You shall * not disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ /* * @(#)Date.java 1.21 95/11/21 James Gosling, Arthur van Hoff * */ package java.util; /** * A wrapper for a date. This class lets you manipulate * dates in a system independent way. To print today's * date use: *
* Date d = new Date();
* System.out.println("today = " + d);
*
* To find out what day corresponds to a particular date:
*
* Date d = new Date(63, 0, 16); // January 16, 1963
* System.out.println("Day of the week: " + d.getDay());
*
* The date can be set and examined
* according to the local time zone into the
* year, month, day, hour, minute and second.
* * While the API is intended to reflect UTC, Coordinated Universal Time, * it doesn't do so exactly. This inexact behavior is inherited from * the time system of the underlying OS. All modern OS's that I (jag) * am aware of assume that 1 day = 24*60*60 seconds. In UTC, about once * a year there is an extra second, called a "leap second" added to * a day to account for the wobble of the earth. Most computer clocks * are not accurate enough to be able to reflect this distinction. * Some computer standards are defined in GMT, which is equivalent * to UT, Universal Time. GMT is the "civil" name for the standard, * UT is the "scientific" name for the same standard. The distinction * between UTC and UT is that the first is based on an atomic clock and * the second is based on astronomical observations, which for all * practical purposes is an invisibly fine hair to split. * An interesting source of further information is the * US Naval Observatory, particularly the * Directorate of Time * and their definitions of * Systems of Time. * * @version 1.14, 28 Jul 1995 * @author James Gosling * @author Arthur van Hoff */ public class Date { private long value; private boolean valueValid; private boolean expanded; private short tm_millis; /* miliseconds within the second - [0,999] */ private byte tm_sec; /* seconds after the minute - [0, 61] for * leap seconds */ private byte tm_min; /* minutes after the hour - [0, 59] */ private byte tm_hour; /* hour since midnight - [0, 23] */ private byte tm_mday; /* day of the month - [1, 31] */ private byte tm_mon; /* months since January - [0, 11] */ private byte tm_wday; /* days since Sunday - [0, 6] */ private short tm_yday; /* days since January 1 - [0, 365] */ private int tm_year; /* years since 1900 */ private int tm_isdst; /* flag for alternate daylight savings time */ /** * Creates today's date/time. */ public Date () { this(System.currentTimeMillis()); } /** * Creates a date. * The fields are normalized before the Date object is created. * The argument does not have to be in the correct range. For * example, the 32nd of January is correctly interpreted as the * 1st of February. You can use this to figure out what day a * particular date falls on. * @param date the value of the argument to be created */ public Date (long date) { value = date; valueValid = true; expanded = false; } /** * Creates a date. * The fields are normalized before the Date object is created. * The arguments do not have to be in the correct range. For example, * the 32nd of January is correctly interpreted as the 1st of February. * You can use this to figure out what day a particular date falls on. * @param year a year after 1900 * @param month a month between 0-11 * @param date day of the month between 1-31 */ public Date (int year, int month, int date) { this(year, month, date, 0, 0, 0); } /** * Creates a date. * The fields are normalized before the Date object is created. * The arguments do not have to be in the correct range. For example, * the 32nd of January is correctly interpreted as the 1st of February. * You can use this to figure out what day a particular date falls on. * @param year a year after 1900 * @param month a month between 0-11 * @param date day of the month between 1-31 * @param hrs hours between 0-23 * @param min minutes between 0-59 */ public Date (int year, int month, int date, int hrs, int min) { this(year, month, date, hrs, min, 0); } /** * Creates a date. The fields are normalized before the Date object is * created. The arguments do not have to be in the correct range. For * example, the 32nd of January is correctly interpreted as the 1st of * February. You can use this to figure out what day a particular date * falls on. * @param year a year after 1900 * @param month a month between 0-11 * @param date day of the month between 1-31 * @param hrs hours between 0-23 * @param min minutes between 0-59 * @param sec seconds between 0-59 */ public Date (int year, int month, int date, int hrs, int min, int sec) { expanded = true; valueValid = false; tm_millis = 0; tm_sec = (byte) sec; tm_min = (byte) min; tm_hour = (byte) hrs; tm_mday = (byte) date; tm_mon = (byte) month; tm_wday = 0; tm_yday = 0; tm_year = year; computeValue(); expand(); } /** * Creates a date from a string according to the syntax * accepted by parse(). */ public Date (String s) { this(parse(s)); } /** * Calculates a UTC value from YMDHMS. Interpretes * the parameters in UTC, not in the local time zone. * @param year a year after 1900 * @param month a month between 0-11 * @param date day of the month between 1-31 * @param hrs hours between 0-23 * @param min minutes between 0-59 * @param sec seconds between 0-59 */ public static long UTC(int year, int month, int date, int hrs, int min, int sec) { long day = (date + monthOffset[month] + ((year & 3) != 0 || year % 100 == 0 && (year + 300) % 400 != 0 || month < 2 ? -1 : 0)/* convert day-of-month to 0 based range, * except following February in a leap year, * in which case we skip the conversion to * account for the extra day in February */ + (year - 70) * 365L // days per year + (year - 69) / 4 // plus leap days - (year - 1) / 100 // no leap on century years + (year + 299) / 400); // except %400 years return (sec + 60 * (min + 60 * hrs)) * 1000 + (60 * 60 * 24 * 1000) * day; } private static short monthOffset[] = { 0, // 31 January 31, // 28 February 59, // 31 March 90, // 30 April 120, // 31 May 151, // 30 June 181, // 31 July 212, // 31 August 243, // 30 September 273, // 31 October 304, // 30 November 334 // 31 December // 365 }; /** * Given a string representing a time, parse it and return the time value. * It accepts many syntaxes, but most importantly, in accepts the IETF * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It understands * the continental US time zone abbreviations, but for general use, a * timezone offset should be used: "Sat, 12 Aug 1995 13:30:00 GMT+0430" * (4 hours, 30 minutes west of the Greenwich meridian). * If no time zone is specified, the local time zone is assumed. * GMT and UTC are considered equivalent. */ public static long parse(String s) { int year = -1; int mon = -1; int mday = -1; int hour = -1; int min = -1; int sec = -1; int millis = -1; int c = -1; int i = 0; int n = -1; int wst = -1; int tzoffset = -1; int prevc = 0; syntax: { if (s == null) break syntax; int limit = s.length(); while (i < limit) { c = s.charAt(i); i++; if (c <= ' ' || c == ',' || c == '-') continue; if (c == '(') { // skip comments int depth = 1; while (i < limit) { c = s.charAt(i); i++; if (c == '(') depth++; else if (c == ')') if (--depth <= 0) break; } continue; } if ('0' <= c && c <= '9') { n = c - '0'; while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') { n = n * 10 + c - '0'; i++; } if (prevc == '+' || prevc == '-' && year>=0) { // timezone offset if (n < 24) n = n * 60; // EG. "GMT-3" else n = n % 100 + n / 100 * 60; // eg "GMT-0430" if (prevc == '+') // plus means east of GMT n = -n; if (tzoffset != 0 && tzoffset != -1) break syntax; tzoffset = n; } else if (n >= 70) if (year >= 0) break syntax; else if (c <= ' ' || c == ',' || c == '/' || i >= limit) year = n < 1900 ? n : n - 1900; else break syntax; else if (c == ':') if (hour < 0) hour = (byte) n; else if (min < 0) min = (byte) n; else break syntax; else if (c == '/') if (mon < 0) mon = (byte) n; else if (mday < 0) mday = (byte) n; else break syntax; else if (i < limit && c != ',' && c > ' ' && c != '-') break syntax; else if (hour >= 0 && min < 0) min = (byte) n; else if (min >= 0 && sec < 0) sec = (byte) n; else if (mday < 0) mday = (byte) n; else break syntax; prevc = 0; } else if (c == '/' || c == ':' || c == '+' || c == '-') prevc = c; else { int st = i - 1; while (i < limit) { c = s.charAt(i); if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z')) break; i++; } if (i <= st + 1) break syntax; int k; for (k = wtb.length; --k >= 0;) if (wtb[k].regionMatches(true, 0, s, st, i - st)) { int action = ttb[k]; if (action != 0) if (action == 1) // pm if (hour > 12 || hour < 0) break syntax; else hour += 12; else if (action <= 13) // month! if (mon < 0) mon = (byte) (action - 2); else break syntax; else tzoffset = action - 10000; break; } if (k < 0) break syntax; prevc = 0; } } if (year < 0 || mon < 0 || mday < 0) break syntax; if (sec < 0) sec = 0; if (min < 0) min = 0; if (hour < 0) hour = 0; if (tzoffset == -1) // no time zone specified, have to use local return new Date (year, mon, mday, hour, min, sec).getTime(); return UTC(year, mon, mday, hour, min, sec) + tzoffset * (60 * 1000); } // syntax error throw new IllegalArgumentException(); } private final static String wtb[] = { "am", "pm", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december", "gmt", "ut", "utc", "est", "edt", "cst", "cdt", "mst", "mdt", "pst", "pdt" // this time zone table needs to be expanded }; private final static int ttb[] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 10000 + 0, 10000 + 0, 10000 + 0, // GMT/UT/UTC 10000 + 5 * 60, 10000 + 4 * 60, // EST/EDT 10000 + 6 * 60, 10000 + 5 * 60, 10000 + 7 * 60, 10000 + 6 * 60, 10000 + 8 * 60, 10000 + 7 * 60 }; /** * Returns the year after 1900. */ public int getYear() { if (!expanded) expand(); return tm_year; } /** * Sets the year. * @param year the year value */ public void setYear(int year) { if (!expanded) expand(); tm_year = year; valueValid = false; } /** * Returns the month. This method assigns months with the * values 0-11, with January beginning at value 0. */ public int getMonth() { if (!expanded) expand(); return tm_mon; } /** * Sets the month. * @param month the month value (0-11) */ public void setMonth(int month) { if (!expanded) expand(); tm_mon = (byte) month; valueValid = false; } /** * Returns the day of the month. This method assigns days * with the values of 1 to 31. */ public int getDate() { if (!expanded) expand(); return tm_mday; } /** * Sets the date. * @param date the day value */ public void setDate(int date) { if (!expanded) expand(); tm_mday = (byte) date; valueValid = false; } /** * Returns the day of the week. This method assigns days * of the week with the values 0-6, with 0 being Sunday. */ public int getDay() { if (!expanded) { expand(); } else if ((tm_wday < 0) || !valueValid) { computeValue(); expand(); } return tm_wday; } /** * Returns the hour. This method assigns the value of the * hours of the day to range from 0 to 23, with midnight equal * to 0. */ public int getHours() { if (!expanded) expand(); return tm_hour; } /** * Sets the hours. * @param hours the hour value */ public void setHours(int hours) { if (!expanded) expand(); tm_hour = (byte) hours; valueValid = false; } /** * Returns the minute. This method assigns the minutes of an * hour to be any value from 0 to 59. */ public int getMinutes() { if (!expanded) expand(); return tm_min; } /** * Sets the minutes. * @param minutes the value of the minutes */ public void setMinutes(int minutes) { if (!expanded) expand(); tm_min = (byte) minutes; valueValid = false; } /** * Returns the second. This method assigns the seconds of * a minute to values of 0-59. */ public int getSeconds() { if (!expanded) expand(); return tm_sec; } /** * Sets the seconds. * @param seconds the second value */ public void setSeconds(int seconds) { if (!expanded) expand(); tm_sec = (byte) seconds; valueValid = false; } /** * Returns the time in milliseconds since the epoch. */ public long getTime() { if (!valueValid) computeValue(); return value; } /** * Sets the time. * @param time The new time value in milliseconds since the epoch. */ public void setTime(long time) { value = time; valueValid = true; expanded = false; } /** * Checks whether this date comes before the specified date. * @param when the date to compare * @return true if the original date comes before the specified * one; false otherwise. */ public boolean before(Date when) { return getTime() < when.getTime(); } /** * Checks whether this date comes after the specified date. * @param when the date to compare * @return true if the original date comes after the specified * one; false otherwise. */ public boolean after(Date when) { return getTime() > when.getTime(); } /** * Compares this object against the specified object. * @param obj the object to compare with * @return true if the objects are the same; false otherwise. */ public boolean equals(Object obj) { return obj != null && obj instanceof Date &&getTime() == ((Date) obj).getTime(); } /** * Computes a hashCode. */ public int hashCode() { long ht = getTime(); return (int) ht ^ (int) (ht >> 32); } /** * Converts a date to a String, using the UNIX ctime conventions. */ public native String toString(); /** * Converts a date to a String, using the locale conventions. */ public native String toLocaleString(); /** * Converts a date to a String, using the Internet GMT conventions. */ public native String toGMTString(); /** * Return the time zone offset in minutes for the current locale that is appropriate * for this time. This value would be a constant except for * daylight savings time. */ public int getTimezoneOffset() { if (!expanded) expand(); return (int) ((getTime() - UTC(tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec)) / (60 * 1000)); } /* * Gets date values. */ private native void expand(); private native void computeValue(); }