home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1997 May / Pcwk0597.iso / sybase / starbuck / java.z / Date.java < prev    next >
Text File  |  1996-05-03  |  17KB  |  612 lines

  1. /*
  2.  * @(#)Date.java    1.21 95/11/21 James Gosling, Arthur van Hoff
  3.  * 
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for NON-COMMERCIAL purposes and without fee is hereby
  8.  * granted provided that this copyright notice appears in all copies. Please
  9.  * refer to the file "copyright.html" for further important copyright and
  10.  * licensing information.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
  15.  * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
  16.  * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
  17.  * ITS DERIVATIVES.
  18.  */
  19.  
  20. package java.util;
  21.  
  22.  
  23. /**
  24.  * A wrapper for a date. This class lets you manipulate
  25.  * dates in a system independent way. To print today's
  26.  * date use:
  27.  * <pre>
  28.  *    Date d = new Date();
  29.  *    System.out.println("today = " + d);
  30.  * </pre>
  31.  * To find out what day corresponds to a particular date:
  32.  * <pre>
  33.  *    Date d = new Date(63, 0, 16);    // January 16, 1963
  34.  *    System.out.println("Day of the week: " + d.getDay());
  35.  * </pre>
  36.  * The date can be set and examined
  37.  * according to the local time zone into the
  38.  * year, month, day, hour, minute and second.
  39.  * <p>
  40.  * While the API is intended to reflect UTC, Coordinated Universal Time,
  41.  * it doesn't do so exactly.  This inexact behavior is inherited from
  42.  * the time system of the underlying OS.  All modern OS's that I (jag)
  43.  * am aware of assume that 1 day = 24*60*60 seconds.  In UTC, about once
  44.  * a year there is an extra second, called a "leap second" added to
  45.  * a day to account for the wobble of the earth.  Most computer clocks
  46.  * are not accurate enough to be able to reflect this distinction.
  47.  * Some computer standards are defined in GMT, which is equivalent
  48.  * to UT, Universal Time.  GMT is the "civil" name for the standard,
  49.  * UT is the "scientific" name for the same standard.  The distinction
  50.  * between UTC and UT is that the first is based on an atomic clock and
  51.  * the second is based on astronomical observations, which for all
  52.  * practical purposes is an invisibly fine hair to split.
  53.  * An interesting source of further information is the
  54.  * US Naval Observatory, particularly the
  55.  * <a href=http://tycho.usno.navy.mil>Directorate of Time</a>
  56.  * and their definitions of
  57.  * <a href=http://tycho.usno.navy.mil/systime.html>Systems of Time</a>.
  58.  *
  59.  * @version     1.14, 28 Jul 1995
  60.  * @author    James Gosling
  61.  * @author    Arthur van Hoff
  62.  */
  63. public
  64. class Date {
  65.     private long value;
  66.     private boolean valueValid;
  67.     private boolean expanded;
  68.  
  69.     private short tm_millis;    /* miliseconds within the second - [0,999] */
  70.     private byte tm_sec;    /* seconds after the minute - [0, 61] for
  71.                  * leap seconds */
  72.     private byte tm_min;    /* minutes after the hour - [0, 59] */
  73.     private byte tm_hour;    /* hour since midnight - [0, 23] */
  74.     private byte tm_mday;    /* day of the month - [1, 31] */
  75.     private byte tm_mon;    /* months since January - [0, 11] */
  76.     private byte tm_wday;    /* days since Sunday - [0, 6] */
  77.     private short tm_yday;    /* days since January 1 - [0, 365] */
  78.     private int tm_year;    /* years since 1900 */
  79.     private int tm_isdst;    /* flag for alternate daylight savings time */
  80.  
  81.     /**
  82.      * Creates today's date/time.
  83.      */
  84.     public Date () {
  85.     this(System.currentTimeMillis());
  86.     }
  87.  
  88.     /**
  89.      * Creates a date.
  90.      * The fields are normalized before the Date object is created.
  91.      * The argument does not have to be in the correct range. For
  92.      * example, the 32nd of January is correctly interpreted as the
  93.      * 1st of February.  You can use this to figure out what day a
  94.      * particular date falls on.
  95.      * @param date the value of the argument to be created
  96.      */
  97.     public Date (long date) {
  98.     value = date;
  99.     valueValid = true;
  100.     expanded = false;
  101.     }
  102.  
  103.     /**
  104.      * Creates a date.
  105.      * The fields are normalized before the Date object is created.
  106.      * The arguments do not have to be in the correct range. For example,
  107.      * the 32nd of January is correctly interpreted as the 1st of February.
  108.      * You can use this to figure out what day a particular date falls on.
  109.      * @param year    a year after 1900
  110.      * @param month    a month between 0-11
  111.      * @param date    day of the month between 1-31
  112.      */
  113.     public Date (int year, int month, int date) {
  114.     this(year, month, date, 0, 0, 0);
  115.     }
  116.  
  117.     /**
  118.      * Creates a date.
  119.      * The fields are normalized before the Date object is created.
  120.      * The arguments do not have to be in the correct range. For example,
  121.      * the 32nd of January is correctly interpreted as the 1st of February.
  122.      * You can use this to figure out what day a particular date falls on.
  123.      * @param year    a year after 1900
  124.      * @param month    a month between 0-11
  125.      * @param date    day of the month between 1-31
  126.      * @param hrs    hours between 0-23
  127.      * @param min    minutes between 0-59
  128.      */
  129.     public Date (int year, int month, int date, int hrs, int min) {
  130.     this(year, month, date, hrs, min, 0);
  131.     }
  132.  
  133.     /**
  134.      * Creates a date. The fields are normalized before the Date object is
  135.      * created. The arguments do not have to be in the correct range. For
  136.      * example, the 32nd of January is correctly interpreted as the 1st of
  137.      * February. You can use this to figure out what day a particular date
  138.      * falls on.
  139.      * @param year    a year after 1900
  140.      * @param month    a month between 0-11
  141.      * @param date    day of the month between 1-31
  142.      * @param hrs    hours between 0-23
  143.      * @param min    minutes between 0-59
  144.      * @param sec    seconds between 0-59
  145.      */
  146.     public Date (int year, int month, int date, int hrs, int min, int sec) {
  147.     expanded = true;
  148.     valueValid = false;
  149.     tm_millis = 0;
  150.     tm_sec = (byte) sec;
  151.     tm_min = (byte) min;
  152.     tm_hour = (byte) hrs;
  153.     tm_mday = (byte) date;
  154.     tm_mon = (byte) month;
  155.     tm_wday = 0;
  156.     tm_yday = 0;
  157.     tm_year = year;
  158.     computeValue();
  159.     expand();
  160.     }
  161.  
  162.     /**
  163.      * Creates a date from a string according to the syntax
  164.      * accepted by parse().
  165.      */
  166.     public Date (String s) {
  167.     this(parse(s));
  168.     }
  169.  
  170.  
  171.  
  172.     /**
  173.      * Calculates a UTC value from YMDHMS. Interpretes
  174.      * the parameters in UTC, <i>not<i> in the local time zone.
  175.      * @param year    a year after 1900
  176.      * @param month    a month between 0-11
  177.      * @param date    day of the month between 1-31
  178.      * @param hrs    hours between 0-23
  179.      * @param min    minutes between 0-59
  180.      * @param sec    seconds between 0-59
  181.      */
  182.     public static long UTC(int year, int month, int date,
  183.                     int hrs, int min, int sec) {
  184.     long day = (date
  185.             + monthOffset[month]
  186.             + ((year & 3) != 0
  187.                || year % 100 == 0 && (year + 300) % 400 != 0
  188.                || month < 2
  189.                ? -1 : 0)/* convert day-of-month to 0 based range,
  190.                  * except following February in a leap year,
  191.                  * in which case we skip the conversion to
  192.                  * account for the extra day in February */
  193.             + (year - 70) * 365L    // days per year
  194.             + (year - 69) / 4    // plus leap days
  195.             - (year - 1) / 100    // no leap on century years
  196.             + (year + 299) / 400);    // except %400 years
  197.     return (sec + 60 * (min + 60 * hrs)) * 1000 + (60 * 60 * 24 * 1000) * day;
  198.     }
  199.  
  200.     private static short monthOffset[] = {
  201.     0,            // 31    January
  202.     31,            // 28    February
  203.     59,            // 31    March
  204.     90,            // 30    April
  205.     120,            // 31    May
  206.     151,            // 30    June
  207.     181,            // 31    July
  208.     212,            // 31    August
  209.     243,            // 30    September
  210.     273,            // 31    October
  211.     304,            // 30    November
  212.     334            // 31    December
  213.     // 365
  214.     };
  215.  
  216.     /**
  217.      * Given a string representing a time, parse it and return the time value.
  218.      * It accepts many syntaxes, but most importantly, in accepts the IETF
  219.      * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT".  It understands
  220.      * the continental US time zone abbreviations, but for general use, a
  221.      * timezone offset should be used: "Sat, 12 Aug 1995 13:30:00 GMT+0430"
  222.      * (4 hours, 30 minutes west of the Greenwich meridian).
  223.      * If no time zone is specified, the local time zone is assumed.
  224.      * GMT and UTC are considered equivalent.
  225.      */
  226.     public static long parse(String s) {
  227.     int year = -1;
  228.     int mon = -1;
  229.     int mday = -1;
  230.     int hour = -1;
  231.     int min = -1;
  232.     int sec = -1;
  233.     int millis = -1;
  234.     int c = -1;
  235.     int i = 0;
  236.     int n = -1;
  237.     int wst = -1;
  238.     int tzoffset = -1;
  239.     int prevc = 0;
  240. syntax:
  241.     {
  242.         if (s == null)
  243.         break syntax;
  244.         int limit = s.length();
  245.         while (i < limit) {
  246.         c = s.charAt(i);
  247.         i++;
  248.         if (c <= ' ' || c == ',' || c == '-')
  249.             continue;
  250.         if (c == '(') {    // skip comments
  251.             int depth = 1;
  252.             while (i < limit) {
  253.             c = s.charAt(i);
  254.             i++;
  255.             if (c == '(') depth++;
  256.             else if (c == ')')
  257.                 if (--depth <= 0)
  258.                     break;
  259.             }
  260.             continue;
  261.         }
  262.         if ('0' <= c && c <= '9') {
  263.             n = c - '0';
  264.             while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
  265.             n = n * 10 + c - '0';
  266.             i++;
  267.             }
  268.             if (prevc == '+' || prevc == '-' && year>=0) {
  269.             // timezone offset
  270.             if (n < 24)
  271.                 n = n * 60;    // EG. "GMT-3"
  272.             else
  273.                 n = n % 100 + n / 100 * 60;    // eg "GMT-0430"
  274.             if (prevc == '+')    // plus means east of GMT
  275.                 n = -n;
  276.             if (tzoffset != 0 && tzoffset != -1)
  277.                 break syntax;
  278.             tzoffset = n;
  279.             } else if (n >= 70)
  280.             if (year >= 0)
  281.                 break syntax;
  282.             else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
  283.                 year = n < 1900 ? n : n - 1900;
  284.             else
  285.                 break syntax;
  286.             else if (c == ':')
  287.             if (hour < 0)
  288.                 hour = (byte) n;
  289.             else if (min < 0)
  290.                 min = (byte) n;
  291.             else
  292.                 break syntax;
  293.             else if (c == '/')
  294.             if (mon < 0)
  295.                 mon = (byte) n;
  296.             else if (mday < 0)
  297.                 mday = (byte) n;
  298.             else
  299.                 break syntax;
  300.             else if (i < limit && c != ',' && c > ' ' && c != '-')
  301.             break syntax;
  302.             else if (hour >= 0 && min < 0)
  303.             min = (byte) n;
  304.             else if (min >= 0 && sec < 0)
  305.             sec = (byte) n;
  306.             else if (mday < 0)
  307.             mday = (byte) n;
  308.             else
  309.             break syntax;
  310.             prevc = 0;
  311.         } else if (c == '/' || c == ':' || c == '+' || c == '-')
  312.             prevc = c;
  313.         else {
  314.             int st = i - 1;
  315.             while (i < limit) {
  316.             c = s.charAt(i);
  317.             if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
  318.                 break;
  319.             i++;
  320.             }
  321.             if (i <= st + 1)
  322.             break syntax;
  323.             int k;
  324.             for (k = wtb.length; --k >= 0;)
  325.             if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
  326.                 int action = ttb[k];
  327.                 if (action != 0)
  328.                 if (action == 1)    // pm
  329.                     if (hour > 12 || hour < 0)
  330.                     break syntax;
  331.                     else
  332.                     hour += 12;
  333.                 else if (action <= 13)    // month!
  334.                     if (mon < 0)
  335.                     mon = (byte) (action - 2);
  336.                     else
  337.                     break syntax;
  338.                 else
  339.                     tzoffset = action - 10000;
  340.                 break;
  341.             }
  342.             if (k < 0)
  343.             break syntax;
  344.             prevc = 0;
  345.         }
  346.         }
  347.         if (year < 0 || mon < 0 || mday < 0)
  348.         break syntax;
  349.         if (sec < 0)
  350.         sec = 0;
  351.         if (min < 0)
  352.         min = 0;
  353.         if (hour < 0)
  354.         hour = 0;
  355.         if (tzoffset == -1)    // no time zone specified, have to use local
  356.         return new Date (year, mon, mday, hour, min, sec).getTime();
  357.         return UTC(year, mon, mday, hour, min, sec) + tzoffset * (60 * 1000);
  358.     }
  359.     // syntax error
  360.     throw new IllegalArgumentException();
  361.     }
  362.     private final static String wtb[] = {
  363.     "am", "pm",
  364.     "monday", "tuesday", "wednesday", "thursday", "friday",
  365.     "saturday", "sunday",
  366.     "january", "february", "march", "april", "may", "june",
  367.     "july", "august", "september", "october", "november", "december",
  368.     "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
  369.     "mst", "mdt", "pst", "pdt"
  370.     // this time zone table needs to be expanded
  371.     };
  372.     private final static int ttb[] = {
  373.     0, 1, 0, 0, 0, 0, 0, 0, 0,
  374.     2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
  375.     10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
  376.     10000 + 5 * 60, 10000 + 4 * 60,    // EST/EDT
  377.     10000 + 6 * 60, 10000 + 5 * 60,
  378.     10000 + 7 * 60, 10000 + 6 * 60,
  379.     10000 + 8 * 60, 10000 + 7 * 60
  380.     };
  381.  
  382.     /**
  383.      * Returns the year after 1900.
  384.      */
  385.     public int getYear() {
  386.     if (!expanded)
  387.         expand();
  388.     return tm_year;
  389.     }
  390.  
  391.     /**
  392.      * Sets the year.
  393.      * @param year the year value
  394.      */
  395.     public void setYear(int year) {
  396.     if (!expanded)
  397.         expand();
  398.     tm_year = year;
  399.     valueValid = false;
  400.     }
  401.  
  402.     /**
  403.      * Returns the month. This method assigns months with the
  404.      * values 0-11, with January beginning at value 0.
  405.      */
  406.     public int getMonth() {
  407.     if (!expanded)
  408.         expand();
  409.     return tm_mon;
  410.     }
  411.  
  412.     /**
  413.      * Sets the month.
  414.      * @param month the month value (0-11)
  415.      */
  416.     public void setMonth(int month) {
  417.     if (!expanded)
  418.         expand();
  419.     tm_mon = (byte) month;
  420.     valueValid = false;
  421.     }
  422.  
  423.     /**
  424.      * Returns the day of the month. This method assigns days
  425.      * with the values of 1 to 31.
  426.      */
  427.     public int getDate() {
  428.     if (!expanded)
  429.         expand();
  430.     return tm_mday;
  431.     }
  432.  
  433.     /**
  434.      * Sets the date.
  435.      * @param date the day value
  436.      */
  437.     public void setDate(int date) {
  438.     if (!expanded)
  439.         expand();
  440.     tm_mday = (byte) date;
  441.     valueValid = false;
  442.     }
  443.  
  444.     /**
  445.      * Returns the day of the week. This method assigns days
  446.      * of the week with the values 0-6, with 0 being Sunday.
  447.      */
  448.     public int getDay() {
  449.     if (!expanded) {
  450.         expand();
  451.     } else if ((tm_wday < 0) || !valueValid) {
  452.         computeValue();
  453.         expand();
  454.     }
  455.     return tm_wday;
  456.     }
  457.  
  458.     /**
  459.      * Returns the hour. This method assigns the value of the
  460.      * hours of the day to range from 0 to 23, with midnight equal
  461.      * to 0.
  462.      */
  463.     public int getHours() {
  464.     if (!expanded)
  465.         expand();
  466.     return tm_hour;
  467.     }
  468.  
  469.     /**
  470.      * Sets the hours.
  471.      * @param hours the hour value
  472.      */
  473.     public void setHours(int hours) {
  474.     if (!expanded)
  475.         expand();
  476.     tm_hour = (byte) hours;
  477.     valueValid = false;
  478.     }
  479.  
  480.     /**
  481.      * Returns the minute. This method assigns the minutes of an
  482.      * hour to be any value from 0 to 59.
  483.      */
  484.     public int getMinutes() {
  485.     if (!expanded)
  486.         expand();
  487.     return tm_min;
  488.     }
  489.  
  490.     /**
  491.      * Sets the minutes.
  492.      * @param minutes the value of the minutes
  493.      */
  494.     public void setMinutes(int minutes) {
  495.     if (!expanded)
  496.         expand();
  497.     tm_min = (byte) minutes;
  498.     valueValid = false;
  499.     }
  500.  
  501.     /**
  502.      * Returns the second. This method assigns the seconds of
  503.      * a minute to values of 0-59.
  504.      */
  505.     public int getSeconds() {
  506.     if (!expanded)
  507.         expand();
  508.     return tm_sec;
  509.     }
  510.  
  511.     /**
  512.      * Sets the seconds.
  513.      * @param seconds the second value
  514.      */
  515.     public void setSeconds(int seconds) {
  516.     if (!expanded)
  517.         expand();
  518.     tm_sec = (byte) seconds;
  519.     valueValid = false;
  520.     }
  521.  
  522.     /**
  523.      * Returns the time in milliseconds since the epoch.
  524.      */
  525.     public long getTime() {
  526.     if (!valueValid)
  527.         computeValue();
  528.     return value;
  529.     }
  530.  
  531.     /**
  532.      * Sets the time.
  533.      * @param time    The new time value in milliseconds since the epoch.
  534.      */
  535.     public void setTime(long time) {
  536.     value = time;
  537.     valueValid = true;
  538.     expanded = false;
  539.     }
  540.  
  541.     /**
  542.      * Checks whether this date comes before the specified date.
  543.      * @param when the date to compare
  544.      * @return true if the original date comes before the specified
  545.      * one; false otherwise.
  546.      */
  547.     public boolean before(Date when) {
  548.     return getTime() < when.getTime();
  549.     }
  550.  
  551.     /**
  552.      * Checks whether this date comes after the specified date.
  553.      * @param when the date to compare
  554.      * @return true if the original date comes after the specified
  555.      * one; false otherwise.
  556.      */
  557.     public boolean after(Date when) {
  558.     return getTime() > when.getTime();
  559.     }
  560.  
  561.     /**
  562.      * Compares this object against the specified object.
  563.      * @param obj the object to compare with
  564.      * @return true if the objects are the same; false otherwise.
  565.      */
  566.     public boolean equals(Object obj) {
  567.     return obj != null && obj instanceof Date &&getTime() == ((Date) obj).getTime();
  568.     }
  569.  
  570.     /**
  571.      * Computes a hashCode.
  572.      */
  573.     public int hashCode() {
  574.     long ht = getTime();
  575.     return (int) ht ^ (int) (ht >> 32);
  576.     }
  577.  
  578.     /**
  579.      * Converts a date to a String, using the UNIX ctime conventions.
  580.      */
  581.     public native String toString();
  582.  
  583.     /**
  584.      * Converts a date to a String, using the locale conventions.
  585.      */
  586.     public native String toLocaleString();
  587.  
  588.     /**
  589.      * Converts a date to a String, using the Internet GMT conventions.
  590.      */
  591.     public native String toGMTString();
  592.  
  593.     /**
  594.      * Return the time zone offset in minutes for the current locale that is appropriate
  595.      * for this time.  This value would be a constant except for
  596.      * daylight savings time.
  597.      */
  598.     public int getTimezoneOffset() {
  599.     if (!expanded)
  600.         expand();
  601.     return (int) ((getTime() - UTC(tm_year, tm_mon, tm_mday,
  602.                    tm_hour, tm_min, tm_sec)) / (60 * 1000));
  603.     }
  604.  
  605.     /*
  606.      * Gets date values.
  607.      */
  608.     private native void expand();
  609.     private native void computeValue();
  610.  
  611. }
  612.