1   /*
2    * %W% %E%
3    *
4    * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
5    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6    */
7   
8   package java.util;
9   
10  import java.text.DateFormat;
11  import java.io.IOException;
12  import java.io.ObjectOutputStream;
13  import java.io.ObjectInputStream;
14  import java.lang.ref.SoftReference;
15  import sun.util.calendar.BaseCalendar;
16  import sun.util.calendar.CalendarDate;
17  import sun.util.calendar.CalendarSystem;
18  import sun.util.calendar.CalendarUtils;
19  import sun.util.calendar.Era;
20  import sun.util.calendar.Gregorian;
21  import sun.util.calendar.ZoneInfo;
22  
23  /**
24   * The class <code>Date</code> represents a specific instant
25   * in time, with millisecond precision.
26   * <p>
27   * Prior to JDK&nbsp;1.1, the class <code>Date</code> had two additional
28   * functions.  It allowed the interpretation of dates as year, month, day, hour,
29   * minute, and second values.  It also allowed the formatting and parsing
30   * of date strings.  Unfortunately, the API for these functions was not
31   * amenable to internationalization.  As of JDK&nbsp;1.1, the
32   * <code>Calendar</code> class should be used to convert between dates and time
33   * fields and the <code>DateFormat</code> class should be used to format and
34   * parse date strings.
35   * The corresponding methods in <code>Date</code> are deprecated.
36   * <p>
37   * Although the <code>Date</code> class is intended to reflect 
38   * coordinated universal time (UTC), it may not do so exactly, 
39   * depending on the host environment of the Java Virtual Machine. 
40   * Nearly all modern operating systems assume that 1&nbsp;day&nbsp;=
41   * 24&nbsp;&times;&nbsp;60&nbsp;&times;&nbsp;60&nbsp;= 86400 seconds 
42   * in all cases. In UTC, however, about once every year or two there 
43   * is an extra second, called a "leap second." The leap 
44   * second is always added as the last second of the day, and always 
45   * on December 31 or June 30. For example, the last minute of the 
46   * year 1995 was 61 seconds long, thanks to an added leap second. 
47   * Most computer clocks are not accurate enough to be able to reflect 
48   * the leap-second distinction. 
49   * <p>
50   * Some computer standards are defined in terms of Greenwich mean 
51   * time (GMT), which is equivalent to universal time (UT).  GMT is 
52   * the "civil" name for the standard; UT is the 
53   * "scientific" name for the same standard. The 
54   * distinction between UTC and UT is that UTC is based on an atomic 
55   * clock and UT is based on astronomical observations, which for all 
56   * practical purposes is an invisibly fine hair to split. Because the 
57   * earth's rotation is not uniform (it slows down and speeds up 
58   * in complicated ways), UT does not always flow uniformly. Leap 
59   * seconds are introduced as needed into UTC so as to keep UTC within 
60   * 0.9 seconds of UT1, which is a version of UT with certain 
61   * corrections applied. There are other time and date systems as 
62   * well; for example, the time scale used by the satellite-based 
63   * global positioning system (GPS) is synchronized to UTC but is 
64   * <i>not</i> adjusted for leap seconds. An interesting source of 
65   * further information is the U.S. Naval Observatory, particularly 
66   * the Directorate of Time at:
67   * <blockquote><pre>
68   *     <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
69   * </pre></blockquote>
70   * <p>
71   * and their definitions of "Systems of Time" at:
72   * <blockquote><pre>
73   *     <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
74   * </pre></blockquote>
75   * <p>
76   * In all methods of class <code>Date</code> that accept or return 
77   * year, month, date, hours, minutes, and seconds values, the 
78   * following representations are used: 
79   * <ul>
80   * <li>A year <i>y</i> is represented by the integer 
81   *     <i>y</i>&nbsp;<code>-&nbsp;1900</code>. 
82   * <li>A month is represented by an integer from 0 to 11; 0 is January, 
83   *     1 is February, and so forth; thus 11 is December. 
84   * <li>A date (day of month) is represented by an integer from 1 to 31 
85   *     in the usual manner. 
86   * <li>An hour is represented by an integer from 0 to 23. Thus, the hour 
87   *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1 
88   *     p.m. is hour 12. 
89   * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
90   * <li>A second is represented by an integer from 0 to 61; the values 60 and 
91   *     61 occur only for leap seconds and even then only in Java 
92   *     implementations that actually track leap seconds correctly. Because 
93   *     of the manner in which leap seconds are currently introduced, it is 
94   *     extremely unlikely that two leap seconds will occur in the same 
95   *     minute, but this specification follows the date and time conventions 
96   *     for ISO C.
97   * </ul>
98   * <p>
99   * In all cases, arguments given to methods for these purposes need 
100  * not fall within the indicated ranges; for example, a date may be 
101  * specified as January 32 and is interpreted as meaning February 1.
102  *
103  * @author  James Gosling
104  * @author  Arthur van Hoff
105  * @author  Alan Liu
106  * @version %I%, %G%
107  * @see     java.text.DateFormat
108  * @see     java.util.Calendar
109  * @see     java.util.TimeZone
110  * @since   JDK1.0
111  */
112 public class Date
113     implements java.io.Serializable, Cloneable, Comparable<Date>
114 {
115     private static final BaseCalendar gcal =
116                 CalendarSystem.getGregorianCalendar();
117     private static BaseCalendar jcal;
118 
119     private transient long fastTime;
120 
121     /*
122      * If cdate is null, then fastTime indicates the time in millis.
123      * If cdate.isNormalized() is true, then fastTime and cdate are in
124      * synch. Otherwise, fastTime is ignored, and cdate indicates the
125      * time.
126      */
127     private transient BaseCalendar.Date cdate;
128 
129     // Initialized just before the value is used. See parse().
130     private static int defaultCenturyStart;
131 
132     /* use serialVersionUID from modified java.util.Date for
133      * interoperability with JDK1.1. The Date was modified to write
134      * and read only the UTC time.
135      */
136     private static final long serialVersionUID = 7523967970034938905L;
137 
138     /**
139      * Allocates a <code>Date</code> object and initializes it so that 
140      * it represents the time at which it was allocated, measured to the 
141      * nearest millisecond. 
142      *
143      * @see     java.lang.System#currentTimeMillis()
144      */
145     public Date() {
146         this(System.currentTimeMillis());
147     }
148 
149     /**
150      * Allocates a <code>Date</code> object and initializes it to 
151      * represent the specified number of milliseconds since the 
152      * standard base time known as "the epoch", namely January 1, 
153      * 1970, 00:00:00 GMT. 
154      *
155      * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
156      * @see     java.lang.System#currentTimeMillis()
157      */
158     public Date(long date) {
159         fastTime = date;
160     }
161 
162     /**
163      * Allocates a <code>Date</code> object and initializes it so that 
164      * it represents midnight, local time, at the beginning of the day 
165      * specified by the <code>year</code>, <code>month</code>, and 
166      * <code>date</code> arguments. 
167      *
168      * @param   year    the year minus 1900.
169      * @param   month   the month between 0-11.
170      * @param   date    the day of the month between 1-31.
171      * @see     java.util.Calendar
172      * @deprecated As of JDK version 1.1,
173      * replaced by <code>Calendar.set(year + 1900, month, date)</code>
174      * or <code>GregorianCalendar(year + 1900, month, date)</code>.
175      */
176     @Deprecated
177     public Date(int year, int month, int date) {
178         this(year, month, date, 0, 0, 0);
179     }
180 
181     /**
182      * Allocates a <code>Date</code> object and initializes it so that 
183      * it represents the instant at the start of the minute specified by 
184      * the <code>year</code>, <code>month</code>, <code>date</code>, 
185      * <code>hrs</code>, and <code>min</code> arguments, in the local 
186      * time zone. 
187      *
188      * @param   year    the year minus 1900.
189      * @param   month   the month between 0-11.
190      * @param   date    the day of the month between 1-31.
191      * @param   hrs     the hours between 0-23.
192      * @param   min     the minutes between 0-59.
193      * @see     java.util.Calendar
194      * @deprecated As of JDK version 1.1,
195      * replaced by <code>Calendar.set(year + 1900, month, date,
196      * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
197      * month, date, hrs, min)</code>.
198      */
199     @Deprecated
200     public Date(int year, int month, int date, int hrs, int min) {
201         this(year, month, date, hrs, min, 0);
202     }
203 
204     /**
205      * Allocates a <code>Date</code> object and initializes it so that 
206      * it represents the instant at the start of the second specified 
207      * by the <code>year</code>, <code>month</code>, <code>date</code>, 
208      * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments, 
209      * in the local time zone. 
210      *
211      * @param   year    the year minus 1900.
212      * @param   month   the month between 0-11.
213      * @param   date    the day of the month between 1-31.
214      * @param   hrs     the hours between 0-23.
215      * @param   min     the minutes between 0-59.
216      * @param   sec     the seconds between 0-59.
217      * @see     java.util.Calendar
218      * @deprecated As of JDK version 1.1,
219      * replaced by <code>Calendar.set(year + 1900, month, date,
220      * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
221      * month, date, hrs, min, sec)</code>.
222      */
223     @Deprecated
224     public Date(int year, int month, int date, int hrs, int min, int sec) {
225     int y = year + 1900;
226     // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
227     if (month >= 12) {
228         y += month / 12;
229         month %= 12;
230     } else if (month < 0) {
231         y += CalendarUtils.floorDivide(month, 12);
232         month = CalendarUtils.mod(month, 12);
233     }
234     BaseCalendar cal = getCalendarSystem(y);
235         cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
236     cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
237     getTimeImpl();
238     cdate = null;
239     }
240 
241     /**
242      * Allocates a <code>Date</code> object and initializes it so that 
243      * it represents the date and time indicated by the string 
244      * <code>s</code>, which is interpreted as if by the 
245      * {@link Date#parse} method. 
246      *
247      * @param   s   a string representation of the date.
248      * @see     java.text.DateFormat
249      * @see     java.util.Date#parse(java.lang.String)
250      * @deprecated As of JDK version 1.1,
251      * replaced by <code>DateFormat.parse(String s)</code>.
252      */
253     @Deprecated
254     public Date(String s) {
255         this(parse(s));
256     }
257 
258     /**
259      * Return a copy of this object.
260      */
261     public Object clone() {
262         Date d = null;
263         try {
264             d = (Date)super.clone();
265         if (cdate != null) {
266         d.cdate = (BaseCalendar.Date) cdate.clone();
267         }
268         } catch (CloneNotSupportedException e) {} // Won't happen
269         return d;
270     }
271     
272     /**
273      * Determines the date and time based on the arguments. The 
274      * arguments are interpreted as a year, month, day of the month, 
275      * hour of the day, minute within the hour, and second within the 
276      * minute, exactly as for the <tt>Date</tt> constructor with six 
277      * arguments, except that the arguments are interpreted relative 
278      * to UTC rather than to the local time zone. The time indicated is 
279      * returned represented as the distance, measured in milliseconds, 
280      * of that time from the epoch (00:00:00 GMT on January 1, 1970).
281      *
282      * @param   year    the year minus 1900.
283      * @param   month   the month between 0-11.
284      * @param   date    the day of the month between 1-31.
285      * @param   hrs     the hours between 0-23.
286      * @param   min     the minutes between 0-59.
287      * @param   sec     the seconds between 0-59.
288      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
289      *          the date and time specified by the arguments. 
290      * @see     java.util.Calendar
291      * @deprecated As of JDK version 1.1,
292      * replaced by <code>Calendar.set(year + 1900, month, date,
293      * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
294      * month, date, hrs, min, sec)</code>, using a UTC
295      * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
296      */
297     @Deprecated
298     public static long UTC(int year, int month, int date,
299                            int hrs, int min, int sec) {
300     int y = year + 1900;
301     // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
302     if (month >= 12) {
303         y += month / 12;
304         month %= 12;
305     } else if (month < 0) {
306         y += CalendarUtils.floorDivide(month, 12);
307         month = CalendarUtils.mod(month, 12);
308     }
309     int m = month + 1;
310     BaseCalendar cal = getCalendarSystem(y);
311         BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
312     udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
313 
314     // Use a Date instance to perform normalization. Its fastTime
315     // is the UTC value after the normalization.
316     Date d = new Date(0);
317     d.normalize(udate);
318     return d.fastTime;
319     }
320 
321     /**
322      * Attempts to interpret the string <tt>s</tt> as a representation 
323      * of a date and time. If the attempt is successful, the time 
324      * indicated is returned represented as the distance, measured in 
325      * milliseconds, of that time from the epoch (00:00:00 GMT on 
326      * January 1, 1970). If the attempt fails, an 
327      * <tt>IllegalArgumentException</tt> is thrown.
328      * <p>
329      * It accepts many syntaxes; in particular, it recognizes the IETF 
330      * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also 
331      * understands the continental U.S. time-zone abbreviations, but for 
332      * general use, a time-zone offset should be used: "Sat, 12 Aug 1995 
333      * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich 
334      * meridian). If no time zone is specified, the local time zone is 
335      * assumed. GMT and UTC are considered equivalent.
336      * <p>
337      * The string <tt>s</tt> is processed from left to right, looking for 
338      * data of interest. Any material in <tt>s</tt> that is within the 
339      * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored. 
340      * Parentheses may be nested. Otherwise, the only characters permitted 
341      * within <tt>s</tt> are these ASCII characters:
342      * <blockquote><pre>
343      * abcdefghijklmnopqrstuvwxyz
344      * ABCDEFGHIJKLMNOPQRSTUVWXYZ
345      * 0123456789,+-:/</pre></blockquote>
346      * and whitespace characters.<p>
347      * A consecutive sequence of decimal digits is treated as a decimal 
348      * number:<ul>
349      * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year 
350      *     has already been recognized, then the number is a time-zone 
351      *     offset. If the number is less than 24, it is an offset measured 
352      *     in hours. Otherwise, it is regarded as an offset in minutes, 
353      *     expressed in 24-hour time format without punctuation. A 
354      *     preceding <tt>-</tt> means a westward offset. Time zone offsets 
355      *     are always relative to UTC (Greenwich). Thus, for example, 
356      *     <tt>-5</tt> occurring in the string would mean "five hours west 
357      *     of Greenwich" and <tt>+0430</tt> would mean "four hours and 
358      *     thirty minutes east of Greenwich." It is permitted for the 
359      *     string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt> 
360      *     redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
361      * <li>The number is regarded as a year number if one of the
362      *     following conditions is true:
363      * <ul>
364      *     <li>The number is equal to or greater than 70 and followed by a
365      *         space, comma, slash, or end of string
366      *     <li>The number is less than 70, and both a month and a day of
367      *         the month have already been recognized</li>
368      * </ul>
369      *     If the recognized year number is less than 100, it is
370      *     interpreted as an abbreviated year relative to a century of
371      *     which dates are within 80 years before and 19 years after
372      *     the time when the Date class is initialized.
373      *     After adjusting the year number, 1900 is subtracted from
374      *     it. For example, if the current year is 1999 then years in
375      *     the range 19 to 99 are assumed to mean 1919 to 1999, while
376      *     years from 0 to 18 are assumed to mean 2000 to 2018.  Note
377      *     that this is slightly different from the interpretation of
378      *     years less than 100 that is used in {@link java.text.SimpleDateFormat}.
379      * <li>If the number is followed by a colon, it is regarded as an hour, 
380      *     unless an hour has already been recognized, in which case it is 
381      *     regarded as a minute.
382      * <li>If the number is followed by a slash, it is regarded as a month 
383      *     (it is decreased by 1 to produce a number in the range <tt>0</tt> 
384      *     to <tt>11</tt>), unless a month has already been recognized, in 
385      *     which case it is regarded as a day of the month.
386      * <li>If the number is followed by whitespace, a comma, a hyphen, or 
387      *     end of string, then if an hour has been recognized but not a 
388      *     minute, it is regarded as a minute; otherwise, if a minute has 
389      *     been recognized but not a second, it is regarded as a second; 
390      *     otherwise, it is regarded as a day of the month. </ul><p>
391      * A consecutive sequence of letters is regarded as a word and treated 
392      * as follows:<ul>
393      * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but 
394      *     the parse fails if an hour has not been recognized or is less 
395      *     than <tt>1</tt> or greater than <tt>12</tt>).
396      * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt> 
397      *     to the hour (but the parse fails if an hour has not been 
398      *     recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
399      * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY, 
400      *     WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring 
401      *     case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and 
402      *     <tt>Thurs</tt> are ignored.
403      * <li>Otherwise, any word that matches any prefix of <tt>JANUARY, 
404      *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, 
405      *     OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and 
406      *     considering them in the order given here, is recognized as
407      *     specifying a month and is converted to a number (<tt>0</tt> to 
408      *     <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and 
409      *     <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which 
410      *     is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
411      * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring 
412      *     case, is treated as referring to UTC. 
413      * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>, 
414      *     ignoring case, is recognized as referring to the time zone in 
415      *     North America that is five, six, seven, or eight hours west of 
416      *     Greenwich, respectively. Any word that matches <tt>EDT, CDT, 
417      *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as 
418      *     referring to the same time zone, respectively, during daylight 
419      *     saving time.</ul><p>
420      * Once the entire string s has been scanned, it is converted to a time 
421      * result in one of two ways. If a time zone or time-zone offset has been 
422      * recognized, then the year, month, day of month, hour, minute, and 
423      * second are interpreted in UTC and then the time-zone offset is 
424      * applied. Otherwise, the year, month, day of month, hour, minute, and 
425      * second are interpreted in the local time zone.
426      *
427      * @param   s   a string to be parsed as a date.
428      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
429      *          represented by the string argument.
430      * @see     java.text.DateFormat
431      * @deprecated As of JDK version 1.1,
432      * replaced by <code>DateFormat.parse(String s)</code>.
433      */
434     @Deprecated
435     public static long parse(String s) {
436         int year = Integer.MIN_VALUE;
437         int mon = -1;
438         int mday = -1;
439         int hour = -1;
440         int min = -1;
441         int sec = -1;
442         int millis = -1;
443         int c = -1;
444         int i = 0;
445         int n = -1;
446         int wst = -1;
447         int tzoffset = -1;
448         int prevc = 0;
449     syntax:
450         {
451             if (s == null)
452                 break syntax;
453             int limit = s.length();
454             while (i < limit) {
455                 c = s.charAt(i);
456                 i++;
457                 if (c <= ' ' || c == ',')
458                     continue;
459                 if (c == '(') { // skip comments
460                     int depth = 1;
461                     while (i < limit) {
462                         c = s.charAt(i);
463                         i++;
464                         if (c == '(') depth++;
465                         else if (c == ')')
466                             if (--depth <= 0)
467                                 break;
468                     }
469                     continue;
470                 }
471                 if ('0' <= c && c <= '9') {
472                     n = c - '0';
473                     while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
474                         n = n * 10 + c - '0';
475                         i++;
476                     }
477                     if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
478                         // timezone offset
479                         if (n < 24)
480                             n = n * 60; // EG. "GMT-3"
481                         else
482                             n = n % 100 + n / 100 * 60; // eg "GMT-0430"
483                         if (prevc == '+')   // plus means east of GMT
484                             n = -n;
485                         if (tzoffset != 0 && tzoffset != -1)
486                             break syntax;
487                         tzoffset = n;
488                     } else if (n >= 70)
489                         if (year != Integer.MIN_VALUE)
490                             break syntax;
491                         else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
492                             // year = n < 1900 ? n : n - 1900;
493                             year = n;
494                         else
495                             break syntax;
496                     else if (c == ':')
497                         if (hour < 0)
498                             hour = (byte) n;
499                         else if (min < 0)
500                             min = (byte) n;
501                         else
502                             break syntax;
503                     else if (c == '/')
504                         if (mon < 0)
505                             mon = (byte) (n - 1);
506                         else if (mday < 0)
507                             mday = (byte) n;
508                         else
509                             break syntax;
510                     else if (i < limit && c != ',' && c > ' ' && c != '-')
511                         break syntax;
512                     else if (hour >= 0 && min < 0)
513                         min = (byte) n;
514                     else if (min >= 0 && sec < 0)
515                         sec = (byte) n;
516                     else if (mday < 0)
517                         mday = (byte) n;
518                     // Handle two-digit years < 70 (70-99 handled above).
519                     else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
520                         year = n;
521                     else
522                         break syntax;
523                     prevc = 0;
524                 } else if (c == '/' || c == ':' || c == '+' || c == '-')
525                     prevc = c;
526                 else {
527                     int st = i - 1;
528                     while (i < limit) {
529                         c = s.charAt(i);
530                         if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
531                             break;
532                         i++;
533                     }
534                     if (i <= st + 1)
535                         break syntax;
536                     int k;
537                     for (k = wtb.length; --k >= 0;)
538                         if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
539                             int action = ttb[k];
540                             if (action != 0) {
541                                 if (action == 1) {  // pm
542                                     if (hour > 12 || hour < 1)
543                                         break syntax;
544                                     else if (hour < 12)
545                                         hour += 12;
546                                 } else if (action == 14) {  // am
547                                     if (hour > 12 || hour < 1)
548                                         break syntax;
549                                     else if (hour == 12)
550                                         hour = 0;
551                                 } else if (action <= 13) {  // month!
552                                     if (mon < 0)
553                                         mon = (byte) (action - 2);
554                                     else
555                                         break syntax;
556                                 } else {
557                                     tzoffset = action - 10000;
558                                 }
559                             }
560                             break;
561                         }
562                     if (k < 0)
563                         break syntax;
564                     prevc = 0;
565                 }
566             }
567             if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
568                 break syntax;
569             // Parse 2-digit years within the correct default century.
570             if (year < 100) {
571         synchronized (Date.class) {
572             if (defaultCenturyStart == 0) {
573             defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
574             }
575         }
576                 year += (defaultCenturyStart / 100) * 100;
577                 if (year < defaultCenturyStart) year += 100;
578             }
579             if (sec < 0)
580                 sec = 0;
581             if (min < 0)
582                 min = 0;
583             if (hour < 0)
584                 hour = 0;
585         BaseCalendar cal = getCalendarSystem(year);
586             if (tzoffset == -1)  { // no time zone specified, have to use local
587         BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
588         ldate.setDate(year, mon + 1, mday);
589         ldate.setTimeOfDay(hour, min, sec, 0);
590                 return cal.getTime(ldate);
591         }
592         BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
593         udate.setDate(year, mon + 1, mday);
594         udate.setTimeOfDay(hour, min, sec, 0);
595             return cal.getTime(udate) + tzoffset * (60 * 1000);
596         }
597         // syntax error
598         throw new IllegalArgumentException();
599     }
600     private final static String wtb[] = {
601         "am", "pm",
602         "monday", "tuesday", "wednesday", "thursday", "friday",
603         "saturday", "sunday",
604         "january", "february", "march", "april", "may", "june",
605         "july", "august", "september", "october", "november", "december",
606         "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
607         "mst", "mdt", "pst", "pdt"
608     };
609     private final static int ttb[] = {
610         14, 1, 0, 0, 0, 0, 0, 0, 0,
611         2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
612         10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
613         10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
614         10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
615         10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
616         10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
617     };
618 
619     /**
620      * Returns a value that is the result of subtracting 1900 from the 
621      * year that contains or begins with the instant in time represented 
622      * by this <code>Date</code> object, as interpreted in the local 
623      * time zone.
624      *
625      * @return  the year represented by this date, minus 1900.
626      * @see     java.util.Calendar
627      * @deprecated As of JDK version 1.1,
628      * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
629      */
630     @Deprecated
631     public int getYear() {
632         return normalize().getYear() - 1900;
633     }
634 
635     /**
636      * Sets the year of this <tt>Date</tt> object to be the specified 
637      * value plus 1900. This <code>Date</code> object is modified so 
638      * that it represents a point in time within the specified year, 
639      * with the month, date, hour, minute, and second the same as 
640      * before, as interpreted in the local time zone. (Of course, if 
641      * the date was February 29, for example, and the year is set to a 
642      * non-leap year, then the new date will be treated as if it were 
643      * on March 1.)
644      *
645      * @param   year    the year value.
646      * @see     java.util.Calendar
647      * @deprecated As of JDK version 1.1,
648      * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
649      */
650     @Deprecated
651     public void setYear(int year) {
652     getCalendarDate().setNormalizedYear(year + 1900);
653     }
654 
655     /**
656      * Returns a number representing the month that contains or begins 
657      * with the instant in time represented by this <tt>Date</tt> object. 
658      * The value returned is between <code>0</code> and <code>11</code>, 
659      * with the value <code>0</code> representing January.
660      *
661      * @return  the month represented by this date.
662      * @see     java.util.Calendar
663      * @deprecated As of JDK version 1.1,
664      * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
665      */
666     @Deprecated
667     public int getMonth() {
668     return normalize().getMonth() - 1; // adjust 1-based to 0-based
669     }
670 
671     /**
672      * Sets the month of this date to the specified value. This 
673      * <tt>Date</tt> object is modified so that it represents a point 
674      * in time within the specified month, with the year, date, hour, 
675      * minute, and second the same as before, as interpreted in the 
676      * local time zone. If the date was October 31, for example, and 
677      * the month is set to June, then the new date will be treated as 
678      * if it were on July 1, because June has only 30 days.
679      *
680      * @param   month   the month value between 0-11.
681      * @see     java.util.Calendar
682      * @deprecated As of JDK version 1.1,
683      * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
684      */
685     @Deprecated
686     public void setMonth(int month) {
687     int y = 0;
688     if (month >= 12) {
689         y = month / 12;
690         month %= 12;
691     } else if (month < 0) {
692         y = CalendarUtils.floorDivide(month, 12);
693         month = CalendarUtils.mod(month, 12);
694     }
695         BaseCalendar.Date d = getCalendarDate();
696     if (y != 0) {
697         d.setNormalizedYear(d.getNormalizedYear() + y);
698     }
699     d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
700     }
701 
702     /**
703      * Returns the day of the month represented by this <tt>Date</tt> object. 
704      * The value returned is between <code>1</code> and <code>31</code> 
705      * representing the day of the month that contains or begins with the 
706      * instant in time represented by this <tt>Date</tt> object, as 
707      * interpreted in the local time zone.
708      *
709      * @return  the day of the month represented by this date.
710      * @see     java.util.Calendar
711      * @deprecated As of JDK version 1.1,
712      * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
713      * @deprecated
714      */
715     @Deprecated
716     public int getDate() {
717     return normalize().getDayOfMonth();
718     }
719 
720     /**
721      * Sets the day of the month of this <tt>Date</tt> object to the 
722      * specified value. This <tt>Date</tt> object is modified so that 
723      * it represents a point in time within the specified day of the 
724      * month, with the year, month, hour, minute, and second the same 
725      * as before, as interpreted in the local time zone. If the date 
726      * was April 30, for example, and the date is set to 31, then it 
727      * will be treated as if it were on May 1, because April has only 
728      * 30 days.
729      *
730      * @param   date   the day of the month value between 1-31.
731      * @see     java.util.Calendar
732      * @deprecated As of JDK version 1.1,
733      * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
734      */
735     @Deprecated
736     public void setDate(int date) {
737         getCalendarDate().setDayOfMonth(date);
738     }
739 
740     /**
741      * Returns the day of the week represented by this date. The 
742      * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday, 
743      * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> = 
744      * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday) 
745      * represents the day of the week that contains or begins with 
746      * the instant in time represented by this <tt>Date</tt> object, 
747      * as interpreted in the local time zone.
748      *
749      * @return  the day of the week represented by this date.
750      * @see     java.util.Calendar
751      * @deprecated As of JDK version 1.1,
752      * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
753      */
754     @Deprecated
755     public int getDay() {
756     return normalize().getDayOfWeek() - gcal.SUNDAY;
757     }
758 
759     /**
760      * Returns the hour represented by this <tt>Date</tt> object. The 
761      * returned value is a number (<tt>0</tt> through <tt>23</tt>) 
762      * representing the hour within the day that contains or begins 
763      * with the instant in time represented by this <tt>Date</tt> 
764      * object, as interpreted in the local time zone.
765      *
766      * @return  the hour represented by this date.
767      * @see     java.util.Calendar
768      * @deprecated As of JDK version 1.1,
769      * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
770      */
771     @Deprecated
772     public int getHours() {
773     return normalize().getHours();
774     }
775 
776     /**
777      * Sets the hour of this <tt>Date</tt> object to the specified value. 
778      * This <tt>Date</tt> object is modified so that it represents a point 
779      * in time within the specified hour of the day, with the year, month, 
780      * date, minute, and second the same as before, as interpreted in the 
781      * local time zone.
782      *
783      * @param   hours   the hour value.
784      * @see     java.util.Calendar
785      * @deprecated As of JDK version 1.1,
786      * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
787      */
788     @Deprecated
789     public void setHours(int hours) {
790         getCalendarDate().setHours(hours);
791     }
792 
793     /**
794      * Returns the number of minutes past the hour represented by this date, 
795      * as interpreted in the local time zone. 
796      * The value returned is between <code>0</code> and <code>59</code>.
797      *
798      * @return  the number of minutes past the hour represented by this date.
799      * @see     java.util.Calendar
800      * @deprecated As of JDK version 1.1,
801      * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
802      */
803     @Deprecated
804     public int getMinutes() {
805     return normalize().getMinutes();
806     }
807 
808     /**
809      * Sets the minutes of this <tt>Date</tt> object to the specified value. 
810      * This <tt>Date</tt> object is modified so that it represents a point 
811      * in time within the specified minute of the hour, with the year, month, 
812      * date, hour, and second the same as before, as interpreted in the 
813      * local time zone.
814      *
815      * @param   minutes   the value of the minutes.
816      * @see     java.util.Calendar
817      * @deprecated As of JDK version 1.1,
818      * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
819      */
820     @Deprecated
821     public void setMinutes(int minutes) {
822         getCalendarDate().setMinutes(minutes);
823     }
824 
825     /**
826      * Returns the number of seconds past the minute represented by this date.
827      * The value returned is between <code>0</code> and <code>61</code>. The
828      * values <code>60</code> and <code>61</code> can only occur on those 
829      * Java Virtual Machines that take leap seconds into account.
830      *
831      * @return  the number of seconds past the minute represented by this date.
832      * @see     java.util.Calendar
833      * @deprecated As of JDK version 1.1,
834      * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
835      */
836     @Deprecated
837     public int getSeconds() {
838     return normalize().getSeconds();
839     }
840 
841     /**
842      * Sets the seconds of this <tt>Date</tt> to the specified value. 
843      * This <tt>Date</tt> object is modified so that it represents a 
844      * point in time within the specified second of the minute, with 
845      * the year, month, date, hour, and minute the same as before, as 
846      * interpreted in the local time zone.
847      *
848      * @param   seconds   the seconds value.
849      * @see     java.util.Calendar
850      * @deprecated As of JDK version 1.1,
851      * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>. 
852      */
853     @Deprecated
854     public void setSeconds(int seconds) {
855         getCalendarDate().setSeconds(seconds);
856     }
857 
858     /**
859      * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
860      * represented by this <tt>Date</tt> object.
861      *
862      * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
863      *          represented by this date.
864      */
865     public long getTime() {
866         return getTimeImpl();
867     }
868 
869     private final long getTimeImpl() {
870     if (cdate != null && !cdate.isNormalized()) {
871         normalize();
872     }
873     return fastTime;
874     }
875 
876     /**
877      * Sets this <code>Date</code> object to represent a point in time that is 
878      * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT. 
879      *
880      * @param   time   the number of milliseconds.
881      */
882     public void setTime(long time) {
883     fastTime = time;
884     cdate = null;
885     }
886 
887     /**
888      * Tests if this date is before the specified date.
889      *
890      * @param   when   a date.
891      * @return  <code>true</code> if and only if the instant of time 
892      *            represented by this <tt>Date</tt> object is strictly 
893      *            earlier than the instant represented by <tt>when</tt>;
894      *          <code>false</code> otherwise.
895      * @exception NullPointerException if <code>when</code> is null.
896      */
897     public boolean before(Date when) {
898         return getMillisOf(this) < getMillisOf(when);
899     }
900 
901     /**
902      * Tests if this date is after the specified date.
903      *
904      * @param   when   a date.
905      * @return  <code>true</code> if and only if the instant represented 
906      *          by this <tt>Date</tt> object is strictly later than the 
907      *          instant represented by <tt>when</tt>; 
908      *          <code>false</code> otherwise.
909      * @exception NullPointerException if <code>when</code> is null.
910      */
911     public boolean after(Date when) {
912         return getMillisOf(this) > getMillisOf(when);
913     }
914 
915     /**
916      * Compares two dates for equality.
917      * The result is <code>true</code> if and only if the argument is 
918      * not <code>null</code> and is a <code>Date</code> object that 
919      * represents the same point in time, to the millisecond, as this object.
920      * <p>
921      * Thus, two <code>Date</code> objects are equal if and only if the 
922      * <code>getTime</code> method returns the same <code>long</code> 
923      * value for both. 
924      *
925      * @param   obj   the object to compare with.
926      * @return  <code>true</code> if the objects are the same;
927      *          <code>false</code> otherwise.
928      * @see     java.util.Date#getTime()
929      */
930     public boolean equals(Object obj) {
931         return obj instanceof Date && getTime() == ((Date) obj).getTime();
932     }
933 
934     /**
935      * Returns the millisecond value of this <code>Date</code> object
936      * without affecting its internal state.
937      */
938     static final long getMillisOf(Date date) {
939     if (date.cdate == null || date.cdate.isNormalized()) {
940         return date.fastTime;
941     }
942     BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
943     return gcal.getTime(d);
944     }
945 
946     /**
947      * Compares two Dates for ordering.
948      *
949      * @param   anotherDate   the <code>Date</code> to be compared.
950      * @return  the value <code>0</code> if the argument Date is equal to
951      *          this Date; a value less than <code>0</code> if this Date
952      *          is before the Date argument; and a value greater than
953      *      <code>0</code> if this Date is after the Date argument.
954      * @since   1.2
955      * @exception NullPointerException if <code>anotherDate</code> is null.
956      */
957     public int compareTo(Date anotherDate) {
958     long thisTime = getMillisOf(this);
959     long anotherTime = getMillisOf(anotherDate);
960     return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
961     }
962 
963     /**
964      * Returns a hash code value for this object. The result is the 
965      * exclusive OR of the two halves of the primitive <tt>long</tt> 
966      * value returned by the {@link Date#getTime} 
967      * method. That is, the hash code is the value of the expression:
968      * <blockquote><pre>
969      * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
970      *
971      * @return  a hash code value for this object. 
972      */
973     public int hashCode() {
974         long ht = this.getTime();
975         return (int) ht ^ (int) (ht >> 32);
976     }
977 
978     /**
979      * Converts this <code>Date</code> object to a <code>String</code> 
980      * of the form:
981      * <blockquote><pre>
982      * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
983      * where:<ul>
984      * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed, 
985      *     Thu, Fri, Sat</tt>).
986      * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, 
987      *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
988      * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through 
989      *     <tt>31</tt>), as two decimal digits.
990      * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through 
991      *     <tt>23</tt>), as two decimal digits.
992      * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through 
993      *     <tt>59</tt>), as two decimal digits.
994      * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through 
995      *     <tt>61</tt>, as two decimal digits.
996      * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving 
997      *     time). Standard time zone abbreviations include those 
998      *     recognized by the method <tt>parse</tt>. If time zone 
999      *     information is not available, then <tt>zzz</tt> is empty - 
1000     *     that is, it consists of no characters at all.
1001     * <li><tt>yyyy</tt> is the year, as four decimal digits.
1002     * </ul>
1003     *
1004     * @return  a string representation of this date. 
1005     * @see     java.util.Date#toLocaleString()
1006     * @see     java.util.Date#toGMTString()
1007     */
1008    public String toString() {
1009    // "EEE MMM dd HH:mm:ss zzz yyyy";
1010    BaseCalendar.Date date = normalize();
1011    StringBuilder sb = new StringBuilder(28);
1012    int index = date.getDayOfWeek();
1013    if (index == gcal.SUNDAY) {
1014        index = 8;
1015    }
1016    convertToAbbr(sb, wtb[index]).append(' ');            // EEE
1017    convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
1018    CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
1019
1020    CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
1021    CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
1022    CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
1023    TimeZone zi = date.getZone();
1024    if (zi != null) {
1025        sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
1026    } else {
1027        sb.append("GMT");
1028    }
1029    sb.append(' ').append(date.getYear());  // yyyy
1030    return sb.toString();
1031    }
1032
1033    /**
1034     * Converts the given name to its 3-letter abbreviation (e.g.,
1035     * "monday" -> "Mon") and stored the abbreviation in the given
1036     * <code>StringBuilder</code>.
1037     */
1038    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
1039    sb.append(Character.toUpperCase(name.charAt(0)));
1040    sb.append(name.charAt(1)).append(name.charAt(2));
1041    return sb;
1042    }
1043
1044    /**
1045     * Creates a string representation of this <tt>Date</tt> object in an 
1046     * implementation-dependent form. The intent is that the form should 
1047     * be familiar to the user of the Java application, wherever it may 
1048     * happen to be running. The intent is comparable to that of the 
1049     * "<code>%c</code>" format supported by the <code>strftime()</code> 
1050     * function of ISO&nbsp;C. 
1051     *
1052     * @return  a string representation of this date, using the locale
1053     *          conventions.
1054     * @see     java.text.DateFormat
1055     * @see     java.util.Date#toString()
1056     * @see     java.util.Date#toGMTString()
1057     * @deprecated As of JDK version 1.1,
1058     * replaced by <code>DateFormat.format(Date date)</code>.
1059     */
1060    @Deprecated
1061    public String toLocaleString() {
1062    DateFormat formatter = DateFormat.getDateTimeInstance();
1063    return formatter.format(this);
1064    }
1065
1066    /**
1067     * Creates a string representation of this <tt>Date</tt> object of 
1068     * the form:
1069     * <blockquote<pre>
1070     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
1071     * where:<ul>
1072     * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>), 
1073     *     as one or two decimal digits.
1074     * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul, 
1075     *     Aug, Sep, Oct, Nov, Dec</tt>).
1076     * <li><i>yyyy</i> is the year, as four decimal digits.
1077     * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>), 
1078     *     as two decimal digits.
1079     * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through 
1080     *     <tt>59</tt>), as two decimal digits.
1081     * <li><i>ss</i> is the second within the minute (<tt>00</tt> through 
1082     *     <tt>61</tt>), as two decimal digits.
1083     * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate 
1084     *     Greenwich Mean Time.
1085     * </ul><p>
1086     * The result does not depend on the local time zone.
1087     * 
1088     * @return  a string representation of this date, using the Internet GMT
1089     *          conventions.
1090     * @see     java.text.DateFormat
1091     * @see     java.util.Date#toString()
1092     * @see     java.util.Date#toLocaleString()
1093     * @deprecated As of JDK version 1.1,
1094     * replaced by <code>DateFormat.format(Date date)</code>, using a
1095     * GMT <code>TimeZone</code>.
1096     */
1097    @Deprecated
1098    public String toGMTString() {
1099    // d MMM yyyy HH:mm:ss 'GMT'
1100    long t = getTime();
1101    BaseCalendar cal = getCalendarSystem(t);
1102    BaseCalendar.Date date =
1103        (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
1104    StringBuilder sb = new StringBuilder(32);
1105    CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
1106    convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
1107    sb.append(date.getYear()).append(' ');                            // yyyy
1108    CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
1109    CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
1110    CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
1111    sb.append(" GMT");                                                // ' GMT'
1112    return sb.toString();
1113    }
1114
1115    /**
1116     * Returns the offset, measured in minutes, for the local time zone 
1117     * relative to UTC that is appropriate for the time represented by 
1118     * this <code>Date</code> object. 
1119     * <p>
1120     * For example, in Massachusetts, five time zones west of Greenwich:
1121     * <blockquote><pre>
1122     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
1123     * because on February 14, 1996, standard time (Eastern Standard Time) 
1124     * is in use, which is offset five hours from UTC; but:
1125     * <blockquote><pre>
1126     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
1127     * because on June 1, 1996, daylight saving time (Eastern Daylight Time) 
1128     * is in use, which is offset only four hours from UTC.<p>
1129     * This method produces the same result as if it computed:
1130     * <blockquote><pre>
1131     * (this.getTime() - UTC(this.getYear(), 
1132     *                       this.getMonth(), 
1133     *                       this.getDate(),
1134     *                       this.getHours(), 
1135     *                       this.getMinutes(), 
1136     *                       this.getSeconds())) / (60 * 1000)
1137     * </pre></blockquote>
1138     *
1139     * @return  the time-zone offset, in minutes, for the current time zone.
1140     * @see     java.util.Calendar#ZONE_OFFSET
1141     * @see     java.util.Calendar#DST_OFFSET
1142     * @see     java.util.TimeZone#getDefault
1143     * @deprecated As of JDK version 1.1,
1144     * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
1145     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
1146     */
1147    @Deprecated
1148    public int getTimezoneOffset() {
1149    int zoneOffset;
1150        if (cdate == null) {
1151        TimeZone tz = TimeZone.getDefaultRef();
1152        if (tz instanceof ZoneInfo) {
1153        zoneOffset = ((ZoneInfo)tz).getOffsets(fastTime, null);
1154        } else {
1155        zoneOffset = tz.getOffset(fastTime);
1156        }
1157    } else {
1158        normalize();
1159        zoneOffset = cdate.getZoneOffset();
1160    }
1161    return -zoneOffset/60000;  // convert to minutes
1162    }
1163
1164    private final BaseCalendar.Date getCalendarDate() {
1165    if (cdate == null) {
1166        BaseCalendar cal = getCalendarSystem(fastTime);
1167        cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
1168                                TimeZone.getDefaultRef());
1169    }
1170    return cdate;
1171    }
1172
1173    private final BaseCalendar.Date normalize() {
1174    if (cdate == null) {
1175        BaseCalendar cal = getCalendarSystem(fastTime);
1176        cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
1177                                TimeZone.getDefaultRef());
1178        return cdate;
1179    }
1180
1181    // Normalize cdate with the TimeZone in cdate first. This is
1182    // required for the compatible behavior.
1183    if (!cdate.isNormalized()) {
1184        cdate = normalize(cdate);
1185    }
1186
1187    // If the default TimeZone has changed, then recalculate the
1188    // fields with the new TimeZone.
1189    TimeZone tz = TimeZone.getDefaultRef();
1190    if (tz != cdate.getZone()) {
1191        cdate.setZone(tz);
1192        CalendarSystem cal = getCalendarSystem(cdate);
1193        cal.getCalendarDate(fastTime, cdate);
1194    }
1195    return cdate;
1196    }
1197
1198    // fastTime and the returned data are in sync upon return.
1199    private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
1200    int y = date.getNormalizedYear();
1201    int m = date.getMonth();
1202    int d = date.getDayOfMonth();
1203    int hh = date.getHours();
1204    int mm = date.getMinutes();
1205    int ss = date.getSeconds();
1206    int ms = date.getMillis();
1207    TimeZone tz = date.getZone();
1208
1209    // If the specified year can't be handled using a long value
1210    // in milliseconds, GregorianCalendar is used for full
1211    // compatibility with underflow and overflow. This is required
1212    // by some JCK tests. The limits are based max year values -
1213    // years that can be represented by max values of d, hh, mm,
1214    // ss and ms. Also, let GregorianCalendar handle the default
1215    // cutover year so that we don't need to worry about the
1216    // transition here.
1217    if (y == 1582 || y > 280000000 || y < -280000000) {
1218        if (tz == null) {
1219        tz = TimeZone.getTimeZone("GMT");
1220        }
1221        GregorianCalendar gc = new GregorianCalendar(tz);
1222        gc.clear();
1223        gc.set(gc.MILLISECOND, ms);
1224        gc.set(y, m-1, d, hh, mm, ss);
1225        fastTime = gc.getTimeInMillis();
1226        BaseCalendar cal = getCalendarSystem(fastTime);
1227        date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
1228        return date;
1229    }
1230
1231    BaseCalendar cal = getCalendarSystem(y);
1232    if (cal != getCalendarSystem(date)) {
1233        date = (BaseCalendar.Date) cal.newCalendarDate(tz);
1234        date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
1235    }
1236    // Perform the GregorianCalendar-style normalization.
1237    fastTime = cal.getTime(date);
1238
1239    // In case the normalized date requires the other calendar
1240    // system, we need to recalculate it using the other one.
1241    BaseCalendar ncal = getCalendarSystem(fastTime);
1242    if (ncal != cal) {
1243        date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
1244        date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
1245        fastTime = ncal.getTime(date);
1246    }
1247    return date;
1248    }
1249
1250    /**
1251     * Returns the Gregorian or Julian calendar system to use with the
1252     * given date. Use Gregorian from October 15, 1582.
1253     *
1254     * @param year normalized calendar year (not -1900)
1255     * @return the CalendarSystem to use for the specified date
1256     */
1257    private static final BaseCalendar getCalendarSystem(int year) {
1258    if (year >= 1582) {
1259        return gcal;
1260    }
1261    return getJulianCalendar();
1262    }
1263
1264    private static final BaseCalendar getCalendarSystem(long utc) {
1265    // Quickly check if the time stamp given by `utc' is the Epoch
1266    // or later. If it's before 1970, we convert the cutover to
1267    // local time to compare.
1268    if (utc >= 0
1269        || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
1270            - TimeZone.getDefaultRef().getOffset(utc)) {
1271        return gcal;
1272    }
1273    return getJulianCalendar();
1274    }
1275
1276    private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
1277    if (jcal == null) {
1278        return gcal;
1279    }
1280    if (cdate.getEra() != null) {
1281        return jcal;
1282    }
1283    return gcal;
1284    }
1285
1286    synchronized private static final BaseCalendar getJulianCalendar() {
1287    if (jcal == null) {
1288        jcal = (BaseCalendar) CalendarSystem.forName("julian");
1289    }
1290    return jcal;
1291    }
1292
1293    /**
1294     * Save the state of this object to a stream (i.e., serialize it).
1295     *
1296     * @serialData The value returned by <code>getTime()</code>
1297     *         is emitted (long).  This represents the offset from
1298     *             January 1, 1970, 00:00:00 GMT in milliseconds.
1299     */
1300    private void writeObject(ObjectOutputStream s)
1301         throws IOException
1302    {
1303        s.writeLong(getTimeImpl());
1304    }
1305
1306    /**
1307     * Reconstitute this object from a stream (i.e., deserialize it).
1308     */
1309    private void readObject(ObjectInputStream s)
1310         throws IOException, ClassNotFoundException
1311    {
1312        fastTime = s.readLong();
1313    }
1314}
1315