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