Date.java revision 2c87ad3a45cecf9e344487cad1abfdebe79f2c7c
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                        // timezone offset
496                        if (n < 24)
497                            n = n * 60; // EG. "GMT-3"
498                        else
499                            n = n % 100 + n / 100 * 60; // eg "GMT-0430"
500                        if (prevc == '+')   // plus means east of GMT
501                            n = -n;
502                        if (tzoffset != 0 && tzoffset != -1)
503                            break syntax;
504                        tzoffset = n;
505                    } else if (n >= 70)
506                        if (year != Integer.MIN_VALUE)
507                            break syntax;
508                        else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
509                            // year = n < 1900 ? n : n - 1900;
510                            year = n;
511                        else
512                            break syntax;
513                    else if (c == ':')
514                        if (hour < 0)
515                            hour = (byte) n;
516                        else if (min < 0)
517                            min = (byte) n;
518                        else
519                            break syntax;
520                    else if (c == '/')
521                        if (mon < 0)
522                            mon = (byte) (n - 1);
523                        else if (mday < 0)
524                            mday = (byte) n;
525                        else
526                            break syntax;
527                    else if (i < limit && c != ',' && c > ' ' && c != '-')
528                        break syntax;
529                    else if (hour >= 0 && min < 0)
530                        min = (byte) n;
531                    else if (min >= 0 && sec < 0)
532                        sec = (byte) n;
533                    else if (mday < 0)
534                        mday = (byte) n;
535                    // Handle two-digit years < 70 (70-99 handled above).
536                    else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
537                        year = n;
538                    else
539                        break syntax;
540                    prevc = 0;
541                } else if (c == '/' || c == ':' || c == '+' || c == '-')
542                    prevc = c;
543                else {
544                    int st = i - 1;
545                    while (i < limit) {
546                        c = s.charAt(i);
547                        if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
548                            break;
549                        i++;
550                    }
551                    if (i <= st + 1)
552                        break syntax;
553                    int k;
554                    for (k = wtb.length; --k >= 0;)
555                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
556                            int action = ttb[k];
557                            if (action != 0) {
558                                if (action == 1) {  // pm
559                                    if (hour > 12 || hour < 1)
560                                        break syntax;
561                                    else if (hour < 12)
562                                        hour += 12;
563                                } else if (action == 14) {  // am
564                                    if (hour > 12 || hour < 1)
565                                        break syntax;
566                                    else if (hour == 12)
567                                        hour = 0;
568                                } else if (action <= 13) {  // month!
569                                    if (mon < 0)
570                                        mon = (byte) (action - 2);
571                                    else
572                                        break syntax;
573                                } else {
574                                    tzoffset = action - 10000;
575                                }
576                            }
577                            break;
578                        }
579                    if (k < 0)
580                        break syntax;
581                    prevc = 0;
582                }
583            }
584            if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
585                break syntax;
586            // Parse 2-digit years within the correct default century.
587            if (year < 100) {
588                synchronized (Date.class) {
589                    if (defaultCenturyStart == 0) {
590                        defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
591                    }
592                }
593                year += (defaultCenturyStart / 100) * 100;
594                if (year < defaultCenturyStart) year += 100;
595            }
596            if (sec < 0)
597                sec = 0;
598            if (min < 0)
599                min = 0;
600            if (hour < 0)
601                hour = 0;
602            BaseCalendar cal = getCalendarSystem(year);
603            if (tzoffset == -1)  { // no time zone specified, have to use local
604                BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
605                ldate.setDate(year, mon + 1, mday);
606                ldate.setTimeOfDay(hour, min, sec, 0);
607                return cal.getTime(ldate);
608            }
609            BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
610            udate.setDate(year, mon + 1, mday);
611            udate.setTimeOfDay(hour, min, sec, 0);
612            return cal.getTime(udate) + tzoffset * (60 * 1000);
613        }
614        // syntax error
615        throw new IllegalArgumentException();
616    }
617    private final static String wtb[] = {
618        "am", "pm",
619        "monday", "tuesday", "wednesday", "thursday", "friday",
620        "saturday", "sunday",
621        "january", "february", "march", "april", "may", "june",
622        "july", "august", "september", "october", "november", "december",
623        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
624        "mst", "mdt", "pst", "pdt"
625    };
626    private final static int ttb[] = {
627        14, 1, 0, 0, 0, 0, 0, 0, 0,
628        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
629        10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
630        10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
631        10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
632        10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
633        10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
634    };
635
636    /**
637     * Returns a value that is the result of subtracting 1900 from the
638     * year that contains or begins with the instant in time represented
639     * by this <code>Date</code> object, as interpreted in the local
640     * time zone.
641     *
642     * @return  the year represented by this date, minus 1900.
643     * @see     java.util.Calendar
644     * @deprecated As of JDK version 1.1,
645     * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
646     */
647    @Deprecated
648    public int getYear() {
649        return normalize().getYear() - 1900;
650    }
651
652    /**
653     * Sets the year of this <tt>Date</tt> object to be the specified
654     * value plus 1900. This <code>Date</code> object is modified so
655     * that it represents a point in time within the specified year,
656     * with the month, date, hour, minute, and second the same as
657     * before, as interpreted in the local time zone. (Of course, if
658     * the date was February 29, for example, and the year is set to a
659     * non-leap year, then the new date will be treated as if it were
660     * on March 1.)
661     *
662     * @param   year    the year value.
663     * @see     java.util.Calendar
664     * @deprecated As of JDK version 1.1,
665     * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
666     */
667    @Deprecated
668    public void setYear(int year) {
669        getCalendarDate().setNormalizedYear(year + 1900);
670    }
671
672    /**
673     * Returns a number representing the month that contains or begins
674     * with the instant in time represented by this <tt>Date</tt> object.
675     * The value returned is between <code>0</code> and <code>11</code>,
676     * with the value <code>0</code> representing January.
677     *
678     * @return  the month represented by this date.
679     * @see     java.util.Calendar
680     * @deprecated As of JDK version 1.1,
681     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
682     */
683    @Deprecated
684    public int getMonth() {
685        return normalize().getMonth() - 1; // adjust 1-based to 0-based
686    }
687
688    /**
689     * Sets the month of this date to the specified value. This
690     * <tt>Date</tt> object is modified so that it represents a point
691     * in time within the specified month, with the year, date, hour,
692     * minute, and second the same as before, as interpreted in the
693     * local time zone. If the date was October 31, for example, and
694     * the month is set to June, then the new date will be treated as
695     * if it were on July 1, because June has only 30 days.
696     *
697     * @param   month   the month value between 0-11.
698     * @see     java.util.Calendar
699     * @deprecated As of JDK version 1.1,
700     * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
701     */
702    @Deprecated
703    public void setMonth(int month) {
704        int y = 0;
705        if (month >= 12) {
706            y = month / 12;
707            month %= 12;
708        } else if (month < 0) {
709            y = CalendarUtils.floorDivide(month, 12);
710            month = CalendarUtils.mod(month, 12);
711        }
712        BaseCalendar.Date d = getCalendarDate();
713        if (y != 0) {
714            d.setNormalizedYear(d.getNormalizedYear() + y);
715        }
716        d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
717    }
718
719    /**
720     * Returns the day of the month represented by this <tt>Date</tt> object.
721     * The value returned is between <code>1</code> and <code>31</code>
722     * representing the day of the month that contains or begins with the
723     * instant in time represented by this <tt>Date</tt> object, as
724     * interpreted in the local time zone.
725     *
726     * @return  the day of the month represented by this date.
727     * @see     java.util.Calendar
728     * @deprecated As of JDK version 1.1,
729     * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
730     */
731    @Deprecated
732    // Android removed stray @deprecated tag.
733    public int getDate() {
734        return normalize().getDayOfMonth();
735    }
736
737    /**
738     * Sets the day of the month of this <tt>Date</tt> object to the
739     * specified value. This <tt>Date</tt> object is modified so that
740     * it represents a point in time within the specified day of the
741     * month, with the year, month, hour, minute, and second the same
742     * as before, as interpreted in the local time zone. If the date
743     * was April 30, for example, and the date is set to 31, then it
744     * will be treated as if it were on May 1, because April has only
745     * 30 days.
746     *
747     * @param   date   the day of the month value between 1-31.
748     * @see     java.util.Calendar
749     * @deprecated As of JDK version 1.1,
750     * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
751     */
752    @Deprecated
753    public void setDate(int date) {
754        getCalendarDate().setDayOfMonth(date);
755    }
756
757    /**
758     * Returns the day of the week represented by this date. The
759     * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
760     * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
761     * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
762     * represents the day of the week that contains or begins with
763     * the instant in time represented by this <tt>Date</tt> object,
764     * as interpreted in the local time zone.
765     *
766     * @return  the day of the week represented by this date.
767     * @see     java.util.Calendar
768     * @deprecated As of JDK version 1.1,
769     * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
770     */
771    @Deprecated
772    public int getDay() {
773        return normalize().getDayOfWeek() - gcal.SUNDAY;
774    }
775
776    /**
777     * Returns the hour represented by this <tt>Date</tt> object. The
778     * returned value is a number (<tt>0</tt> through <tt>23</tt>)
779     * representing the hour within the day that contains or begins
780     * with the instant in time represented by this <tt>Date</tt>
781     * object, as interpreted in the local time zone.
782     *
783     * @return  the hour represented by this date.
784     * @see     java.util.Calendar
785     * @deprecated As of JDK version 1.1,
786     * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
787     */
788    @Deprecated
789    public int getHours() {
790        return normalize().getHours();
791    }
792
793    /**
794     * Sets the hour of this <tt>Date</tt> object to the specified value.
795     * This <tt>Date</tt> object is modified so that it represents a point
796     * in time within the specified hour of the day, with the year, month,
797     * date, minute, and second the same as before, as interpreted in the
798     * local time zone.
799     *
800     * @param   hours   the hour value.
801     * @see     java.util.Calendar
802     * @deprecated As of JDK version 1.1,
803     * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
804     */
805    @Deprecated
806    public void setHours(int hours) {
807        getCalendarDate().setHours(hours);
808    }
809
810    /**
811     * Returns the number of minutes past the hour represented by this date,
812     * as interpreted in the local time zone.
813     * The value returned is between <code>0</code> and <code>59</code>.
814     *
815     * @return  the number of minutes past the hour represented by this date.
816     * @see     java.util.Calendar
817     * @deprecated As of JDK version 1.1,
818     * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
819     */
820    @Deprecated
821    public int getMinutes() {
822        return normalize().getMinutes();
823    }
824
825    /**
826     * Sets the minutes of this <tt>Date</tt> object to the specified value.
827     * This <tt>Date</tt> object is modified so that it represents a point
828     * in time within the specified minute of the hour, with the year, month,
829     * date, hour, and second the same as before, as interpreted in the
830     * local time zone.
831     *
832     * @param   minutes   the value of the minutes.
833     * @see     java.util.Calendar
834     * @deprecated As of JDK version 1.1,
835     * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
836     */
837    @Deprecated
838    public void setMinutes(int minutes) {
839        getCalendarDate().setMinutes(minutes);
840    }
841
842    /**
843     * Returns the number of seconds past the minute represented by this date.
844     * The value returned is between <code>0</code> and <code>61</code>. The
845     * values <code>60</code> and <code>61</code> can only occur on those
846     * Java Virtual Machines that take leap seconds into account.
847     *
848     * @return  the number of seconds past the minute represented by this date.
849     * @see     java.util.Calendar
850     * @deprecated As of JDK version 1.1,
851     * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
852     */
853    @Deprecated
854    public int getSeconds() {
855        return normalize().getSeconds();
856    }
857
858    /**
859     * Sets the seconds of this <tt>Date</tt> to the specified value.
860     * This <tt>Date</tt> object is modified so that it represents a
861     * point in time within the specified second of the minute, with
862     * the year, month, date, hour, and minute the same as before, as
863     * interpreted in the local time zone.
864     *
865     * @param   seconds   the seconds value.
866     * @see     java.util.Calendar
867     * @deprecated As of JDK version 1.1,
868     * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
869     */
870    @Deprecated
871    public void setSeconds(int seconds) {
872        getCalendarDate().setSeconds(seconds);
873    }
874
875    /**
876     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
877     * represented by this <tt>Date</tt> object.
878     *
879     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
880     *          represented by this date.
881     */
882    public long getTime() {
883        return getTimeImpl();
884    }
885
886    private final long getTimeImpl() {
887        if (cdate != null && !cdate.isNormalized()) {
888            normalize();
889        }
890        return fastTime;
891    }
892
893    /**
894     * Sets this <code>Date</code> object to represent a point in time that is
895     * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
896     *
897     * @param   time   the number of milliseconds.
898     */
899    public void setTime(long time) {
900        fastTime = time;
901        cdate = null;
902    }
903
904    /**
905     * Tests if this date is before the specified date.
906     *
907     * @param   when   a date.
908     * @return  <code>true</code> if and only if the instant of time
909     *            represented by this <tt>Date</tt> object is strictly
910     *            earlier than the instant represented by <tt>when</tt>;
911     *          <code>false</code> otherwise.
912     * @exception NullPointerException if <code>when</code> is null.
913     */
914    public boolean before(Date when) {
915        return getMillisOf(this) < getMillisOf(when);
916    }
917
918    /**
919     * Tests if this date is after the specified date.
920     *
921     * @param   when   a date.
922     * @return  <code>true</code> if and only if the instant represented
923     *          by this <tt>Date</tt> object is strictly later than the
924     *          instant represented by <tt>when</tt>;
925     *          <code>false</code> otherwise.
926     * @exception NullPointerException if <code>when</code> is null.
927     */
928    public boolean after(Date when) {
929        return getMillisOf(this) > getMillisOf(when);
930    }
931
932    /**
933     * Compares two dates for equality.
934     * The result is <code>true</code> if and only if the argument is
935     * not <code>null</code> and is a <code>Date</code> object that
936     * represents the same point in time, to the millisecond, as this object.
937     * <p>
938     * Thus, two <code>Date</code> objects are equal if and only if the
939     * <code>getTime</code> method returns the same <code>long</code>
940     * value for both.
941     *
942     * @param   obj   the object to compare with.
943     * @return  <code>true</code> if the objects are the same;
944     *          <code>false</code> otherwise.
945     * @see     java.util.Date#getTime()
946     */
947    public boolean equals(Object obj) {
948        return obj instanceof Date && getTime() == ((Date) obj).getTime();
949    }
950
951    /**
952     * Returns the millisecond value of this <code>Date</code> object
953     * without affecting its internal state.
954     */
955    static final long getMillisOf(Date date) {
956        if (date.cdate == null || date.cdate.isNormalized()) {
957            return date.fastTime;
958        }
959        BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
960        return gcal.getTime(d);
961    }
962
963    /**
964     * Compares two Dates for ordering.
965     *
966     * @param   anotherDate   the <code>Date</code> to be compared.
967     * @return  the value <code>0</code> if the argument Date is equal to
968     *          this Date; a value less than <code>0</code> if this Date
969     *          is before the Date argument; and a value greater than
970     *      <code>0</code> if this Date is after the Date argument.
971     * @since   1.2
972     * @exception NullPointerException if <code>anotherDate</code> is null.
973     */
974    public int compareTo(Date anotherDate) {
975        long thisTime = getMillisOf(this);
976        long anotherTime = getMillisOf(anotherDate);
977        return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
978    }
979
980    /**
981     * Returns a hash code value for this object. The result is the
982     * exclusive OR of the two halves of the primitive <tt>long</tt>
983     * value returned by the {@link Date#getTime}
984     * method. That is, the hash code is the value of the expression:
985     * <blockquote><pre>
986     * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
987     *
988     * @return  a hash code value for this object.
989     */
990    public int hashCode() {
991        long ht = this.getTime();
992        return (int) ht ^ (int) (ht >> 32);
993    }
994
995    /**
996     * Converts this <code>Date</code> object to a <code>String</code>
997     * of the form:
998     * <blockquote><pre>
999     * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
1000     * where:<ul>
1001     * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
1002     *     Thu, Fri, Sat</tt>).
1003     * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
1004     *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
1005     * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
1006     *     <tt>31</tt>), as two decimal digits.
1007     * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
1008     *     <tt>23</tt>), as two decimal digits.
1009     * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
1010     *     <tt>59</tt>), as two decimal digits.
1011     * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
1012     *     <tt>61</tt>, as two decimal digits.
1013     * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
1014     *     time). Standard time zone abbreviations include those
1015     *     recognized by the method <tt>parse</tt>. If time zone
1016     *     information is not available, then <tt>zzz</tt> is empty -
1017     *     that is, it consists of no characters at all.
1018     * <li><tt>yyyy</tt> is the year, as four decimal digits.
1019     * </ul>
1020     *
1021     * @return  a string representation of this date.
1022     * @see     java.util.Date#toLocaleString()
1023     * @see     java.util.Date#toGMTString()
1024     */
1025    public String toString() {
1026        // "EEE MMM dd HH:mm:ss zzz yyyy";
1027        BaseCalendar.Date date = normalize();
1028        StringBuilder sb = new StringBuilder(28);
1029        int index = date.getDayOfWeek();
1030        if (index == gcal.SUNDAY) {
1031            index = 8;
1032        }
1033        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
1034        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
1035        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
1036
1037        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
1038        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
1039        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
1040        TimeZone zi = date.getZone();
1041        if (zi != null) {
1042            sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
1043        } else {
1044            sb.append("GMT");
1045        }
1046        sb.append(' ').append(date.getYear());  // yyyy
1047        return sb.toString();
1048    }
1049
1050    /**
1051     * Converts the given name to its 3-letter abbreviation (e.g.,
1052     * "monday" -> "Mon") and stored the abbreviation in the given
1053     * <code>StringBuilder</code>.
1054     */
1055    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
1056        sb.append(Character.toUpperCase(name.charAt(0)));
1057        sb.append(name.charAt(1)).append(name.charAt(2));
1058        return sb;
1059    }
1060
1061    /**
1062     * Creates a string representation of this <tt>Date</tt> object in an
1063     * implementation-dependent form. The intent is that the form should
1064     * be familiar to the user of the Java application, wherever it may
1065     * happen to be running. The intent is comparable to that of the
1066     * "<code>%c</code>" format supported by the <code>strftime()</code>
1067     * function of ISO&nbsp;C.
1068     *
1069     * @return  a string representation of this date, using the locale
1070     *          conventions.
1071     * @see     java.text.DateFormat
1072     * @see     java.util.Date#toString()
1073     * @see     java.util.Date#toGMTString()
1074     * @deprecated As of JDK version 1.1,
1075     * replaced by <code>DateFormat.format(Date date)</code>.
1076     */
1077    @Deprecated
1078    public String toLocaleString() {
1079        DateFormat formatter = DateFormat.getDateTimeInstance();
1080        return formatter.format(this);
1081    }
1082
1083    /**
1084     * Creates a string representation of this <tt>Date</tt> object of
1085     * the form:
1086     * <blockquote<pre>
1087     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
1088     * where:<ul>
1089     * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
1090     *     as one or two decimal digits.
1091     * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
1092     *     Aug, Sep, Oct, Nov, Dec</tt>).
1093     * <li><i>yyyy</i> is the year, as four decimal digits.
1094     * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
1095     *     as two decimal digits.
1096     * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
1097     *     <tt>59</tt>), as two decimal digits.
1098     * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
1099     *     <tt>61</tt>), as two decimal digits.
1100     * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
1101     *     Greenwich Mean Time.
1102     * </ul><p>
1103     * The result does not depend on the local time zone.
1104     *
1105     * @return  a string representation of this date, using the Internet GMT
1106     *          conventions.
1107     * @see     java.text.DateFormat
1108     * @see     java.util.Date#toString()
1109     * @see     java.util.Date#toLocaleString()
1110     * @deprecated As of JDK version 1.1,
1111     * replaced by <code>DateFormat.format(Date date)</code>, using a
1112     * GMT <code>TimeZone</code>.
1113     */
1114    @Deprecated
1115    public String toGMTString() {
1116        // d MMM yyyy HH:mm:ss 'GMT'
1117        long t = getTime();
1118        BaseCalendar cal = getCalendarSystem(t);
1119        BaseCalendar.Date date =
1120            (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
1121        StringBuilder sb = new StringBuilder(32);
1122        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
1123        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
1124        sb.append(date.getYear()).append(' ');                            // yyyy
1125        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
1126        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
1127        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
1128        sb.append(" GMT");                                                // ' GMT'
1129        return sb.toString();
1130    }
1131
1132    /**
1133     * Returns the offset, measured in minutes, for the local time zone
1134     * relative to UTC that is appropriate for the time represented by
1135     * this <code>Date</code> object.
1136     * <p>
1137     * For example, in Massachusetts, five time zones west of Greenwich:
1138     * <blockquote><pre>
1139     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
1140     * because on February 14, 1996, standard time (Eastern Standard Time)
1141     * is in use, which is offset five hours from UTC; but:
1142     * <blockquote><pre>
1143     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
1144     * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
1145     * is in use, which is offset only four hours from UTC.<p>
1146     * This method produces the same result as if it computed:
1147     * <blockquote><pre>
1148     * (this.getTime() - UTC(this.getYear(),
1149     *                       this.getMonth(),
1150     *                       this.getDate(),
1151     *                       this.getHours(),
1152     *                       this.getMinutes(),
1153     *                       this.getSeconds())) / (60 * 1000)
1154     * </pre></blockquote>
1155     *
1156     * @return  the time-zone offset, in minutes, for the current time zone.
1157     * @see     java.util.Calendar#ZONE_OFFSET
1158     * @see     java.util.Calendar#DST_OFFSET
1159     * @see     java.util.TimeZone#getDefault
1160     * @deprecated As of JDK version 1.1,
1161     * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
1162     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
1163     */
1164    @Deprecated
1165    public int getTimezoneOffset() {
1166        int zoneOffset;
1167        if (cdate == null) {
1168            GregorianCalendar cal = new GregorianCalendar(fastTime);
1169            zoneOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET));
1170        } else {
1171            normalize();
1172            zoneOffset = cdate.getZoneOffset();
1173        }
1174        return -zoneOffset/60000;  // convert to minutes
1175    }
1176
1177    private final BaseCalendar.Date getCalendarDate() {
1178        if (cdate == null) {
1179            BaseCalendar cal = getCalendarSystem(fastTime);
1180            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
1181                                                            TimeZone.getDefaultRef());
1182        }
1183        return cdate;
1184    }
1185
1186    private final BaseCalendar.Date normalize() {
1187        if (cdate == null) {
1188            BaseCalendar cal = getCalendarSystem(fastTime);
1189            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
1190                                                            TimeZone.getDefaultRef());
1191            return cdate;
1192        }
1193
1194        // Normalize cdate with the TimeZone in cdate first. This is
1195        // required for the compatible behavior.
1196        if (!cdate.isNormalized()) {
1197            cdate = normalize(cdate);
1198        }
1199
1200        // If the default TimeZone has changed, then recalculate the
1201        // fields with the new TimeZone.
1202        TimeZone tz = TimeZone.getDefaultRef();
1203        if (tz != cdate.getZone()) {
1204            cdate.setZone(tz);
1205            CalendarSystem cal = getCalendarSystem(cdate);
1206            cal.getCalendarDate(fastTime, cdate);
1207        }
1208        return cdate;
1209    }
1210
1211    // fastTime and the returned data are in sync upon return.
1212    private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
1213        int y = date.getNormalizedYear();
1214        int m = date.getMonth();
1215        int d = date.getDayOfMonth();
1216        int hh = date.getHours();
1217        int mm = date.getMinutes();
1218        int ss = date.getSeconds();
1219        int ms = date.getMillis();
1220        TimeZone tz = date.getZone();
1221
1222        // If the specified year can't be handled using a long value
1223        // in milliseconds, GregorianCalendar is used for full
1224        // compatibility with underflow and overflow. This is required
1225        // by some JCK tests. The limits are based max year values -
1226        // years that can be represented by max values of d, hh, mm,
1227        // ss and ms. Also, let GregorianCalendar handle the default
1228        // cutover year so that we don't need to worry about the
1229        // transition here.
1230        if (y == 1582 || y > 280000000 || y < -280000000) {
1231            if (tz == null) {
1232                tz = TimeZone.getTimeZone("GMT");
1233            }
1234            GregorianCalendar gc = new GregorianCalendar(tz);
1235            gc.clear();
1236            gc.set(gc.MILLISECOND, ms);
1237            gc.set(y, m-1, d, hh, mm, ss);
1238            fastTime = gc.getTimeInMillis();
1239            BaseCalendar cal = getCalendarSystem(fastTime);
1240            date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
1241            return date;
1242        }
1243
1244        BaseCalendar cal = getCalendarSystem(y);
1245        if (cal != getCalendarSystem(date)) {
1246            date = (BaseCalendar.Date) cal.newCalendarDate(tz);
1247            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
1248        }
1249        // Perform the GregorianCalendar-style normalization.
1250        fastTime = cal.getTime(date);
1251
1252        // In case the normalized date requires the other calendar
1253        // system, we need to recalculate it using the other one.
1254        BaseCalendar ncal = getCalendarSystem(fastTime);
1255        if (ncal != cal) {
1256            date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
1257            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
1258            fastTime = ncal.getTime(date);
1259        }
1260        return date;
1261    }
1262
1263    /**
1264     * Returns the Gregorian or Julian calendar system to use with the
1265     * given date. Use Gregorian from October 15, 1582.
1266     *
1267     * @param year normalized calendar year (not -1900)
1268     * @return the CalendarSystem to use for the specified date
1269     */
1270    private static final BaseCalendar getCalendarSystem(int year) {
1271        if (year >= 1582) {
1272            return gcal;
1273        }
1274        return getJulianCalendar();
1275    }
1276
1277    private static final BaseCalendar getCalendarSystem(long utc) {
1278        // Quickly check if the time stamp given by `utc' is the Epoch
1279        // or later. If it's before 1970, we convert the cutover to
1280        // local time to compare.
1281        if (utc >= 0
1282            || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
1283                        - TimeZone.getDefaultRef().getOffset(utc)) {
1284            return gcal;
1285        }
1286        return getJulianCalendar();
1287    }
1288
1289    private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
1290        if (jcal == null) {
1291            return gcal;
1292        }
1293        if (cdate.getEra() != null) {
1294            return jcal;
1295        }
1296        return gcal;
1297    }
1298
1299    synchronized private static final BaseCalendar getJulianCalendar() {
1300        if (jcal == null) {
1301            jcal = (BaseCalendar) CalendarSystem.forName("julian");
1302        }
1303        return jcal;
1304    }
1305
1306    /**
1307     * Save the state of this object to a stream (i.e., serialize it).
1308     *
1309     * @serialData The value returned by <code>getTime()</code>
1310     *             is emitted (long).  This represents the offset from
1311     *             January 1, 1970, 00:00:00 GMT in milliseconds.
1312     */
1313    private void writeObject(ObjectOutputStream s)
1314         throws IOException
1315    {
1316        s.writeLong(getTimeImpl());
1317    }
1318
1319    /**
1320     * Reconstitute this object from a stream (i.e., deserialize it).
1321     */
1322    private void readObject(ObjectInputStream s)
1323         throws IOException, ClassNotFoundException
1324    {
1325        fastTime = s.readLong();
1326    }
1327}
1328