GregorianCalendar.java revision 90a3721dc9454a67e1c64409782d277424d38fc3
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 1996, 2011, 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
27/*
28 * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
29 * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
30 *
31 *   The original version of this source code and documentation is copyrighted
32 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
33 * materials are provided under terms of a License Agreement between Taligent
34 * and Sun. This technology is protected by multiple US and International
35 * patents. This notice and attribution to Taligent may not be removed.
36 *   Taligent is a registered trademark of Taligent, Inc.
37 *
38 */
39
40package java.util;
41
42import java.io.IOException;
43import java.io.ObjectInputStream;
44import sun.util.calendar.BaseCalendar;
45import sun.util.calendar.CalendarDate;
46import sun.util.calendar.CalendarSystem;
47import sun.util.calendar.CalendarUtils;
48import sun.util.calendar.Era;
49import sun.util.calendar.Gregorian;
50import sun.util.calendar.JulianCalendar;
51
52/**
53 * <code>GregorianCalendar</code> is a concrete subclass of
54 * <code>Calendar</code> and provides the standard calendar system
55 * used by most of the world.
56 *
57 * <p> <code>GregorianCalendar</code> is a hybrid calendar that
58 * supports both the Julian and Gregorian calendar systems with the
59 * support of a single discontinuity, which corresponds by default to
60 * the Gregorian date when the Gregorian calendar was instituted
61 * (October 15, 1582 in some countries, later in others).  The cutover
62 * date may be changed by the caller by calling {@link
63 * #setGregorianChange(Date) setGregorianChange()}.
64 *
65 * <p>
66 * Historically, in those countries which adopted the Gregorian calendar first,
67 * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
68 * this correctly.  Before the Gregorian cutover, <code>GregorianCalendar</code>
69 * implements the Julian calendar.  The only difference between the Gregorian
70 * and the Julian calendar is the leap year rule. The Julian calendar specifies
71 * leap years every four years, whereas the Gregorian calendar omits century
72 * years which are not divisible by 400.
73 *
74 * <p>
75 * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
76 * Julian calendars. That is, dates are computed by extrapolating the current
77 * rules indefinitely far backward and forward in time. As a result,
78 * <code>GregorianCalendar</code> may be used for all years to generate
79 * meaningful and consistent results. However, dates obtained using
80 * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
81 * AD onward, when modern Julian calendar rules were adopted.  Before this date,
82 * leap year rules were applied irregularly, and before 45 BC the Julian
83 * calendar did not even exist.
84 *
85 * <p>
86 * Prior to the institution of the Gregorian calendar, New Year's Day was
87 * March 25. To avoid confusion, this calendar always uses January 1. A manual
88 * adjustment may be made if desired for dates that are prior to the Gregorian
89 * changeover and which fall between January 1 and March 24.
90 *
91 * <h4><a name="week_and_year">Week Of Year and Week Year</a></h4>
92 *
93 * <p>Values calculated for the {@link Calendar#WEEK_OF_YEAR
94 * WEEK_OF_YEAR} field range from 1 to 53. The first week of a
95 * calendar year is the earliest seven day period starting on {@link
96 * Calendar#getFirstDayOfWeek() getFirstDayOfWeek()} that contains at
97 * least {@link Calendar#getMinimalDaysInFirstWeek()
98 * getMinimalDaysInFirstWeek()} days from that year. It thus depends
99 * on the values of {@code getMinimalDaysInFirstWeek()}, {@code
100 * getFirstDayOfWeek()}, and the day of the week of January 1. Weeks
101 * between week 1 of one year and week 1 of the following year
102 * (exclusive) are numbered sequentially from 2 to 52 or 53 (except
103 * for year(s) involved in the Julian-Gregorian transition).
104 *
105 * <p>The {@code getFirstDayOfWeek()} and {@code
106 * getMinimalDaysInFirstWeek()} values are initialized using
107 * locale-dependent resources when constructing a {@code
108 * GregorianCalendar}. <a name="iso8601_compatible_setting">The week
109 * determination is compatible</a> with the ISO 8601 standard when {@code
110 * getFirstDayOfWeek()} is {@code MONDAY} and {@code
111 * getMinimalDaysInFirstWeek()} is 4, which values are used in locales
112 * where the standard is preferred. These values can explicitly be set by
113 * calling {@link Calendar#setFirstDayOfWeek(int) setFirstDayOfWeek()} and
114 * {@link Calendar#setMinimalDaysInFirstWeek(int)
115 * setMinimalDaysInFirstWeek()}.
116 *
117 * <p>A <a name="week_year"><em>week year</em></a> is in sync with a
118 * {@code WEEK_OF_YEAR} cycle. All weeks between the first and last
119 * weeks (inclusive) have the same <em>week year</em> value.
120 * Therefore, the first and last days of a week year may have
121 * different calendar year values.
122 *
123 * <p>For example, January 1, 1998 is a Thursday. If {@code
124 * getFirstDayOfWeek()} is {@code MONDAY} and {@code
125 * getMinimalDaysInFirstWeek()} is 4 (ISO 8601 standard compatible
126 * setting), then week 1 of 1998 starts on December 29, 1997, and ends
127 * on January 4, 1998. The week year is 1998 for the last three days
128 * of calendar year 1997. If, however, {@code getFirstDayOfWeek()} is
129 * {@code SUNDAY}, then week 1 of 1998 starts on January 4, 1998, and
130 * ends on January 10, 1998; the first three days of 1998 then are
131 * part of week 53 of 1997 and their week year is 1997.
132 *
133 * <h4>Week Of Month</h4>
134 *
135 * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
136 * to 6.  Week 1 of a month (the days with <code>WEEK_OF_MONTH =
137 * 1</code>) is the earliest set of at least
138 * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
139 * ending on the day before <code>getFirstDayOfWeek()</code>.  Unlike
140 * week 1 of a year, week 1 of a month may be shorter than 7 days, need
141 * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
142 * the previous month.  Days of a month before week 1 have a
143 * <code>WEEK_OF_MONTH</code> of 0.
144 *
145 * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
146 * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
147 * January 1998 is Sunday, January 4 through Saturday, January 10.  These days
148 * have a <code>WEEK_OF_MONTH</code> of 1.  Thursday, January 1 through
149 * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0.  If
150 * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
151 * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
152 *
153 * <h4>Default Fields Values</h4>
154 *
155 * <p>The <code>clear</code> method sets calendar field(s)
156 * undefined. <code>GregorianCalendar</code> uses the following
157 * default value for each calendar field if its value is undefined.
158 *
159 * <table cellpadding="0" cellspacing="3" border="0"
160 *        summary="GregorianCalendar default field values"
161 *        style="text-align: left; width: 66%;">
162 *   <tbody>
163 *     <tr>
164 *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
165 *           text-align: center;">Field<br>
166 *       </th>
167 *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
168 *           text-align: center;">Default Value<br>
169 *       </th>
170 *     </tr>
171 *     <tr>
172 *       <td style="vertical-align: middle;">
173 *              <code>ERA<br></code>
174 *       </td>
175 *       <td style="vertical-align: middle;">
176 *              <code>AD<br></code>
177 *       </td>
178 *     </tr>
179 *     <tr>
180 *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
181 *              <code>YEAR<br></code>
182 *       </td>
183 *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
184 *              <code>1970<br></code>
185 *       </td>
186 *     </tr>
187 *     <tr>
188 *       <td style="vertical-align: middle;">
189 *              <code>MONTH<br></code>
190 *       </td>
191 *       <td style="vertical-align: middle;">
192 *              <code>JANUARY<br></code>
193 *       </td>
194 *     </tr>
195 *     <tr>
196 *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
197 *              <code>DAY_OF_MONTH<br></code>
198 *       </td>
199 *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
200 *              <code>1<br></code>
201 *       </td>
202 *     </tr>
203 *     <tr>
204 *       <td style="vertical-align: middle;">
205 *              <code>DAY_OF_WEEK<br></code>
206 *       </td>
207 *       <td style="vertical-align: middle;">
208 *              <code>the first day of week<br></code>
209 *       </td>
210 *     </tr>
211 *     <tr>
212 *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
213 *              <code>WEEK_OF_MONTH<br></code>
214 *       </td>
215 *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
216 *              <code>0<br></code>
217 *       </td>
218 *     </tr>
219 *     <tr>
220 *       <td style="vertical-align: top;">
221 *              <code>DAY_OF_WEEK_IN_MONTH<br></code>
222 *       </td>
223 *       <td style="vertical-align: top;">
224 *              <code>1<br></code>
225 *       </td>
226 *     </tr>
227 *     <tr>
228 *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
229 *              <code>AM_PM<br></code>
230 *       </td>
231 *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
232 *              <code>AM<br></code>
233 *       </td>
234 *     </tr>
235 *     <tr>
236 *       <td style="vertical-align: middle;">
237 *              <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
238 *       </td>
239 *       <td style="vertical-align: middle;">
240 *              <code>0<br></code>
241 *       </td>
242 *     </tr>
243 *   </tbody>
244 * </table>
245 * <br>Default values are not applicable for the fields not listed above.
246 *
247 * <p>
248 * <strong>Example:</strong>
249 * <blockquote>
250 * <pre>
251 * // get the supported ids for GMT-08:00 (Pacific Standard Time)
252 * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
253 * // if no ids were returned, something is wrong. get out.
254 * if (ids.length == 0)
255 *     System.exit(0);
256 *
257 *  // begin output
258 * System.out.println("Current Time");
259 *
260 * // create a Pacific Standard Time time zone
261 * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
262 *
263 * // set up rules for Daylight Saving Time
264 * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
265 * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
266 *
267 * // create a GregorianCalendar with the Pacific Daylight time zone
268 * // and the current date and time
269 * Calendar calendar = new GregorianCalendar(pdt);
270 * Date trialTime = new Date();
271 * calendar.setTime(trialTime);
272 *
273 * // print out a bunch of interesting things
274 * System.out.println("ERA: " + calendar.get(Calendar.ERA));
275 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
276 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
277 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
278 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
279 * System.out.println("DATE: " + calendar.get(Calendar.DATE));
280 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
281 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
282 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
283 * System.out.println("DAY_OF_WEEK_IN_MONTH: "
284 *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
285 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
286 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
287 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
288 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
289 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
290 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
291 * System.out.println("ZONE_OFFSET: "
292 *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
293 * System.out.println("DST_OFFSET: "
294 *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
295
296 * System.out.println("Current Time, with hour reset to 3");
297 * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
298 * calendar.set(Calendar.HOUR, 3);
299 * System.out.println("ERA: " + calendar.get(Calendar.ERA));
300 * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
301 * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
302 * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
303 * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
304 * System.out.println("DATE: " + calendar.get(Calendar.DATE));
305 * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
306 * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
307 * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
308 * System.out.println("DAY_OF_WEEK_IN_MONTH: "
309 *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
310 * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
311 * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
312 * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
313 * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
314 * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
315 * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
316 * System.out.println("ZONE_OFFSET: "
317 *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
318 * System.out.println("DST_OFFSET: "
319 *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
320 * </pre>
321 * </blockquote>
322 *
323 * @see          TimeZone
324 * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
325 * @since JDK1.1
326 */
327public class GregorianCalendar extends Calendar {
328    /*
329     * Implementation Notes
330     *
331     * The epoch is the number of days or milliseconds from some defined
332     * starting point. The epoch for java.util.Date is used here; that is,
333     * milliseconds from January 1, 1970 (Gregorian), midnight UTC.  Other
334     * epochs which are used are January 1, year 1 (Gregorian), which is day 1
335     * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
336     * day 1 of the Julian calendar.
337     *
338     * We implement the proleptic Julian and Gregorian calendars.  This means we
339     * implement the modern definition of the calendar even though the
340     * historical usage differs.  For example, if the Gregorian change is set
341     * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
342     * labels dates preceding the invention of the Gregorian calendar in 1582 as
343     * if the calendar existed then.
344     *
345     * Likewise, with the Julian calendar, we assume a consistent
346     * 4-year leap year rule, even though the historical pattern of
347     * leap years is irregular, being every 3 years from 45 BCE
348     * through 9 BCE, then every 4 years from 8 CE onwards, with no
349     * leap years in-between.  Thus date computations and functions
350     * such as isLeapYear() are not intended to be historically
351     * accurate.
352     */
353
354//////////////////
355// Class Variables
356//////////////////
357
358    /**
359     * Value of the <code>ERA</code> field indicating
360     * the period before the common era (before Christ), also known as BCE.
361     * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
362     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
363     *
364     * @see #ERA
365     */
366    public static final int BC = 0;
367
368    /**
369     * Value of the {@link #ERA} field indicating
370     * the period before the common era, the same value as {@link #BC}.
371     *
372     * @see #CE
373     */
374    static final int BCE = 0;
375
376    /**
377     * Value of the <code>ERA</code> field indicating
378     * the common era (Anno Domini), also known as CE.
379     * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
380     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
381     *
382     * @see #ERA
383     */
384    public static final int AD = 1;
385
386    /**
387     * Value of the {@link #ERA} field indicating
388     * the common era, the same value as {@link #AD}.
389     *
390     * @see #BCE
391     */
392    static final int CE = 1;
393
394    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
395    private static final int EPOCH_YEAR     = 1970;
396
397    static final int MONTH_LENGTH[]
398        = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
399    static final int LEAP_MONTH_LENGTH[]
400        = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
401
402    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
403    // into ints, they must be longs in order to prevent arithmetic overflow
404    // when performing (bug 4173516).
405    private static final int  ONE_SECOND = 1000;
406    private static final int  ONE_MINUTE = 60*ONE_SECOND;
407    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
408    private static final long ONE_DAY    = 24*ONE_HOUR;
409    private static final long ONE_WEEK   = 7*ONE_DAY;
410
411    /*
412     * <pre>
413     *                            Greatest       Least
414     * Field name        Minimum   Minimum     Maximum     Maximum
415     * ----------        -------   -------     -------     -------
416     * ERA                     0         0           1           1
417     * YEAR                    1         1   292269054   292278994
418     * MONTH                   0         0          11          11
419     * WEEK_OF_YEAR            1         1          52*         53
420     * WEEK_OF_MONTH           0         0           4*          6
421     * DAY_OF_MONTH            1         1          28*         31
422     * DAY_OF_YEAR             1         1         365*        366
423     * DAY_OF_WEEK             1         1           7           7
424     * DAY_OF_WEEK_IN_MONTH   -1        -1           4*          6
425     * AM_PM                   0         0           1           1
426     * HOUR                    0         0          11          11
427     * HOUR_OF_DAY             0         0          23          23
428     * MINUTE                  0         0          59          59
429     * SECOND                  0         0          59          59
430     * MILLISECOND             0         0         999         999
431     * ZONE_OFFSET        -13:00    -13:00       14:00       14:00
432     * DST_OFFSET           0:00      0:00        0:20        2:00
433     * </pre>
434     * *: depends on the Gregorian change date
435     */
436    static final int MIN_VALUES[] = {
437        BCE,            // ERA
438        1,              // YEAR
439        JANUARY,        // MONTH
440        1,              // WEEK_OF_YEAR
441        0,              // WEEK_OF_MONTH
442        1,              // DAY_OF_MONTH
443        1,              // DAY_OF_YEAR
444        SUNDAY,         // DAY_OF_WEEK
445        1,              // DAY_OF_WEEK_IN_MONTH
446        AM,             // AM_PM
447        0,              // HOUR
448        0,              // HOUR_OF_DAY
449        0,              // MINUTE
450        0,              // SECOND
451        0,              // MILLISECOND
452        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
453        0               // DST_OFFSET
454    };
455    static final int LEAST_MAX_VALUES[] = {
456        CE,             // ERA
457        292269054,      // YEAR
458        DECEMBER,       // MONTH
459        52,             // WEEK_OF_YEAR
460        4,              // WEEK_OF_MONTH
461        28,             // DAY_OF_MONTH
462        365,            // DAY_OF_YEAR
463        SATURDAY,       // DAY_OF_WEEK
464        4,              // DAY_OF_WEEK_IN
465        PM,             // AM_PM
466        11,             // HOUR
467        23,             // HOUR_OF_DAY
468        59,             // MINUTE
469        59,             // SECOND
470        999,            // MILLISECOND
471        14*ONE_HOUR,    // ZONE_OFFSET
472        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
473    };
474    static final int MAX_VALUES[] = {
475        CE,             // ERA
476        292278994,      // YEAR
477        DECEMBER,       // MONTH
478        53,             // WEEK_OF_YEAR
479        6,              // WEEK_OF_MONTH
480        31,             // DAY_OF_MONTH
481        366,            // DAY_OF_YEAR
482        SATURDAY,       // DAY_OF_WEEK
483        6,              // DAY_OF_WEEK_IN
484        PM,             // AM_PM
485        11,             // HOUR
486        23,             // HOUR_OF_DAY
487        59,             // MINUTE
488        59,             // SECOND
489        999,            // MILLISECOND
490        14*ONE_HOUR,    // ZONE_OFFSET
491        2*ONE_HOUR      // DST_OFFSET (double summer time)
492    };
493
494    // Proclaim serialization compatibility with JDK 1.1
495    static final long serialVersionUID = -8125100834729963327L;
496
497    // Reference to the sun.util.calendar.Gregorian instance (singleton).
498    private static final Gregorian gcal =
499                                CalendarSystem.getGregorianCalendar();
500
501    // Reference to the JulianCalendar instance (singleton), set as needed. See
502    // getJulianCalendarSystem().
503    private static JulianCalendar jcal;
504
505    // JulianCalendar eras. See getJulianCalendarSystem().
506    private static Era[] jeras;
507
508    // The default value of gregorianCutover.
509    static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
510
511/////////////////////
512// Instance Variables
513/////////////////////
514
515    /**
516     * The point at which the Gregorian calendar rules are used, measured in
517     * milliseconds from the standard epoch.  Default is October 15, 1582
518     * (Gregorian) 00:00:00 UTC or -12219292800000L.  For this value, October 4,
519     * 1582 (Julian) is followed by October 15, 1582 (Gregorian).  This
520     * corresponds to Julian day number 2299161.
521     * @serial
522     */
523    private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
524
525    /**
526     * The fixed date of the gregorianCutover.
527     */
528    private transient long gregorianCutoverDate =
529        (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
530
531    /**
532     * The normalized year of the gregorianCutover in Gregorian, with
533     * 0 representing 1 BCE, -1 representing 2 BCE, etc.
534     */
535    private transient int gregorianCutoverYear = 1582;
536
537    /**
538     * The normalized year of the gregorianCutover in Julian, with 0
539     * representing 1 BCE, -1 representing 2 BCE, etc.
540     */
541    private transient int gregorianCutoverYearJulian = 1582;
542
543    /**
544     * gdate always has a sun.util.calendar.Gregorian.Date instance to
545     * avoid overhead of creating it. The assumption is that most
546     * applications will need only Gregorian calendar calculations.
547     */
548    private transient BaseCalendar.Date gdate;
549
550    /**
551     * Reference to either gdate or a JulianCalendar.Date
552     * instance. After calling complete(), this value is guaranteed to
553     * be set.
554     */
555    private transient BaseCalendar.Date cdate;
556
557    /**
558     * The CalendarSystem used to calculate the date in cdate. After
559     * calling complete(), this value is guaranteed to be set and
560     * consistent with the cdate value.
561     */
562    private transient BaseCalendar calsys;
563
564    /**
565     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
566     * the GMT offset value and zoneOffsets[1] gets the DST saving
567     * value.
568     */
569    private transient int[] zoneOffsets;
570
571    /**
572     * Temporary storage for saving original fields[] values in
573     * non-lenient mode.
574     */
575    private transient int[] originalFields;
576
577///////////////
578// Constructors
579///////////////
580
581    /**
582     * Constructs a default <code>GregorianCalendar</code> using the current time
583     * in the default time zone with the default locale.
584     */
585    public GregorianCalendar() {
586        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
587        setZoneShared(true);
588    }
589
590    /**
591     * Constructs a <code>GregorianCalendar</code> based on the current time
592     * in the given time zone with the default locale.
593     *
594     * @param zone the given time zone.
595     */
596    public GregorianCalendar(TimeZone zone) {
597        this(zone, Locale.getDefault(Locale.Category.FORMAT));
598    }
599
600    /**
601     * Constructs a <code>GregorianCalendar</code> based on the current time
602     * in the default time zone with the given locale.
603     *
604     * @param aLocale the given locale.
605     */
606    public GregorianCalendar(Locale aLocale) {
607        this(TimeZone.getDefaultRef(), aLocale);
608        setZoneShared(true);
609    }
610
611    /**
612     * Constructs a <code>GregorianCalendar</code> based on the current time
613     * in the given time zone with the given locale.
614     *
615     * @param zone the given time zone.
616     * @param aLocale the given locale.
617     */
618    public GregorianCalendar(TimeZone zone, Locale aLocale) {
619        super(zone, aLocale);
620        gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
621        setTimeInMillis(System.currentTimeMillis());
622    }
623
624    /**
625     * Constructs a <code>GregorianCalendar</code> with the given date set
626     * in the default time zone with the default locale.
627     *
628     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
629     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
630     * Month value is 0-based. e.g., 0 for January.
631     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
632     */
633    public GregorianCalendar(int year, int month, int dayOfMonth) {
634        this(year, month, dayOfMonth, 0, 0, 0, 0);
635    }
636
637    /**
638     * Constructs a <code>GregorianCalendar</code> with the given date
639     * and time set for the default time zone with the default locale.
640     *
641     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
642     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
643     * Month value is 0-based. e.g., 0 for January.
644     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
645     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
646     * in the calendar.
647     * @param minute the value used to set the <code>MINUTE</code> calendar field
648     * in the calendar.
649     */
650    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
651                             int minute) {
652        this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
653    }
654
655    /**
656     * Constructs a GregorianCalendar with the given date
657     * and time set for the default time zone with the default locale.
658     *
659     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
660     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
661     * Month value is 0-based. e.g., 0 for January.
662     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
663     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
664     * in the calendar.
665     * @param minute the value used to set the <code>MINUTE</code> calendar field
666     * in the calendar.
667     * @param second the value used to set the <code>SECOND</code> calendar field
668     * in the calendar.
669     */
670    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
671                             int minute, int second) {
672        this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
673    }
674
675    /**
676     * Constructs a <code>GregorianCalendar</code> with the given date
677     * and time set for the default time zone with the default locale.
678     *
679     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
680     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
681     * Month value is 0-based. e.g., 0 for January.
682     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
683     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
684     * in the calendar.
685     * @param minute the value used to set the <code>MINUTE</code> calendar field
686     * in the calendar.
687     * @param second the value used to set the <code>SECOND</code> calendar field
688     * in the calendar.
689     * @param millis the value used to set the <code>MILLISECOND</code> calendar field
690     */
691    GregorianCalendar(int year, int month, int dayOfMonth,
692                      int hourOfDay, int minute, int second, int millis) {
693        super();
694        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
695        this.set(YEAR, year);
696        this.set(MONTH, month);
697        this.set(DAY_OF_MONTH, dayOfMonth);
698
699        // Set AM_PM and HOUR here to set their stamp values before
700        // setting HOUR_OF_DAY (6178071).
701        if (hourOfDay >= 12 && hourOfDay <= 23) {
702            // If hourOfDay is a valid PM hour, set the correct PM values
703            // so that it won't throw an exception in case it's set to
704            // non-lenient later.
705            this.internalSet(AM_PM, PM);
706            this.internalSet(HOUR, hourOfDay - 12);
707        } else {
708            // The default value for AM_PM is AM.
709            // We don't care any out of range value here for leniency.
710            this.internalSet(HOUR, hourOfDay);
711        }
712        // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
713        setFieldsComputed(HOUR_MASK|AM_PM_MASK);
714
715        this.set(HOUR_OF_DAY, hourOfDay);
716        this.set(MINUTE, minute);
717        this.set(SECOND, second);
718        // should be changed to set() when this constructor is made
719        // public.
720        this.internalSet(MILLISECOND, millis);
721    }
722
723    GregorianCalendar(long milliseconds) {
724        this();
725        setTimeInMillis(milliseconds);
726    }
727
728/////////////////
729// Public methods
730/////////////////
731
732    /**
733     * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
734     * from Julian dates to Gregorian dates occurred. Default is October 15,
735     * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
736     * <p>
737     * To obtain a pure Julian calendar, set the change date to
738     * <code>Date(Long.MAX_VALUE)</code>.  To obtain a pure Gregorian calendar,
739     * set the change date to <code>Date(Long.MIN_VALUE)</code>.
740     *
741     * @param date the given Gregorian cutover date.
742     */
743    public void setGregorianChange(Date date) {
744        long cutoverTime = date.getTime();
745        if (cutoverTime == gregorianCutover) {
746            return;
747        }
748        // Before changing the cutover date, make sure to have the
749        // time of this calendar.
750        complete();
751        setGregorianChange(cutoverTime);
752    }
753
754    private void setGregorianChange(long cutoverTime) {
755        gregorianCutover = cutoverTime;
756        gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
757                                + EPOCH_OFFSET;
758
759        // To provide the "pure" Julian calendar as advertised.
760        // Strictly speaking, the last millisecond should be a
761        // Gregorian date. However, the API doc specifies that setting
762        // the cutover date to Long.MAX_VALUE will make this calendar
763        // a pure Julian calendar. (See 4167995)
764        if (cutoverTime == Long.MAX_VALUE) {
765            gregorianCutoverDate++;
766        }
767
768        BaseCalendar.Date d = getGregorianCutoverDate();
769
770        // Set the cutover year (in the Gregorian year numbering)
771        gregorianCutoverYear = d.getYear();
772
773        BaseCalendar jcal = getJulianCalendarSystem();
774        d = (BaseCalendar.Date) jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
775        jcal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
776        gregorianCutoverYearJulian = d.getNormalizedYear();
777
778        if (time < gregorianCutover) {
779            // The field values are no longer valid under the new
780            // cutover date.
781            setUnnormalized();
782        }
783    }
784
785    /**
786     * Gets the Gregorian Calendar change date.  This is the point when the
787     * switch from Julian dates to Gregorian dates occurred. Default is
788     * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
789     * calendar.
790     *
791     * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
792     */
793    public final Date getGregorianChange() {
794        return new Date(gregorianCutover);
795    }
796
797    /**
798     * Determines if the given year is a leap year. Returns <code>true</code> if
799     * the given year is a leap year. To specify BC year numbers,
800     * <code>1 - year number</code> must be given. For example, year BC 4 is
801     * specified as -3.
802     *
803     * @param year the given year.
804     * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
805     */
806    public boolean isLeapYear(int year) {
807        if ((year & 3) != 0) {
808            return false;
809        }
810
811        if (year > gregorianCutoverYear) {
812            return (year%100 != 0) || (year%400 == 0); // Gregorian
813        }
814        if (year < gregorianCutoverYearJulian) {
815            return true; // Julian
816        }
817        boolean gregorian;
818        // If the given year is the Gregorian cutover year, we need to
819        // determine which calendar system to be applied to February in the year.
820        if (gregorianCutoverYear == gregorianCutoverYearJulian) {
821            BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
822            gregorian = d.getMonth() < BaseCalendar.MARCH;
823        } else {
824            gregorian = year == gregorianCutoverYear;
825        }
826        return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
827    }
828
829    /**
830     * Compares this <code>GregorianCalendar</code> to the specified
831     * <code>Object</code>. The result is <code>true</code> if and
832     * only if the argument is a <code>GregorianCalendar</code> object
833     * that represents the same time value (millisecond offset from
834     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
835     * <code>Calendar</code> parameters and Gregorian change date as
836     * this object.
837     *
838     * @param obj the object to compare with.
839     * @return <code>true</code> if this object is equal to <code>obj</code>;
840     * <code>false</code> otherwise.
841     * @see Calendar#compareTo(Calendar)
842     */
843    public boolean equals(Object obj) {
844        return obj instanceof GregorianCalendar &&
845            super.equals(obj) &&
846            gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
847    }
848
849    /**
850     * Generates the hash code for this <code>GregorianCalendar</code> object.
851     */
852    public int hashCode() {
853        return super.hashCode() ^ (int)gregorianCutoverDate;
854    }
855
856    /**
857     * Adds the specified (signed) amount of time to the given calendar field,
858     * based on the calendar's rules.
859     *
860     * <p><em>Add rule 1</em>. The value of <code>field</code>
861     * after the call minus the value of <code>field</code> before the
862     * call is <code>amount</code>, modulo any overflow that has occurred in
863     * <code>field</code>. Overflow occurs when a field value exceeds its
864     * range and, as a result, the next larger field is incremented or
865     * decremented and the field value is adjusted back into its range.</p>
866     *
867     * <p><em>Add rule 2</em>. If a smaller field is expected to be
868     * invariant, but it is impossible for it to be equal to its
869     * prior value because of changes in its minimum or maximum after
870     * <code>field</code> is changed, then its value is adjusted to be as close
871     * as possible to its expected value. A smaller field represents a
872     * smaller unit of time. <code>HOUR</code> is a smaller field than
873     * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
874     * that are not expected to be invariant. The calendar system
875     * determines what fields are expected to be invariant.</p>
876     *
877     * @param field the calendar field.
878     * @param amount the amount of date or time to be added to the field.
879     * @exception IllegalArgumentException if <code>field</code> is
880     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
881     * or if any calendar fields have out-of-range values in
882     * non-lenient mode.
883     */
884    public void add(int field, int amount) {
885        // If amount == 0, do nothing even the given field is out of
886        // range. This is tested by JCK.
887        if (amount == 0) {
888            return;   // Do nothing!
889        }
890
891        if (field < 0 || field >= ZONE_OFFSET) {
892            throw new IllegalArgumentException();
893        }
894
895        // Sync the time and calendar fields.
896        complete();
897
898        if (field == YEAR) {
899            int year = internalGet(YEAR);
900            if (internalGetEra() == CE) {
901                year += amount;
902                if (year > 0) {
903                    set(YEAR, year);
904                } else { // year <= 0
905                    set(YEAR, 1 - year);
906                    // if year == 0, you get 1 BCE.
907                    set(ERA, BCE);
908                }
909            }
910            else { // era == BCE
911                year -= amount;
912                if (year > 0) {
913                    set(YEAR, year);
914                } else { // year <= 0
915                    set(YEAR, 1 - year);
916                    // if year == 0, you get 1 CE
917                    set(ERA, CE);
918                }
919            }
920            pinDayOfMonth();
921        } else if (field == MONTH) {
922            int month = internalGet(MONTH) + amount;
923            int year = internalGet(YEAR);
924            int y_amount;
925
926            if (month >= 0) {
927                y_amount = month/12;
928            } else {
929                y_amount = (month+1)/12 - 1;
930            }
931            if (y_amount != 0) {
932                if (internalGetEra() == CE) {
933                    year += y_amount;
934                    if (year > 0) {
935                        set(YEAR, year);
936                    } else { // year <= 0
937                        set(YEAR, 1 - year);
938                        // if year == 0, you get 1 BCE
939                        set(ERA, BCE);
940                    }
941                }
942                else { // era == BCE
943                    year -= y_amount;
944                    if (year > 0) {
945                        set(YEAR, year);
946                    } else { // year <= 0
947                        set(YEAR, 1 - year);
948                        // if year == 0, you get 1 CE
949                        set(ERA, CE);
950                    }
951                }
952            }
953
954            if (month >= 0) {
955                set(MONTH, (int) (month % 12));
956            } else {
957                // month < 0
958                month %= 12;
959                if (month < 0) {
960                    month += 12;
961                }
962                set(MONTH, JANUARY + month);
963            }
964            pinDayOfMonth();
965        } else if (field == ERA) {
966            int era = internalGet(ERA) + amount;
967            if (era < 0) {
968                era = 0;
969            }
970            if (era > 1) {
971                era = 1;
972            }
973            set(ERA, era);
974        } else {
975            long delta = amount;
976            long timeOfDay = 0;
977            switch (field) {
978            // Handle the time fields here. Convert the given
979            // amount to milliseconds and call setTimeInMillis.
980            case HOUR:
981            case HOUR_OF_DAY:
982                delta *= 60 * 60 * 1000;        // hours to minutes
983                break;
984
985            case MINUTE:
986                delta *= 60 * 1000;             // minutes to seconds
987                break;
988
989            case SECOND:
990                delta *= 1000;                  // seconds to milliseconds
991                break;
992
993            case MILLISECOND:
994                break;
995
996            // Handle week, day and AM_PM fields which involves
997            // time zone offset change adjustment. Convert the
998            // given amount to the number of days.
999            case WEEK_OF_YEAR:
1000            case WEEK_OF_MONTH:
1001            case DAY_OF_WEEK_IN_MONTH:
1002                delta *= 7;
1003                break;
1004
1005            case DAY_OF_MONTH: // synonym of DATE
1006            case DAY_OF_YEAR:
1007            case DAY_OF_WEEK:
1008                break;
1009
1010            case AM_PM:
1011                // Convert the amount to the number of days (delta)
1012                // and +12 or -12 hours (timeOfDay).
1013                delta = amount / 2;
1014                timeOfDay = 12 * (amount % 2);
1015                break;
1016            }
1017
1018            // The time fields don't require time zone offset change
1019            // adjustment.
1020            if (field >= HOUR) {
1021                setTimeInMillis(time + delta);
1022                return;
1023            }
1024
1025            // The rest of the fields (week, day or AM_PM fields)
1026            // require time zone offset (both GMT and DST) change
1027            // adjustment.
1028
1029            // Translate the current time to the fixed date and time
1030            // of the day.
1031            long fd = getCurrentFixedDate();
1032            timeOfDay += internalGet(HOUR_OF_DAY);
1033            timeOfDay *= 60;
1034            timeOfDay += internalGet(MINUTE);
1035            timeOfDay *= 60;
1036            timeOfDay += internalGet(SECOND);
1037            timeOfDay *= 1000;
1038            timeOfDay += internalGet(MILLISECOND);
1039            if (timeOfDay >= ONE_DAY) {
1040                fd++;
1041                timeOfDay -= ONE_DAY;
1042            } else if (timeOfDay < 0) {
1043                fd--;
1044                timeOfDay += ONE_DAY;
1045            }
1046
1047            fd += delta; // fd is the expected fixed date after the calculation
1048            int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
1049            setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
1050            zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
1051            // If the time zone offset has changed, then adjust the difference.
1052            if (zoneOffset != 0) {
1053                setTimeInMillis(time + zoneOffset);
1054                long fd2 = getCurrentFixedDate();
1055                // If the adjustment has changed the date, then take
1056                // the previous one.
1057                if (fd2 != fd) {
1058                    setTimeInMillis(time - zoneOffset);
1059                }
1060            }
1061        }
1062    }
1063
1064    /**
1065     * Adds or subtracts (up/down) a single unit of time on the given time
1066     * field without changing larger fields.
1067     * <p>
1068     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1069     * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
1070     * sets the calendar to January 31, 1999.  The <code>YEAR</code> field is unchanged
1071     * because it is a larger field than <code>MONTH</code>.</p>
1072     *
1073     * @param up indicates if the value of the specified calendar field is to be
1074     * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
1075     * @exception IllegalArgumentException if <code>field</code> is
1076     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1077     * or if any calendar fields have out-of-range values in
1078     * non-lenient mode.
1079     * @see #add(int,int)
1080     * @see #set(int,int)
1081     */
1082    public void roll(int field, boolean up) {
1083        roll(field, up ? +1 : -1);
1084    }
1085
1086    /**
1087     * Adds a signed amount to the specified calendar field without changing larger fields.
1088     * A negative roll amount means to subtract from field without changing
1089     * larger fields. If the specified amount is 0, this method performs nothing.
1090     *
1091     * <p>This method calls {@link #complete()} before adding the
1092     * amount so that all the calendar fields are normalized. If there
1093     * is any calendar field having an out-of-range value in non-lenient mode, then an
1094     * <code>IllegalArgumentException</code> is thrown.
1095     *
1096     * <p>
1097     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1098     * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
1099     * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
1100     * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
1101     * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
1102     * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
1103     * is a larger field than <code>MONTH</code>.
1104     * <p>
1105     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1106     * originally set to Sunday June 6, 1999. Calling
1107     * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1108     * Tuesday June 1, 1999, whereas calling
1109     * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1110     * Sunday May 30, 1999. This is because the roll rule imposes an
1111     * additional constraint: The <code>MONTH</code> must not change when the
1112     * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
1113     * the resultant date must be between Tuesday June 1 and Saturday June
1114     * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
1115     * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
1116     * closest possible value to Sunday (where Sunday is the first day of the
1117     * week).</p>
1118     *
1119     * @param field the calendar field.
1120     * @param amount the signed amount to add to <code>field</code>.
1121     * @exception IllegalArgumentException if <code>field</code> is
1122     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1123     * or if any calendar fields have out-of-range values in
1124     * non-lenient mode.
1125     * @see #roll(int,boolean)
1126     * @see #add(int,int)
1127     * @see #set(int,int)
1128     * @since 1.2
1129     */
1130    public void roll(int field, int amount) {
1131        // If amount == 0, do nothing even the given field is out of
1132        // range. This is tested by JCK.
1133        if (amount == 0) {
1134            return;
1135        }
1136
1137        if (field < 0 || field >= ZONE_OFFSET) {
1138            throw new IllegalArgumentException();
1139        }
1140
1141        // Sync the time and calendar fields.
1142        complete();
1143
1144        int min = getMinimum(field);
1145        int max = getMaximum(field);
1146
1147        switch (field) {
1148        case AM_PM:
1149        case ERA:
1150        case YEAR:
1151        case MINUTE:
1152        case SECOND:
1153        case MILLISECOND:
1154            // These fields are handled simply, since they have fixed minima
1155            // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
1156            // fields are complicated, since the range within they must roll
1157            // varies depending on the date.
1158            break;
1159
1160        case HOUR:
1161        case HOUR_OF_DAY:
1162            {
1163                int unit = max + 1; // 12 or 24 hours
1164                int h = internalGet(field);
1165                int nh = (h + amount) % unit;
1166                if (nh < 0) {
1167                    nh += unit;
1168                }
1169                time += ONE_HOUR * (nh - h);
1170
1171                // The day might have changed, which could happen if
1172                // the daylight saving time transition brings it to
1173                // the next day, although it's very unlikely. But we
1174                // have to make sure not to change the larger fields.
1175                CalendarDate d = calsys.getCalendarDate(time, getZone());
1176                if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
1177                    d.setDate(internalGet(YEAR),
1178                              internalGet(MONTH) + 1,
1179                              internalGet(DAY_OF_MONTH));
1180                    if (field == HOUR) {
1181                        assert (internalGet(AM_PM) == PM);
1182                        d.addHours(+12); // restore PM
1183                    }
1184                    time = calsys.getTime(d);
1185                }
1186                int hourOfDay = d.getHours();
1187                internalSet(field, hourOfDay % unit);
1188                if (field == HOUR) {
1189                    internalSet(HOUR_OF_DAY, hourOfDay);
1190                } else {
1191                    internalSet(AM_PM, hourOfDay / 12);
1192                    internalSet(HOUR, hourOfDay % 12);
1193                }
1194
1195                // Time zone offset and/or daylight saving might have changed.
1196                int zoneOffset = d.getZoneOffset();
1197                int saving = d.getDaylightSaving();
1198                internalSet(ZONE_OFFSET, zoneOffset - saving);
1199                internalSet(DST_OFFSET, saving);
1200                return;
1201            }
1202
1203        case MONTH:
1204            // Rolling the month involves both pinning the final value to [0, 11]
1205            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
1206            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
1207            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
1208            {
1209                if (!isCutoverYear(cdate.getNormalizedYear())) {
1210                    int mon = (internalGet(MONTH) + amount) % 12;
1211                    if (mon < 0) {
1212                        mon += 12;
1213                    }
1214                    set(MONTH, mon);
1215
1216                    // Keep the day of month in the range.  We don't want to spill over
1217                    // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
1218                    // mar3.
1219                    int monthLen = monthLength(mon);
1220                    if (internalGet(DAY_OF_MONTH) > monthLen) {
1221                        set(DAY_OF_MONTH, monthLen);
1222                    }
1223                } else {
1224                    // We need to take care of different lengths in
1225                    // year and month due to the cutover.
1226                    int yearLength = getActualMaximum(MONTH) + 1;
1227                    int mon = (internalGet(MONTH) + amount) % yearLength;
1228                    if (mon < 0) {
1229                        mon += yearLength;
1230                    }
1231                    set(MONTH, mon);
1232                    int monthLen = getActualMaximum(DAY_OF_MONTH);
1233                    if (internalGet(DAY_OF_MONTH) > monthLen) {
1234                        set(DAY_OF_MONTH, monthLen);
1235                    }
1236                }
1237                return;
1238            }
1239
1240        case WEEK_OF_YEAR:
1241            {
1242                int y = cdate.getNormalizedYear();
1243                max = getActualMaximum(WEEK_OF_YEAR);
1244                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1245                int woy = internalGet(WEEK_OF_YEAR);
1246                int value = woy + amount;
1247                if (!isCutoverYear(y)) {
1248                    // If the new value is in between min and max
1249                    // (exclusive), then we can use the value.
1250                    if (value > min && value < max) {
1251                        set(WEEK_OF_YEAR, value);
1252                        return;
1253                    }
1254                    long fd = getCurrentFixedDate();
1255                    // Make sure that the min week has the current DAY_OF_WEEK
1256                    long day1 = fd - (7 * (woy - min));
1257                    if (calsys.getYearFromFixedDate(day1) != y) {
1258                        min++;
1259                    }
1260
1261                    // Make sure the same thing for the max week
1262                    fd += 7 * (max - internalGet(WEEK_OF_YEAR));
1263                    if (calsys.getYearFromFixedDate(fd) != y) {
1264                        max--;
1265                    }
1266                    break;
1267                }
1268
1269                // Handle cutover here.
1270                long fd = getCurrentFixedDate();
1271                BaseCalendar cal;
1272                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1273                    cal = getCutoverCalendarSystem();
1274                } else if (y == gregorianCutoverYear) {
1275                    cal = gcal;
1276                } else {
1277                    cal = getJulianCalendarSystem();
1278                }
1279                long day1 = fd - (7 * (woy - min));
1280                // Make sure that the min week has the current DAY_OF_WEEK
1281                if (cal.getYearFromFixedDate(day1) != y) {
1282                    min++;
1283                }
1284
1285                // Make sure the same thing for the max week
1286                fd += 7 * (max - woy);
1287                cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
1288                if (cal.getYearFromFixedDate(fd) != y) {
1289                    max--;
1290                }
1291                // value: the new WEEK_OF_YEAR which must be converted
1292                // to month and day of month.
1293                value = getRolledValue(woy, amount, min, max) - 1;
1294                BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
1295                set(MONTH, d.getMonth() - 1);
1296                set(DAY_OF_MONTH, d.getDayOfMonth());
1297                return;
1298            }
1299
1300        case WEEK_OF_MONTH:
1301            {
1302                boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
1303                // dow: relative day of week from first day of week
1304                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
1305                if (dow < 0) {
1306                    dow += 7;
1307                }
1308
1309                long fd = getCurrentFixedDate();
1310                long month1;     // fixed date of the first day (usually 1) of the month
1311                int monthLength; // actual month length
1312                if (isCutoverYear) {
1313                    month1 = getFixedDateMonth1(cdate, fd);
1314                    monthLength = actualMonthLength();
1315                } else {
1316                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
1317                    monthLength = calsys.getMonthLength(cdate);
1318                }
1319
1320                // the first day of week of the month.
1321                long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(month1 + 6,
1322                                                                     getFirstDayOfWeek());
1323                // if the week has enough days to form a week, the
1324                // week starts from the previous month.
1325                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
1326                    monthDay1st -= 7;
1327                }
1328                max = getActualMaximum(field);
1329
1330                // value: the new WEEK_OF_MONTH value
1331                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
1332
1333                // nfd: fixed date of the rolled date
1334                long nfd = monthDay1st + value * 7 + dow;
1335
1336                // Unlike WEEK_OF_YEAR, we need to change day of week if the
1337                // nfd is out of the month.
1338                if (nfd < month1) {
1339                    nfd = month1;
1340                } else if (nfd >= (month1 + monthLength)) {
1341                    nfd = month1 + monthLength - 1;
1342                }
1343                int dayOfMonth;
1344                if (isCutoverYear) {
1345                    // If we are in the cutover year, convert nfd to
1346                    // its calendar date and use dayOfMonth.
1347                    BaseCalendar.Date d = getCalendarDate(nfd);
1348                    dayOfMonth = d.getDayOfMonth();
1349                } else {
1350                    dayOfMonth = (int)(nfd - month1) + 1;
1351                }
1352                set(DAY_OF_MONTH, dayOfMonth);
1353                return;
1354            }
1355
1356        case DAY_OF_MONTH:
1357            {
1358                if (!isCutoverYear(cdate.getNormalizedYear())) {
1359                    max = calsys.getMonthLength(cdate);
1360                    break;
1361                }
1362
1363                // Cutover year handling
1364                long fd = getCurrentFixedDate();
1365                long month1 = getFixedDateMonth1(cdate, fd);
1366                // It may not be a regular month. Convert the date and range to
1367                // the relative values, perform the roll, and
1368                // convert the result back to the rolled date.
1369                int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
1370                BaseCalendar.Date d = getCalendarDate(month1 + value);
1371                assert d.getMonth()-1 == internalGet(MONTH);
1372                set(DAY_OF_MONTH, d.getDayOfMonth());
1373                return;
1374            }
1375
1376        case DAY_OF_YEAR:
1377            {
1378                max = getActualMaximum(field);
1379                if (!isCutoverYear(cdate.getNormalizedYear())) {
1380                    break;
1381                }
1382
1383                // Handle cutover here.
1384                long fd = getCurrentFixedDate();
1385                long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
1386                int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
1387                BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
1388                set(MONTH, d.getMonth() - 1);
1389                set(DAY_OF_MONTH, d.getDayOfMonth());
1390                return;
1391            }
1392
1393        case DAY_OF_WEEK:
1394            {
1395                if (!isCutoverYear(cdate.getNormalizedYear())) {
1396                    // If the week of year is in the same year, we can
1397                    // just change DAY_OF_WEEK.
1398                    int weekOfYear = internalGet(WEEK_OF_YEAR);
1399                    if (weekOfYear > 1 && weekOfYear < 52) {
1400                        set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
1401                        max = SATURDAY;
1402                        break;
1403                    }
1404                }
1405
1406                // We need to handle it in a different way around year
1407                // boundaries and in the cutover year. Note that
1408                // changing era and year values violates the roll
1409                // rule: not changing larger calendar fields...
1410                amount %= 7;
1411                if (amount == 0) {
1412                    return;
1413                }
1414                long fd = getCurrentFixedDate();
1415                long dowFirst = calsys.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
1416                fd += amount;
1417                if (fd < dowFirst) {
1418                    fd += 7;
1419                } else if (fd >= dowFirst + 7) {
1420                    fd -= 7;
1421                }
1422                BaseCalendar.Date d = getCalendarDate(fd);
1423                set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
1424                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
1425                return;
1426            }
1427
1428        case DAY_OF_WEEK_IN_MONTH:
1429            {
1430                min = 1; // after normalized, min should be 1.
1431                if (!isCutoverYear(cdate.getNormalizedYear())) {
1432                    int dom = internalGet(DAY_OF_MONTH);
1433                    int monthLength = calsys.getMonthLength(cdate);
1434                    int lastDays = monthLength % 7;
1435                    max = monthLength / 7;
1436                    int x = (dom - 1) % 7;
1437                    if (x < lastDays) {
1438                        max++;
1439                    }
1440                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1441                    break;
1442                }
1443
1444                // Cutover year handling
1445                long fd = getCurrentFixedDate();
1446                long month1 = getFixedDateMonth1(cdate, fd);
1447                int monthLength = actualMonthLength();
1448                int lastDays = monthLength % 7;
1449                max = monthLength / 7;
1450                int x = (int)(fd - month1) % 7;
1451                if (x < lastDays) {
1452                    max++;
1453                }
1454                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
1455                fd = month1 + value * 7 + x;
1456                BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
1457                BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
1458                cal.getCalendarDateFromFixedDate(d, fd);
1459                set(DAY_OF_MONTH, d.getDayOfMonth());
1460                return;
1461            }
1462        }
1463
1464        set(field, getRolledValue(internalGet(field), amount, min, max));
1465    }
1466
1467    /**
1468     * Returns the minimum value for the given calendar field of this
1469     * <code>GregorianCalendar</code> instance. The minimum value is
1470     * defined as the smallest value returned by the {@link
1471     * Calendar#get(int) get} method for any possible time value,
1472     * taking into consideration the current values of the
1473     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1474     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1475     * {@link #getGregorianChange() getGregorianChange} and
1476     * {@link Calendar#getTimeZone() getTimeZone} methods.
1477     *
1478     * @param field the calendar field.
1479     * @return the minimum value for the given calendar field.
1480     * @see #getMaximum(int)
1481     * @see #getGreatestMinimum(int)
1482     * @see #getLeastMaximum(int)
1483     * @see #getActualMinimum(int)
1484     * @see #getActualMaximum(int)
1485     */
1486    public int getMinimum(int field) {
1487        return MIN_VALUES[field];
1488    }
1489
1490    /**
1491     * Returns the maximum value for the given calendar field of this
1492     * <code>GregorianCalendar</code> instance. The maximum value is
1493     * defined as the largest value returned by the {@link
1494     * Calendar#get(int) get} method for any possible time value,
1495     * taking into consideration the current values of the
1496     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1497     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1498     * {@link #getGregorianChange() getGregorianChange} and
1499     * {@link Calendar#getTimeZone() getTimeZone} methods.
1500     *
1501     * @param field the calendar field.
1502     * @return the maximum value for the given calendar field.
1503     * @see #getMinimum(int)
1504     * @see #getGreatestMinimum(int)
1505     * @see #getLeastMaximum(int)
1506     * @see #getActualMinimum(int)
1507     * @see #getActualMaximum(int)
1508     */
1509    public int getMaximum(int field) {
1510        switch (field) {
1511        case MONTH:
1512        case DAY_OF_MONTH:
1513        case DAY_OF_YEAR:
1514        case WEEK_OF_YEAR:
1515        case WEEK_OF_MONTH:
1516        case DAY_OF_WEEK_IN_MONTH:
1517        case YEAR:
1518            {
1519                // On or after Gregorian 200-3-1, Julian and Gregorian
1520                // calendar dates are the same or Gregorian dates are
1521                // larger (i.e., there is a "gap") after 300-3-1.
1522                if (gregorianCutoverYear > 200) {
1523                    break;
1524                }
1525                // There might be "overlapping" dates.
1526                GregorianCalendar gc = (GregorianCalendar) clone();
1527                gc.setLenient(true);
1528                gc.setTimeInMillis(gregorianCutover);
1529                int v1 = gc.getActualMaximum(field);
1530                gc.setTimeInMillis(gregorianCutover-1);
1531                int v2 = gc.getActualMaximum(field);
1532                return Math.max(MAX_VALUES[field], Math.max(v1, v2));
1533            }
1534        }
1535        return MAX_VALUES[field];
1536    }
1537
1538    /**
1539     * Returns the highest minimum value for the given calendar field
1540     * of this <code>GregorianCalendar</code> instance. The highest
1541     * minimum value is defined as the largest value returned by
1542     * {@link #getActualMinimum(int)} for any possible time value,
1543     * taking into consideration the current values of the
1544     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1545     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1546     * {@link #getGregorianChange() getGregorianChange} and
1547     * {@link Calendar#getTimeZone() getTimeZone} methods.
1548     *
1549     * @param field the calendar field.
1550     * @return the highest minimum value for the given calendar field.
1551     * @see #getMinimum(int)
1552     * @see #getMaximum(int)
1553     * @see #getLeastMaximum(int)
1554     * @see #getActualMinimum(int)
1555     * @see #getActualMaximum(int)
1556     */
1557    public int getGreatestMinimum(int field) {
1558        if (field == DAY_OF_MONTH) {
1559            BaseCalendar.Date d = getGregorianCutoverDate();
1560            long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
1561            d = getCalendarDate(mon1);
1562            return Math.max(MIN_VALUES[field], d.getDayOfMonth());
1563        }
1564        return MIN_VALUES[field];
1565    }
1566
1567    /**
1568     * Returns the lowest maximum value for the given calendar field
1569     * of this <code>GregorianCalendar</code> instance. The lowest
1570     * maximum value is defined as the smallest value returned by
1571     * {@link #getActualMaximum(int)} for any possible time value,
1572     * taking into consideration the current values of the
1573     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1574     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1575     * {@link #getGregorianChange() getGregorianChange} and
1576     * {@link Calendar#getTimeZone() getTimeZone} methods.
1577     *
1578     * @param field the calendar field
1579     * @return the lowest maximum value for the given calendar field.
1580     * @see #getMinimum(int)
1581     * @see #getMaximum(int)
1582     * @see #getGreatestMinimum(int)
1583     * @see #getActualMinimum(int)
1584     * @see #getActualMaximum(int)
1585     */
1586    public int getLeastMaximum(int field) {
1587        switch (field) {
1588        case MONTH:
1589        case DAY_OF_MONTH:
1590        case DAY_OF_YEAR:
1591        case WEEK_OF_YEAR:
1592        case WEEK_OF_MONTH:
1593        case DAY_OF_WEEK_IN_MONTH:
1594        case YEAR:
1595            {
1596                GregorianCalendar gc = (GregorianCalendar) clone();
1597                gc.setLenient(true);
1598                gc.setTimeInMillis(gregorianCutover);
1599                int v1 = gc.getActualMaximum(field);
1600                gc.setTimeInMillis(gregorianCutover-1);
1601                int v2 = gc.getActualMaximum(field);
1602                return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
1603            }
1604        }
1605        return LEAST_MAX_VALUES[field];
1606    }
1607
1608    /**
1609     * Returns the minimum value that this calendar field could have,
1610     * taking into consideration the given time value and the current
1611     * values of the
1612     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1613     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1614     * {@link #getGregorianChange() getGregorianChange} and
1615     * {@link Calendar#getTimeZone() getTimeZone} methods.
1616     *
1617     * <p>For example, if the Gregorian change date is January 10,
1618     * 1970 and the date of this <code>GregorianCalendar</code> is
1619     * January 20, 1970, the actual minimum value of the
1620     * <code>DAY_OF_MONTH</code> field is 10 because the previous date
1621     * of January 10, 1970 is December 27, 1996 (in the Julian
1622     * calendar). Therefore, December 28, 1969 to January 9, 1970
1623     * don't exist.
1624     *
1625     * @param field the calendar field
1626     * @return the minimum of the given field for the time value of
1627     * this <code>GregorianCalendar</code>
1628     * @see #getMinimum(int)
1629     * @see #getMaximum(int)
1630     * @see #getGreatestMinimum(int)
1631     * @see #getLeastMaximum(int)
1632     * @see #getActualMaximum(int)
1633     * @since 1.2
1634     */
1635    public int getActualMinimum(int field) {
1636        if (field == DAY_OF_MONTH) {
1637            GregorianCalendar gc = getNormalizedCalendar();
1638            int year = gc.cdate.getNormalizedYear();
1639            if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
1640                long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
1641                BaseCalendar.Date d = getCalendarDate(month1);
1642                return d.getDayOfMonth();
1643            }
1644        }
1645        return getMinimum(field);
1646    }
1647
1648    /**
1649     * Returns the maximum value that this calendar field could have,
1650     * taking into consideration the given time value and the current
1651     * values of the
1652     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1653     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1654     * {@link #getGregorianChange() getGregorianChange} and
1655     * {@link Calendar#getTimeZone() getTimeZone} methods.
1656     * For example, if the date of this instance is February 1, 2004,
1657     * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1658     * is 29 because 2004 is a leap year, and if the date of this
1659     * instance is February 1, 2005, it's 28.
1660     *
1661     * <p>This method calculates the maximum value of {@link
1662     * Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link
1663     * Calendar#YEAR YEAR} (calendar year) value, not the <a
1664     * href="#week_year">week year</a>. Call {@link
1665     * #getWeeksInWeekYear()} to get the maximum value of {@code
1666     * WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}.
1667     *
1668     * @param field the calendar field
1669     * @return the maximum of the given field for the time value of
1670     * this <code>GregorianCalendar</code>
1671     * @see #getMinimum(int)
1672     * @see #getMaximum(int)
1673     * @see #getGreatestMinimum(int)
1674     * @see #getLeastMaximum(int)
1675     * @see #getActualMinimum(int)
1676     * @since 1.2
1677     */
1678    public int getActualMaximum(int field) {
1679        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
1680            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
1681            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
1682        if ((fieldsForFixedMax & (1<<field)) != 0) {
1683            return getMaximum(field);
1684        }
1685
1686        GregorianCalendar gc = getNormalizedCalendar();
1687        BaseCalendar.Date date = gc.cdate;
1688        BaseCalendar cal = gc.calsys;
1689        int normalizedYear = date.getNormalizedYear();
1690
1691        int value = -1;
1692        switch (field) {
1693        case MONTH:
1694            {
1695                if (!gc.isCutoverYear(normalizedYear)) {
1696                    value = DECEMBER;
1697                    break;
1698                }
1699
1700                // January 1 of the next year may or may not exist.
1701                long nextJan1;
1702                do {
1703                    nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
1704                } while (nextJan1 < gregorianCutoverDate);
1705                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1706                cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
1707                value = d.getMonth() - 1;
1708            }
1709            break;
1710
1711        case DAY_OF_MONTH:
1712            {
1713                value = cal.getMonthLength(date);
1714                if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
1715                    break;
1716                }
1717
1718                // Handle cutover year.
1719                long fd = gc.getCurrentFixedDate();
1720                if (fd >= gregorianCutoverDate) {
1721                    break;
1722                }
1723                int monthLength = gc.actualMonthLength();
1724                long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
1725                // Convert the fixed date to its calendar date.
1726                BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
1727                value = d.getDayOfMonth();
1728            }
1729            break;
1730
1731        case DAY_OF_YEAR:
1732            {
1733                if (!gc.isCutoverYear(normalizedYear)) {
1734                    value = cal.getYearLength(date);
1735                    break;
1736                }
1737
1738                // Handle cutover year.
1739                long jan1;
1740                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1741                    BaseCalendar cocal = gc.getCutoverCalendarSystem();
1742                    jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
1743                } else if (normalizedYear == gregorianCutoverYearJulian) {
1744                    jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
1745                } else {
1746                    jan1 = gregorianCutoverDate;
1747                }
1748                // January 1 of the next year may or may not exist.
1749                long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
1750                if (nextJan1 < gregorianCutoverDate) {
1751                    nextJan1 = gregorianCutoverDate;
1752                }
1753                assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
1754                                                date.getDayOfMonth(), date);
1755                assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
1756                                                date.getDayOfMonth(), date);
1757                value = (int)(nextJan1 - jan1);
1758            }
1759            break;
1760
1761        case WEEK_OF_YEAR:
1762            {
1763                if (!gc.isCutoverYear(normalizedYear)) {
1764                    // Get the day of week of January 1 of the year
1765                    CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
1766                    d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
1767                    int dayOfWeek = cal.getDayOfWeek(d);
1768                    // Normalize the day of week with the firstDayOfWeek value
1769                    dayOfWeek -= getFirstDayOfWeek();
1770                    if (dayOfWeek < 0) {
1771                        dayOfWeek += 7;
1772                    }
1773                    value = 52;
1774                    int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
1775                    if ((magic == 6) ||
1776                        (date.isLeapYear() && (magic == 5 || magic == 12))) {
1777                        value++;
1778                    }
1779                    break;
1780                }
1781
1782                if (gc == this) {
1783                    gc = (GregorianCalendar) gc.clone();
1784                }
1785                int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
1786                gc.set(DAY_OF_YEAR, maxDayOfYear);
1787                value = gc.get(WEEK_OF_YEAR);
1788                if (internalGet(YEAR) != gc.getWeekYear()) {
1789                    gc.set(DAY_OF_YEAR, maxDayOfYear - 7);
1790                    value = gc.get(WEEK_OF_YEAR);
1791                }
1792            }
1793            break;
1794
1795        case WEEK_OF_MONTH:
1796            {
1797                if (!gc.isCutoverYear(normalizedYear)) {
1798                    CalendarDate d = cal.newCalendarDate(null);
1799                    d.setDate(date.getYear(), date.getMonth(), 1);
1800                    int dayOfWeek = cal.getDayOfWeek(d);
1801                    int monthLength = cal.getMonthLength(d);
1802                    dayOfWeek -= getFirstDayOfWeek();
1803                    if (dayOfWeek < 0) {
1804                        dayOfWeek += 7;
1805                    }
1806                    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1807                    value = 3;
1808                    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1809                        value++;
1810                    }
1811                    monthLength -= nDaysFirstWeek + 7 * 3;
1812                    if (monthLength > 0) {
1813                        value++;
1814                        if (monthLength > 7) {
1815                            value++;
1816                        }
1817                    }
1818                    break;
1819                }
1820
1821                // Cutover year handling
1822                if (gc == this) {
1823                    gc = (GregorianCalendar) gc.clone();
1824                }
1825                int y = gc.internalGet(YEAR);
1826                int m = gc.internalGet(MONTH);
1827                do {
1828                    value = gc.get(WEEK_OF_MONTH);
1829                    gc.add(WEEK_OF_MONTH, +1);
1830                } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
1831            }
1832            break;
1833
1834        case DAY_OF_WEEK_IN_MONTH:
1835            {
1836                // may be in the Gregorian cutover month
1837                int ndays, dow1;
1838                int dow = date.getDayOfWeek();
1839                if (!gc.isCutoverYear(normalizedYear)) {
1840                    BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1841                    ndays = cal.getMonthLength(d);
1842                    d.setDayOfMonth(1);
1843                    cal.normalize(d);
1844                    dow1 = d.getDayOfWeek();
1845                } else {
1846                    // Let a cloned GregorianCalendar take care of the cutover cases.
1847                    if (gc == this) {
1848                        gc = (GregorianCalendar) clone();
1849                    }
1850                    ndays = gc.actualMonthLength();
1851                    gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
1852                    dow1 = gc.get(DAY_OF_WEEK);
1853                }
1854                int x = dow - dow1;
1855                if (x < 0) {
1856                    x += 7;
1857                }
1858                ndays -= x;
1859                value = (ndays + 6) / 7;
1860            }
1861            break;
1862
1863        case YEAR:
1864            /* The year computation is no different, in principle, from the
1865             * others, however, the range of possible maxima is large.  In
1866             * addition, the way we know we've exceeded the range is different.
1867             * For these reasons, we use the special case code below to handle
1868             * this field.
1869             *
1870             * The actual maxima for YEAR depend on the type of calendar:
1871             *
1872             *     Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
1873             *     Julian    = Dec  2, 292269055 BCE - Jan  3, 292272993 CE
1874             *     Hybrid    = Dec  2, 292269055 BCE - Aug 17, 292278994 CE
1875             *
1876             * We know we've exceeded the maximum when either the month, date,
1877             * time, or era changes in response to setting the year.  We don't
1878             * check for month, date, and time here because the year and era are
1879             * sufficient to detect an invalid year setting.  NOTE: If code is
1880             * added to check the month and date in the future for some reason,
1881             * Feb 29 must be allowed to shift to Mar 1 when setting the year.
1882             */
1883            {
1884                if (gc == this) {
1885                    gc = (GregorianCalendar) clone();
1886                }
1887
1888                // Calculate the millisecond offset from the beginning
1889                // of the year of this calendar and adjust the max
1890                // year value if we are beyond the limit in the max
1891                // year.
1892                long current = gc.getYearOffsetInMillis();
1893
1894                if (gc.internalGetEra() == CE) {
1895                    gc.setTimeInMillis(Long.MAX_VALUE);
1896                    value = gc.get(YEAR);
1897                    long maxEnd = gc.getYearOffsetInMillis();
1898                    if (current > maxEnd) {
1899                        value--;
1900                    }
1901                } else {
1902                    CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
1903                        gcal : getJulianCalendarSystem();
1904                    CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
1905                    long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
1906                    maxEnd *= 60;
1907                    maxEnd += d.getMinutes();
1908                    maxEnd *= 60;
1909                    maxEnd += d.getSeconds();
1910                    maxEnd *= 1000;
1911                    maxEnd += d.getMillis();
1912                    value = d.getYear();
1913                    if (value <= 0) {
1914                        assert mincal == gcal;
1915                        value = 1 - value;
1916                    }
1917                    if (current < maxEnd) {
1918                        value--;
1919                    }
1920                }
1921            }
1922            break;
1923
1924        default:
1925            throw new ArrayIndexOutOfBoundsException(field);
1926        }
1927        return value;
1928    }
1929
1930    /**
1931     * Returns the millisecond offset from the beginning of this
1932     * year. This Calendar object must have been normalized.
1933     */
1934    private final long getYearOffsetInMillis() {
1935        long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
1936        t += internalGet(HOUR_OF_DAY);
1937        t *= 60;
1938        t += internalGet(MINUTE);
1939        t *= 60;
1940        t += internalGet(SECOND);
1941        t *= 1000;
1942        return t + internalGet(MILLISECOND) -
1943            (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
1944    }
1945
1946    public Object clone()
1947    {
1948        GregorianCalendar other = (GregorianCalendar) super.clone();
1949
1950        other.gdate = (BaseCalendar.Date) gdate.clone();
1951        if (cdate != null) {
1952            if (cdate != gdate) {
1953                other.cdate = (BaseCalendar.Date) cdate.clone();
1954            } else {
1955                other.cdate = other.gdate;
1956            }
1957        }
1958        other.originalFields = null;
1959        other.zoneOffsets = null;
1960        return other;
1961    }
1962
1963    public TimeZone getTimeZone() {
1964        TimeZone zone = super.getTimeZone();
1965        // To share the zone by CalendarDates
1966        gdate.setZone(zone);
1967        if (cdate != null && cdate != gdate) {
1968            cdate.setZone(zone);
1969        }
1970        return zone;
1971    }
1972
1973    public void setTimeZone(TimeZone zone) {
1974        super.setTimeZone(zone);
1975        // To share the zone by CalendarDates
1976        gdate.setZone(zone);
1977        if (cdate != null && cdate != gdate) {
1978            cdate.setZone(zone);
1979        }
1980    }
1981
1982    /**
1983     * Returns {@code true} indicating this {@code GregorianCalendar}
1984     * supports week dates.
1985     *
1986     * @return {@code true} (always)
1987     * @see #getWeekYear()
1988     * @see #setWeekDate(int,int,int)
1989     * @see #getWeeksInWeekYear()
1990     * @since 1.7
1991     */
1992    @Override
1993    public final boolean isWeekDateSupported() {
1994        return true;
1995    }
1996
1997    /**
1998     * Returns the <a href="#week_year">week year</a> represented by this
1999     * {@code GregorianCalendar}. The dates in the weeks between 1 and the
2000     * maximum week number of the week year have the same week year value
2001     * that may be one year before or after the {@link Calendar#YEAR YEAR}
2002     * (calendar year) value.
2003     *
2004     * <p>This method calls {@link Calendar#complete()} before
2005     * calculating the week year.
2006     *
2007     * @return the week year represented by this {@code GregorianCalendar}.
2008     *         If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is
2009     *         represented by 0 or a negative number: BC 1 is 0, BC 2
2010     *         is -1, BC 3 is -2, and so on.
2011     * @throws IllegalArgumentException
2012     *         if any of the calendar fields is invalid in non-lenient mode.
2013     * @see #isWeekDateSupported()
2014     * @see #getWeeksInWeekYear()
2015     * @see Calendar#getFirstDayOfWeek()
2016     * @see Calendar#getMinimalDaysInFirstWeek()
2017     * @since 1.7
2018     */
2019    @Override
2020    public int getWeekYear() {
2021        int year = get(YEAR); // implicitly calls complete()
2022        if (internalGetEra() == BCE) {
2023            year = 1 - year;
2024        }
2025
2026        // Fast path for the Gregorian calendar years that are never
2027        // affected by the Julian-Gregorian transition
2028        if (year > gregorianCutoverYear + 1) {
2029            int weekOfYear = internalGet(WEEK_OF_YEAR);
2030            if (internalGet(MONTH) == JANUARY) {
2031                if (weekOfYear >= 52) {
2032                    --year;
2033                }
2034            } else {
2035                if (weekOfYear == 1) {
2036                    ++year;
2037                }
2038            }
2039            return year;
2040        }
2041
2042        // General (slow) path
2043        int dayOfYear = internalGet(DAY_OF_YEAR);
2044        int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
2045        int minimalDays = getMinimalDaysInFirstWeek();
2046
2047        // Quickly check the possibility of year adjustments before
2048        // cloning this GregorianCalendar.
2049        if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) {
2050            return year;
2051        }
2052
2053        // Create a clone to work on the calculation
2054        GregorianCalendar cal = (GregorianCalendar) clone();
2055        cal.setLenient(true);
2056        // Use GMT so that intermediate date calculations won't
2057        // affect the time of day fields.
2058        cal.setTimeZone(TimeZone.getTimeZone("GMT"));
2059        // Go to the first day of the year, which is usually January 1.
2060        cal.set(DAY_OF_YEAR, 1);
2061        cal.complete();
2062
2063        // Get the first day of the first day-of-week in the year.
2064        int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
2065        if (delta != 0) {
2066            if (delta < 0) {
2067                delta += 7;
2068            }
2069            cal.add(DAY_OF_YEAR, delta);
2070        }
2071        int minDayOfYear = cal.get(DAY_OF_YEAR);
2072        if (dayOfYear < minDayOfYear) {
2073            if (minDayOfYear <= minimalDays) {
2074                --year;
2075            }
2076        } else {
2077            cal.set(YEAR, year + 1);
2078            cal.set(DAY_OF_YEAR, 1);
2079            cal.complete();
2080            int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
2081            if (del != 0) {
2082                if (del < 0) {
2083                    del += 7;
2084                }
2085                cal.add(DAY_OF_YEAR, del);
2086            }
2087            minDayOfYear = cal.get(DAY_OF_YEAR) - 1;
2088            if (minDayOfYear == 0) {
2089                minDayOfYear = 7;
2090            }
2091            if (minDayOfYear >= minimalDays) {
2092                int days = maxDayOfYear - dayOfYear + 1;
2093                if (days <= (7 - minDayOfYear)) {
2094                    ++year;
2095                }
2096            }
2097        }
2098        return year;
2099    }
2100
2101    /**
2102     * Sets this {@code GregorianCalendar} to the date given by the
2103     * date specifiers - <a href="#week_year">{@code weekYear}</a>,
2104     * {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear}
2105     * follows the <a href="#week_and_year">{@code WEEK_OF_YEAR}
2106     * numbering</a>.  The {@code dayOfWeek} value must be one of the
2107     * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link
2108     * Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}.
2109     *
2110     * <p>Note that the numeric day-of-week representation differs from
2111     * the ISO 8601 standard, and that the {@code weekOfYear}
2112     * numbering is compatible with the standard when {@code
2113     * getFirstDayOfWeek()} is {@code MONDAY} and {@code
2114     * getMinimalDaysInFirstWeek()} is 4.
2115     *
2116     * <p>Unlike the {@code set} method, all of the calendar fields
2117     * and the instant of time value are calculated upon return.
2118     *
2119     * <p>If {@code weekOfYear} is out of the valid week-of-year
2120     * range in {@code weekYear}, the {@code weekYear}
2121     * and {@code weekOfYear} values are adjusted in lenient
2122     * mode, or an {@code IllegalArgumentException} is thrown in
2123     * non-lenient mode.
2124     *
2125     * @param weekYear    the week year
2126     * @param weekOfYear  the week number based on {@code weekYear}
2127     * @param dayOfWeek   the day of week value: one of the constants
2128     *                    for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field:
2129     *                    {@link Calendar#SUNDAY SUNDAY}, ...,
2130     *                    {@link Calendar#SATURDAY SATURDAY}.
2131     * @exception IllegalArgumentException
2132     *            if any of the given date specifiers is invalid,
2133     *            or if any of the calendar fields are inconsistent
2134     *            with the given date specifiers in non-lenient mode
2135     * @see GregorianCalendar#isWeekDateSupported()
2136     * @see Calendar#getFirstDayOfWeek()
2137     * @see Calendar#getMinimalDaysInFirstWeek()
2138     * @since 1.7
2139     */
2140    @Override
2141    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
2142        if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {
2143            throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek);
2144        }
2145
2146        // To avoid changing the time of day fields by date
2147        // calculations, use a clone with the GMT time zone.
2148        GregorianCalendar gc = (GregorianCalendar) clone();
2149        gc.setLenient(true);
2150        int era = gc.get(ERA);
2151        gc.clear();
2152        gc.setTimeZone(TimeZone.getTimeZone("GMT"));
2153        gc.set(ERA, era);
2154        gc.set(YEAR, weekYear);
2155        gc.set(WEEK_OF_YEAR, 1);
2156        gc.set(DAY_OF_WEEK, getFirstDayOfWeek());
2157        int days = dayOfWeek - getFirstDayOfWeek();
2158        if (days < 0) {
2159            days += 7;
2160        }
2161        days += 7 * (weekOfYear - 1);
2162        if (days != 0) {
2163            gc.add(DAY_OF_YEAR, days);
2164        } else {
2165            gc.complete();
2166        }
2167
2168        if (!isLenient() &&
2169            (gc.getWeekYear() != weekYear
2170             || gc.internalGet(WEEK_OF_YEAR) != weekOfYear
2171             || gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) {
2172            throw new IllegalArgumentException();
2173        }
2174
2175        set(ERA, gc.internalGet(ERA));
2176        set(YEAR, gc.internalGet(YEAR));
2177        set(MONTH, gc.internalGet(MONTH));
2178        set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH));
2179
2180        // to avoid throwing an IllegalArgumentException in
2181        // non-lenient, set WEEK_OF_YEAR internally
2182        internalSet(WEEK_OF_YEAR, weekOfYear);
2183        complete();
2184    }
2185
2186    /**
2187     * Returns the number of weeks in the <a href="#week_year">week year</a>
2188     * represented by this {@code GregorianCalendar}.
2189     *
2190     * <p>For example, if this {@code GregorianCalendar}'s date is
2191     * December 31, 2008 with <a href="#iso8601_compatible_setting">the ISO
2192     * 8601 compatible setting</a>, this method will return 53 for the
2193     * period: December 29, 2008 to January 3, 2010 while {@link
2194     * #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return
2195     * 52 for the period: December 31, 2007 to December 28, 2008.
2196     *
2197     * @return the number of weeks in the week year.
2198     * @see Calendar#WEEK_OF_YEAR
2199     * @see #getWeekYear()
2200     * @see #getActualMaximum(int)
2201     * @since 1.7
2202     */
2203    public int getWeeksInWeekYear() {
2204        GregorianCalendar gc = getNormalizedCalendar();
2205        int weekYear = gc.getWeekYear();
2206        if (weekYear == gc.internalGet(YEAR)) {
2207            return gc.getActualMaximum(WEEK_OF_YEAR);
2208        }
2209
2210        // Use the 2nd week for calculating the max of WEEK_OF_YEAR
2211        if (gc == this) {
2212            gc = (GregorianCalendar) gc.clone();
2213        }
2214        gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
2215        return gc.getActualMaximum(WEEK_OF_YEAR);
2216    }
2217
2218/////////////////////////////
2219// Time => Fields computation
2220/////////////////////////////
2221
2222    /**
2223     * The fixed date corresponding to gdate. If the value is
2224     * Long.MIN_VALUE, the fixed date value is unknown. Currently,
2225     * Julian calendar dates are not cached.
2226     */
2227    transient private long cachedFixedDate = Long.MIN_VALUE;
2228
2229    /**
2230     * Converts the time value (millisecond offset from the <a
2231     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
2232     * The time is <em>not</em>
2233     * recomputed first; to recompute the time, then the fields, call the
2234     * <code>complete</code> method.
2235     *
2236     * @see Calendar#complete
2237     */
2238    protected void computeFields() {
2239        int mask = 0;
2240        if (isPartiallyNormalized()) {
2241            // Determine which calendar fields need to be computed.
2242            mask = getSetStateFields();
2243            int fieldMask = ~mask & ALL_FIELDS;
2244            // We have to call computTime in case calsys == null in
2245            // order to set calsys and cdate. (6263644)
2246            if (fieldMask != 0 || calsys == null) {
2247                mask |= computeFields(fieldMask,
2248                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
2249                assert mask == ALL_FIELDS;
2250            }
2251        } else {
2252            mask = ALL_FIELDS;
2253            computeFields(mask, 0);
2254        }
2255        // After computing all the fields, set the field state to `COMPUTED'.
2256        setFieldsComputed(mask);
2257    }
2258
2259    /**
2260     * This computeFields implements the conversion from UTC
2261     * (millisecond offset from the Epoch) to calendar
2262     * field values. fieldMask specifies which fields to change the
2263     * setting state to COMPUTED, although all fields are set to
2264     * the correct values. This is required to fix 4685354.
2265     *
2266     * @param fieldMask a bit mask to specify which fields to change
2267     * the setting state.
2268     * @param tzMask a bit mask to specify which time zone offset
2269     * fields to be used for time calculations
2270     * @return a new field mask that indicates what field values have
2271     * actually been set.
2272     */
2273    private int computeFields(int fieldMask, int tzMask) {
2274        int zoneOffset = 0;
2275        TimeZone tz = getZone();
2276        if (zoneOffsets == null) {
2277            zoneOffsets = new int[2];
2278        }
2279        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
2280            zoneOffset = tz.getOffset(time);
2281            zoneOffsets[0] = tz.getRawOffset();
2282            zoneOffsets[1] = zoneOffset - zoneOffsets[0];
2283        }
2284        if (tzMask != 0) {
2285            if (isFieldSet(tzMask, ZONE_OFFSET)) {
2286                zoneOffsets[0] = internalGet(ZONE_OFFSET);
2287            }
2288            if (isFieldSet(tzMask, DST_OFFSET)) {
2289                zoneOffsets[1] = internalGet(DST_OFFSET);
2290            }
2291            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
2292        }
2293
2294        // By computing time and zoneOffset separately, we can take
2295        // the wider range of time+zoneOffset than the previous
2296        // implementation.
2297        long fixedDate = zoneOffset / ONE_DAY;
2298        int timeOfDay = zoneOffset % (int)ONE_DAY;
2299        fixedDate += time / ONE_DAY;
2300        timeOfDay += (int) (time % ONE_DAY);
2301        if (timeOfDay >= ONE_DAY) {
2302            timeOfDay -= ONE_DAY;
2303            ++fixedDate;
2304        } else {
2305            while (timeOfDay < 0) {
2306                timeOfDay += ONE_DAY;
2307                --fixedDate;
2308            }
2309        }
2310        fixedDate += EPOCH_OFFSET;
2311
2312        int era = CE;
2313        int year;
2314        if (fixedDate >= gregorianCutoverDate) {
2315            // Handle Gregorian dates.
2316            assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
2317                        : "cache control: not normalized";
2318            assert cachedFixedDate == Long.MIN_VALUE ||
2319                   gcal.getFixedDate(gdate.getNormalizedYear(),
2320                                          gdate.getMonth(),
2321                                          gdate.getDayOfMonth(), gdate)
2322                                == cachedFixedDate
2323                        : "cache control: inconsictency" +
2324                          ", cachedFixedDate=" + cachedFixedDate +
2325                          ", computed=" +
2326                          gcal.getFixedDate(gdate.getNormalizedYear(),
2327                                                 gdate.getMonth(),
2328                                                 gdate.getDayOfMonth(),
2329                                                 gdate) +
2330                          ", date=" + gdate;
2331
2332            // See if we can use gdate to avoid date calculation.
2333            if (fixedDate != cachedFixedDate) {
2334                gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
2335                cachedFixedDate = fixedDate;
2336            }
2337
2338            year = gdate.getYear();
2339            if (year <= 0) {
2340                year = 1 - year;
2341                era = BCE;
2342            }
2343            calsys = gcal;
2344            cdate = gdate;
2345            assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
2346        } else {
2347            // Handle Julian calendar dates.
2348            calsys = getJulianCalendarSystem();
2349            cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
2350            jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
2351            Era e = cdate.getEra();
2352            if (e == jeras[0]) {
2353                era = BCE;
2354            }
2355            year = cdate.getYear();
2356        }
2357
2358        // Always set the ERA and YEAR values.
2359        internalSet(ERA, era);
2360        internalSet(YEAR, year);
2361        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
2362
2363        int month =  cdate.getMonth() - 1; // 0-based
2364        int dayOfMonth = cdate.getDayOfMonth();
2365
2366        // Set the basic date fields.
2367        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
2368            != 0) {
2369            internalSet(MONTH, month);
2370            internalSet(DAY_OF_MONTH, dayOfMonth);
2371            internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
2372            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
2373        }
2374
2375        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
2376                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
2377            if (timeOfDay != 0) {
2378                int hours = timeOfDay / ONE_HOUR;
2379                internalSet(HOUR_OF_DAY, hours);
2380                internalSet(AM_PM, hours / 12); // Assume AM == 0
2381                internalSet(HOUR, hours % 12);
2382                int r = timeOfDay % ONE_HOUR;
2383                internalSet(MINUTE, r / ONE_MINUTE);
2384                r %= ONE_MINUTE;
2385                internalSet(SECOND, r / ONE_SECOND);
2386                internalSet(MILLISECOND, r % ONE_SECOND);
2387            } else {
2388                internalSet(HOUR_OF_DAY, 0);
2389                internalSet(AM_PM, AM);
2390                internalSet(HOUR, 0);
2391                internalSet(MINUTE, 0);
2392                internalSet(SECOND, 0);
2393                internalSet(MILLISECOND, 0);
2394            }
2395            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
2396                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
2397        }
2398
2399        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
2400            internalSet(ZONE_OFFSET, zoneOffsets[0]);
2401            internalSet(DST_OFFSET, zoneOffsets[1]);
2402            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
2403        }
2404
2405        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
2406            int normalizedYear = cdate.getNormalizedYear();
2407            long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
2408            int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
2409            long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
2410            int cutoverGap = 0;
2411            int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
2412            int relativeDayOfMonth = dayOfMonth - 1;
2413
2414            // If we are in the cutover year, we need some special handling.
2415            if (normalizedYear == cutoverYear) {
2416                // Need to take care of the "missing" days.
2417                if (gregorianCutoverYearJulian <= gregorianCutoverYear) {
2418                    // We need to find out where we are. The cutover
2419                    // gap could even be more than one year.  (One
2420                    // year difference in ~48667 years.)
2421                    fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
2422                    if (fixedDate >= gregorianCutoverDate) {
2423                        fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
2424                    }
2425                }
2426                int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
2427                cutoverGap = dayOfYear - realDayOfYear;
2428                dayOfYear = realDayOfYear;
2429                relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
2430            }
2431            internalSet(DAY_OF_YEAR, dayOfYear);
2432            internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
2433
2434            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
2435
2436            // The spec is to calculate WEEK_OF_YEAR in the
2437            // ISO8601-style. This creates problems, though.
2438            if (weekOfYear == 0) {
2439                // If the date belongs to the last week of the
2440                // previous year, use the week number of "12/31" of
2441                // the "previous" year. Again, if the previous year is
2442                // the Gregorian cutover year, we need to take care of
2443                // it.  Usually the previous day of January 1 is
2444                // December 31, which is not always true in
2445                // GregorianCalendar.
2446                long fixedDec31 = fixedDateJan1 - 1;
2447                long prevJan1  = fixedDateJan1 - 365;
2448                if (normalizedYear > (cutoverYear + 1)) {
2449                    if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
2450                        --prevJan1;
2451                    }
2452                } else if (normalizedYear <= gregorianCutoverYearJulian) {
2453                    if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) {
2454                        --prevJan1;
2455                    }
2456                } else {
2457                    BaseCalendar calForJan1 = calsys;
2458                    //int prevYear = normalizedYear - 1;
2459                    int prevYear = getCalendarDate(fixedDec31).getNormalizedYear();
2460                    if (prevYear == gregorianCutoverYear) {
2461                        calForJan1 = getCutoverCalendarSystem();
2462                        if (calForJan1 == jcal) {
2463                            prevJan1 = calForJan1.getFixedDate(prevYear,
2464                                                               BaseCalendar.JANUARY,
2465                                                               1,
2466                                                               null);
2467                        } else {
2468                            prevJan1 = gregorianCutoverDate;
2469                            calForJan1 = gcal;
2470                        }
2471                    } else if (prevYear <= gregorianCutoverYearJulian) {
2472                        calForJan1 = getJulianCalendarSystem();
2473                        prevJan1 = calForJan1.getFixedDate(prevYear,
2474                                                           BaseCalendar.JANUARY,
2475                                                           1,
2476                                                           null);
2477                    }
2478                }
2479                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
2480            } else {
2481                if (normalizedYear > gregorianCutoverYear ||
2482                    normalizedYear < (gregorianCutoverYearJulian - 1)) {
2483                    // Regular years
2484                    if (weekOfYear >= 52) {
2485                        long nextJan1 = fixedDateJan1 + 365;
2486                        if (cdate.isLeapYear()) {
2487                            nextJan1++;
2488                        }
2489                        long nextJan1st = calsys.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2490                                                                            getFirstDayOfWeek());
2491                        int ndays = (int)(nextJan1st - nextJan1);
2492                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
2493                            // The first days forms a week in which the date is included.
2494                            weekOfYear = 1;
2495                        }
2496                    }
2497                } else {
2498                    BaseCalendar calForJan1 = calsys;
2499                    int nextYear = normalizedYear + 1;
2500                    if (nextYear == (gregorianCutoverYearJulian + 1) &&
2501                        nextYear < gregorianCutoverYear) {
2502                        // In case the gap is more than one year.
2503                        nextYear = gregorianCutoverYear;
2504                    }
2505                    if (nextYear == gregorianCutoverYear) {
2506                        calForJan1 = getCutoverCalendarSystem();
2507                    }
2508
2509                    long nextJan1;
2510                    if (nextYear > gregorianCutoverYear
2511                        || gregorianCutoverYearJulian == gregorianCutoverYear
2512                        || nextYear == gregorianCutoverYearJulian) {
2513                        nextJan1 = calForJan1.getFixedDate(nextYear,
2514                                                           BaseCalendar.JANUARY,
2515                                                           1,
2516                                                           null);
2517                    } else {
2518                        nextJan1 = gregorianCutoverDate;
2519                        calForJan1 = gcal;
2520                    }
2521
2522                    long nextJan1st = calForJan1.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2523                                                                            getFirstDayOfWeek());
2524                    int ndays = (int)(nextJan1st - nextJan1);
2525                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
2526                        // The first days forms a week in which the date is included.
2527                        weekOfYear = 1;
2528                    }
2529                }
2530            }
2531            internalSet(WEEK_OF_YEAR, weekOfYear);
2532            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
2533            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
2534        }
2535        return mask;
2536    }
2537
2538    /**
2539     * Returns the number of weeks in a period between fixedDay1 and
2540     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
2541     * is applied to calculate the number of weeks.
2542     *
2543     * @param fixedDay1 the fixed date of the first day of the period
2544     * @param fixedDate the fixed date of the last day of the period
2545     * @return the number of weeks of the given period
2546     */
2547    private final int getWeekNumber(long fixedDay1, long fixedDate) {
2548        // We can always use `gcal' since Julian and Gregorian are the
2549        // same thing for this calculation.
2550        long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
2551                                                           getFirstDayOfWeek());
2552        int ndays = (int)(fixedDay1st - fixedDay1);
2553        assert ndays <= 7;
2554        if (ndays >= getMinimalDaysInFirstWeek()) {
2555            fixedDay1st -= 7;
2556        }
2557        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
2558        if (normalizedDayOfPeriod >= 0) {
2559            return normalizedDayOfPeriod / 7 + 1;
2560        }
2561        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
2562    }
2563
2564    /**
2565     * Converts calendar field values to the time value (millisecond
2566     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
2567     *
2568     * @exception IllegalArgumentException if any calendar fields are invalid.
2569     */
2570    protected void computeTime() {
2571        // In non-lenient mode, perform brief checking of calendar
2572        // fields which have been set externally. Through this
2573        // checking, the field values are stored in originalFields[]
2574        // to see if any of them are normalized later.
2575        if (!isLenient()) {
2576            if (originalFields == null) {
2577                originalFields = new int[FIELD_COUNT];
2578            }
2579            for (int field = 0; field < FIELD_COUNT; field++) {
2580                int value = internalGet(field);
2581                if (isExternallySet(field)) {
2582                    // Quick validation for any out of range values
2583                    if (value < getMinimum(field) || value > getMaximum(field)) {
2584                        throw new IllegalArgumentException(getFieldName(field));
2585                    }
2586                }
2587                originalFields[field] = value;
2588            }
2589        }
2590
2591        // Let the super class determine which calendar fields to be
2592        // used to calculate the time.
2593        int fieldMask = selectFields();
2594
2595        // The year defaults to the epoch start. We don't check
2596        // fieldMask for YEAR because YEAR is a mandatory field to
2597        // determine the date.
2598        int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
2599
2600        int era = internalGetEra();
2601        if (era == BCE) {
2602            year = 1 - year;
2603        } else if (era != CE) {
2604            // Even in lenient mode we disallow ERA values other than CE & BCE.
2605            // (The same normalization rule as add()/roll() could be
2606            // applied here in lenient mode. But this checking is kept
2607            // unchanged for compatibility as of 1.5.)
2608            throw new IllegalArgumentException("Invalid era");
2609        }
2610
2611        // If year is 0 or negative, we need to set the ERA value later.
2612        if (year <= 0 && !isSet(ERA)) {
2613            fieldMask |= ERA_MASK;
2614            setFieldsComputed(ERA_MASK);
2615        }
2616
2617        // Calculate the time of day. We rely on the convention that
2618        // an UNSET field has 0.
2619        long timeOfDay = 0;
2620        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
2621            timeOfDay += (long) internalGet(HOUR_OF_DAY);
2622        } else {
2623            timeOfDay += internalGet(HOUR);
2624            // The default value of AM_PM is 0 which designates AM.
2625            if (isFieldSet(fieldMask, AM_PM)) {
2626                timeOfDay += 12 * internalGet(AM_PM);
2627            }
2628        }
2629        timeOfDay *= 60;
2630        timeOfDay += internalGet(MINUTE);
2631        timeOfDay *= 60;
2632        timeOfDay += internalGet(SECOND);
2633        timeOfDay *= 1000;
2634        timeOfDay += internalGet(MILLISECOND);
2635
2636        // Convert the time of day to the number of days and the
2637        // millisecond offset from midnight.
2638        long fixedDate = timeOfDay / ONE_DAY;
2639        timeOfDay %= ONE_DAY;
2640        while (timeOfDay < 0) {
2641            timeOfDay += ONE_DAY;
2642            --fixedDate;
2643        }
2644
2645        // Calculate the fixed date since January 1, 1 (Gregorian).
2646        calculateFixedDate: {
2647            long gfd, jfd;
2648            if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
2649                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2650                if (gfd >= gregorianCutoverDate) {
2651                    fixedDate = gfd;
2652                    break calculateFixedDate;
2653                }
2654                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2655            } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
2656                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2657                if (jfd < gregorianCutoverDate) {
2658                    fixedDate = jfd;
2659                    break calculateFixedDate;
2660                }
2661                gfd = jfd;
2662            } else {
2663                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
2664                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2665            }
2666
2667            // Now we have to determine which calendar date it is.
2668
2669            // If the date is relative from the beginning of the year
2670            // in the Julian calendar, then use jfd;
2671            if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) {
2672                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
2673                    fixedDate = jfd;
2674                    break calculateFixedDate;
2675                } else if (year == gregorianCutoverYear) {
2676                    fixedDate = gfd;
2677                    break calculateFixedDate;
2678                }
2679            }
2680
2681            if (gfd >= gregorianCutoverDate) {
2682                if (jfd >= gregorianCutoverDate) {
2683                    fixedDate = gfd;
2684                } else {
2685                    // The date is in an "overlapping" period. No way
2686                    // to disambiguate it. Determine it using the
2687                    // previous date calculation.
2688                    if (calsys == gcal || calsys == null) {
2689                        fixedDate = gfd;
2690                    } else {
2691                        fixedDate = jfd;
2692                    }
2693                }
2694            } else {
2695                if (jfd < gregorianCutoverDate) {
2696                    fixedDate = jfd;
2697                } else {
2698                    // The date is in a "missing" period.
2699                    if (!isLenient()) {
2700                        throw new IllegalArgumentException("the specified date doesn't exist");
2701                    }
2702                    // Take the Julian date for compatibility, which
2703                    // will produce a Gregorian date.
2704                    fixedDate = jfd;
2705                }
2706            }
2707        }
2708
2709        // millis represents local wall-clock time in milliseconds.
2710        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
2711
2712        // Compute the time zone offset and DST offset.  There are two potential
2713        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
2714        // for discussion purposes here.
2715        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
2716        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
2717        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
2718        //    We assume standard time.
2719        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
2720        //    can be in standard or DST.  Both are valid representations (the rep
2721        //    jumps from 1:59:59 DST to 1:00:00 Std).
2722        //    Again, we assume standard time.
2723        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
2724        // or DST_OFFSET fields; then we use those fields.
2725        TimeZone zone = getZone();
2726
2727        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
2728
2729        millis = adjustForZoneAndDaylightSavingsTime(fieldMask, tzMask, millis, zone);
2730
2731        // Set this calendar's time in milliseconds
2732        time = millis;
2733
2734        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
2735
2736        if (!isLenient()) {
2737            for (int field = 0; field < FIELD_COUNT; field++) {
2738                if (!isExternallySet(field)) {
2739                    continue;
2740                }
2741                if (originalFields[field] != internalGet(field)) {
2742                    String s = originalFields[field] + " -> " + internalGet(field);
2743                    // Restore the original field values
2744                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
2745                    throw new IllegalArgumentException(getFieldName(field) + ": " + s);
2746                }
2747            }
2748        }
2749        setFieldsNormalized(mask);
2750    }
2751
2752    /**
2753     * Calculates the time in milliseconds that this calendar represents using the UTC time,
2754     * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
2755     * of what fields were explicitly set on the calendar.
2756     *
2757     * <p>A time is represented as the number of milliseconds since
2758     * <i>1st January 1970 00:00:00.000 UTC</i>.
2759     *
2760     * <p>This uses the terms {@link SimpleTimeZone#STANDARD_TIME standard time},
2761     * {@link SimpleTimeZone#WALL_TIME} wall time} and {@link SimpleTimeZone#UTC_TIME UTC time} as
2762     * used in {@link SimpleTimeZone}. Specifically:
2763     *
2764     * <dl>
2765     * <dt><b>UTC time</b></dt>
2766     * <dd>This is the time within the UTC time zone. UTC does not support DST so the UTC time,
2767     * standard time and wall time are all identical within the UTC time zone.</dd>
2768     * <dt><b>standard time</b></dt>
2769     * <dd>This is the local time within the time zone and is not affected by DST.</dd>
2770     * <dt><b>wall time</b></dt>
2771     * <dd>This is the local time within the time zone as shown on a wall clock. If the time zone
2772     * supports DST then it will be the same as <b>standard time</b> when outside DST and it will
2773     * differ (usually be an hour later) when inside DST. This is what the fields on the Calendar
2774     * represent.</dd>
2775     * </dl>
2776     *
2777     * <p>The {@code utcTimeInMillis} value supplied was calculated as if the fields represented
2778     * a standard time in the {@code UTC} time zone. It is the value that would be returned by
2779     * {@link #getTimeInMillis()} when called on this calendar if it was in UTC time zone. e.g. If
2780     * the calendar was set to say <i>2014 March 19th 13:27.53 -08:00</i> then the value of
2781     * {@code utcTimeInMillis} would be the value of {@link #getTimeInMillis()} when called on a
2782     * calendar set to <i>2014 March 19th 13:27.53 -00:00</i>, note the time zone offset is set to
2783     * 0.
2784     *
2785     * <p>To adjust from a UTC time in millis to the standard time in millis we must
2786     * <em>subtract</em> the offset from UTC. e.g. given an offset of UTC-08:00, to convert
2787     * "14:00 UTC" to "14:00 UTC-08:00" we must subtract -08:00 (i.e. add 8 hours). Another way to
2788     * think about it is that 8 hours has to elapse after 14:00 UTC before it is 14:00 UTC-08:00.
2789     *
2790     * <p>As the zone offset can depend on the time and we cannot calculate the time properly until
2791     * we know the time there is a bit of a catch-22. So, what this does is use the
2792     * {@link TimeZone#getRawOffset() raw offset} to calculate a ballpark standard time and then
2793     * uses that value to retrieve the appropriate zone and DST offsets from the time zone. They
2794     * are then used to make the final wall time calculation.
2795     *
2796     * <p>The DST offset will need clearing if the standard time is not a valid wall clock. See
2797     * {@link #adjustDstOffsetForInvalidWallClock(long, TimeZone, int)} for more information.
2798     *
2799     * @param fieldMask the set of fields that should be used to calculate the time.
2800     * @param tzMask the set of time zone related fields, i.e. {@link #ZONE_OFFSET_MASK} and
2801     * {@link #DST_OFFSET_MASK}
2802     * @param utcTimeInMillis the time in millis, calculated assuming the time zone was GMT.
2803     * @param zone the actual time zone.
2804     * @return the UTC time in millis after adjusting for zone and DST offset.
2805     */
2806    private long adjustForZoneAndDaylightSavingsTime(
2807            int fieldMask, int tzMask, long utcTimeInMillis, TimeZone zone) {
2808
2809        // The following don't actually need to be initialized because they are always set before
2810        // they are used but the compiler cannot detect that.
2811        int zoneOffset = 0;
2812        int dstOffset = 0;
2813
2814        // If either of the ZONE_OFFSET or DST_OFFSET fields are not set then get the information
2815        // from the TimeZone.
2816        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
2817            if (zoneOffsets == null) {
2818                zoneOffsets = new int[2];
2819            }
2820            int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
2821                                internalGet(ZONE_OFFSET) : zone.getRawOffset();
2822
2823            // Calculate the standard time (no DST) in the supplied zone. This is a ballpark figure
2824            // and not used in the final calculation as the offset used here may not be the same as
2825            // the actual offset the time zone requires be used for this time. This is to handle
2826            // situations like Honolulu, where its raw offset changed from GMT-10:30 to GMT-10:00
2827            // in 1947. The TimeZone always uses a raw offset of -10:00 but will return -10:30
2828            // for dates before the change over.
2829            long standardTimeInZone = utcTimeInMillis - gmtOffset;
2830
2831            // Retrieve the correct zone and DST offsets from the time zone.
2832            zone.getOffsets(standardTimeInZone, zoneOffsets);
2833            zoneOffset = zoneOffsets[0];
2834            dstOffset = zoneOffsets[1];
2835
2836            // If necessary adjust the DST offset to handle an invalid wall clock sensibly.
2837            dstOffset = adjustDstOffsetForInvalidWallClock(standardTimeInZone, zone, dstOffset);
2838        }
2839
2840        // If either ZONE_OFFSET of DST_OFFSET fields are set then get the information from the
2841        // fields, potentially overriding information from the TimeZone.
2842        if (tzMask != 0) {
2843            if (isFieldSet(tzMask, ZONE_OFFSET)) {
2844                zoneOffset = internalGet(ZONE_OFFSET);
2845            }
2846            if (isFieldSet(tzMask, DST_OFFSET)) {
2847                dstOffset = internalGet(DST_OFFSET);
2848            }
2849        }
2850
2851        // Adjust the time zone offset values to get the UTC time.
2852        long standardTimeInZone = utcTimeInMillis - zoneOffset;
2853        return standardTimeInZone - dstOffset;
2854    }
2855
2856    /**
2857     * If the supplied millis is in daylight savings time (DST) and is the result of an invalid
2858     * wall clock then adjust the DST offset to ensure sensible behavior.
2859     *
2860     * <p>When transitioning into DST, i.e. when the clocks spring forward (usually by one hour)
2861     * there is a wall clock period that is invalid, it literally doesn't exist. e.g. If clocks
2862     * go forward one hour at 02:00 on 9th March 2014 (standard time) then the wall time of
2863     * 02:00-02:59:59.999 is not a valid. The wall clock jumps straight from 01:59:59.999 to
2864     * 03:00. The following table shows the relationship between the time in millis, the standard
2865     * time and the wall time at the point of transitioning into DST. As can be seen there is no
2866     * 02:00 in the wall time.
2867     *
2868     * <pre>
2869     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h
2870     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 .....
2871     * Wall Time      - ...... 01:00 ..... 03:00 ..... 04:00 .....
2872     *                                       ^
2873     *                                 02:00 missing
2874     * </pre>
2875     *
2876     * <p>The calendar fields represent wall time. If the user sets the fields on the calendar so
2877     * that it is in that invalid period then this code attempts to do something sensible. It
2878     * treats 02:MM:SS.SSS as if it is {@code 01:MM:SS.SSS + 1 hour}. That makes sense from both
2879     * the input calendar fields perspective and from the time in millis perspective. Of course the
2880     * result of that is that when the time is formatted in that time zone that the time is
2881     * actually 03:MM:SS.SSS.
2882     *
2883     * <pre>
2884     * Wall Time      - ...... 01:00 ..... <b>02:00 .....</b> 03:00 ..... 04:00 .....
2885     * Time In Millis - ......  x+1h ..... <b> x+2h .....</b>  x+2h .....  x+3h .....
2886     * </pre>
2887     *
2888     * <p>The way that works is as follows. First the standard time is calculated and the DST
2889     * offset is determined. Then if the time is in DST (the DST offset is not 0) but it was not in
2890     * DST an hour earlier (or however long the DST offset is) then it must be in that invalid
2891     * period, in which case set the DST offset to 0. That is then subtracted from the time in
2892     * millis to produce the correct result. The following diagram illustrates the process.
2893     *
2894     * <pre>
2895     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 ..... 04:00 .....
2896     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h .....  x+4h .....
2897     * DST Offset     - ......    0h .....    1h .....    1h .....    1h .....
2898     * Adjusted DST   - ......    0h .....    <b>0h</b> .....    1h .....    1h .....
2899     * Adjusted Time  - ......  x+1h .....  x+2h .....  <b>x+2h</b> .....  <b>x+3h</b> .....
2900     * </pre>
2901     *
2902     * @return the adjusted DST offset.
2903     */
2904    private int adjustDstOffsetForInvalidWallClock(
2905            long standardTimeInZone, TimeZone zone, int dstOffset) {
2906
2907        if (dstOffset != 0) {
2908            // If applying the DST offset produces a time that is outside DST then it must be
2909            // an invalid wall clock so clear the DST offset to avoid that happening.
2910            if (!zone.inDaylightTime(new Date(standardTimeInZone - dstOffset))) {
2911                dstOffset = 0;
2912            }
2913        }
2914        return dstOffset;
2915    }
2916
2917    /**
2918     * Computes the fixed date under either the Gregorian or the
2919     * Julian calendar, using the given year and the specified calendar fields.
2920     *
2921     * @param cal the CalendarSystem to be used for the date calculation
2922     * @param year the normalized year number, with 0 indicating the
2923     * year 1 BCE, -1 indicating 2 BCE, etc.
2924     * @param fieldMask the calendar fields to be used for the date calculation
2925     * @return the fixed date
2926     * @see Calendar#selectFields
2927     */
2928    private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
2929        int month = JANUARY;
2930        if (isFieldSet(fieldMask, MONTH)) {
2931            // No need to check if MONTH has been set (no isSet(MONTH)
2932            // call) since its unset value happens to be JANUARY (0).
2933            month = internalGet(MONTH);
2934
2935            // If the month is out of range, adjust it into range
2936            if (month > DECEMBER) {
2937                year += month / 12;
2938                month %= 12;
2939            } else if (month < JANUARY) {
2940                int[] rem = new int[1];
2941                year += CalendarUtils.floorDivide(month, 12, rem);
2942                month = rem[0];
2943            }
2944        }
2945
2946        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
2947        // the first day of either `month' or January in 'year'.
2948        long fixedDate = cal.getFixedDate(year, month + 1, 1,
2949                                          cal == gcal ? gdate : null);
2950        if (isFieldSet(fieldMask, MONTH)) {
2951            // Month-based calculations
2952            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
2953                // We are on the first day of the month. Just add the
2954                // offset if DAY_OF_MONTH is set. If the isSet call
2955                // returns false, that means DAY_OF_MONTH has been
2956                // selected just because of the selected
2957                // combination. We don't need to add any since the
2958                // default value is the 1st.
2959                if (isSet(DAY_OF_MONTH)) {
2960                    // To avoid underflow with DAY_OF_MONTH-1, add
2961                    // DAY_OF_MONTH, then subtract 1.
2962                    fixedDate += internalGet(DAY_OF_MONTH);
2963                    fixedDate--;
2964                }
2965            } else {
2966                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2967                    long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2968                                                                         getFirstDayOfWeek());
2969                    // If we have enough days in the first week, then
2970                    // move to the previous week.
2971                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2972                        firstDayOfWeek -= 7;
2973                    }
2974                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2975                        firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2976                                                                        internalGet(DAY_OF_WEEK));
2977                    }
2978                    // In lenient mode, we treat days of the previous
2979                    // months as a part of the specified
2980                    // WEEK_OF_MONTH. See 4633646.
2981                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
2982                } else {
2983                    int dayOfWeek;
2984                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2985                        dayOfWeek = internalGet(DAY_OF_WEEK);
2986                    } else {
2987                        dayOfWeek = getFirstDayOfWeek();
2988                    }
2989                    // We are basing this on the day-of-week-in-month.  The only
2990                    // trickiness occurs if the day-of-week-in-month is
2991                    // negative.
2992                    int dowim;
2993                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2994                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2995                    } else {
2996                        dowim = 1;
2997                    }
2998                    if (dowim >= 0) {
2999                        fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
3000                                                                   dayOfWeek);
3001                    } else {
3002                        // Go to the first day of the next week of
3003                        // the specified week boundary.
3004                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
3005                        // Then, get the day of week date on or before the last date.
3006                        fixedDate = cal.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
3007                                                                   dayOfWeek);
3008                    }
3009                }
3010            }
3011        } else {
3012            if (year == gregorianCutoverYear && cal == gcal
3013                && fixedDate < gregorianCutoverDate
3014                && gregorianCutoverYear != gregorianCutoverYearJulian) {
3015                // January 1 of the year doesn't exist.  Use
3016                // gregorianCutoverDate as the first day of the
3017                // year.
3018                fixedDate = gregorianCutoverDate;
3019            }
3020            // We are on the first day of the year.
3021            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
3022                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
3023                fixedDate += internalGet(DAY_OF_YEAR);
3024                fixedDate--;
3025            } else {
3026                long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
3027                                                                     getFirstDayOfWeek());
3028                // If we have enough days in the first week, then move
3029                // to the previous week.
3030                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
3031                    firstDayOfWeek -= 7;
3032                }
3033                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
3034                    int dayOfWeek = internalGet(DAY_OF_WEEK);
3035                    if (dayOfWeek != getFirstDayOfWeek()) {
3036                        firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
3037                                                                        dayOfWeek);
3038                    }
3039                }
3040                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
3041            }
3042        }
3043
3044        return fixedDate;
3045    }
3046
3047    /**
3048     * Returns this object if it's normalized (all fields and time are
3049     * in sync). Otherwise, a cloned object is returned after calling
3050     * complete() in lenient mode.
3051     */
3052    private final GregorianCalendar getNormalizedCalendar() {
3053        GregorianCalendar gc;
3054        if (isFullyNormalized()) {
3055            gc = this;
3056        } else {
3057            // Create a clone and normalize the calendar fields
3058            gc = (GregorianCalendar) this.clone();
3059            gc.setLenient(true);
3060            gc.complete();
3061        }
3062        return gc;
3063    }
3064
3065    /**
3066     * Returns the Julian calendar system instance (singleton). 'jcal'
3067     * and 'jeras' are set upon the return.
3068     */
3069    synchronized private static final BaseCalendar getJulianCalendarSystem() {
3070        if (jcal == null) {
3071            jcal = (JulianCalendar) CalendarSystem.forName("julian");
3072            jeras = jcal.getEras();
3073        }
3074        return jcal;
3075    }
3076
3077    /**
3078     * Returns the calendar system for dates before the cutover date
3079     * in the cutover year. If the cutover date is January 1, the
3080     * method returns Gregorian. Otherwise, Julian.
3081     */
3082    private BaseCalendar getCutoverCalendarSystem() {
3083        if (gregorianCutoverYearJulian < gregorianCutoverYear) {
3084            return gcal;
3085        }
3086        return getJulianCalendarSystem();
3087    }
3088
3089    /**
3090     * Determines if the specified year (normalized) is the Gregorian
3091     * cutover year. This object must have been normalized.
3092     */
3093    private final boolean isCutoverYear(int normalizedYear) {
3094        int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
3095        return normalizedYear == cutoverYear;
3096    }
3097
3098    /**
3099     * Returns the fixed date of the first day of the year (usually
3100     * January 1) before the specified date.
3101     *
3102     * @param date the date for which the first day of the year is
3103     * calculated. The date has to be in the cut-over year (Gregorian
3104     * or Julian).
3105     * @param fixedDate the fixed date representation of the date
3106     */
3107    private final long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
3108        assert date.getNormalizedYear() == gregorianCutoverYear ||
3109            date.getNormalizedYear() == gregorianCutoverYearJulian;
3110        if (gregorianCutoverYear != gregorianCutoverYearJulian) {
3111            if (fixedDate >= gregorianCutoverDate) {
3112                // Dates before the cutover date don't exist
3113                // in the same (Gregorian) year. So, no
3114                // January 1 exists in the year. Use the
3115                // cutover date as the first day of the year.
3116                return gregorianCutoverDate;
3117            }
3118        }
3119        // January 1 of the normalized year should exist.
3120        BaseCalendar jcal = getJulianCalendarSystem();
3121        return jcal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
3122    }
3123
3124    /**
3125     * Returns the fixed date of the first date of the month (usually
3126     * the 1st of the month) before the specified date.
3127     *
3128     * @param date the date for which the first day of the month is
3129     * calculated. The date has to be in the cut-over year (Gregorian
3130     * or Julian).
3131     * @param fixedDate the fixed date representation of the date
3132     */
3133    private final long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
3134        assert date.getNormalizedYear() == gregorianCutoverYear ||
3135            date.getNormalizedYear() == gregorianCutoverYearJulian;
3136        BaseCalendar.Date gCutover = getGregorianCutoverDate();
3137        if (gCutover.getMonth() == BaseCalendar.JANUARY
3138            && gCutover.getDayOfMonth() == 1) {
3139            // The cutover happened on January 1.
3140            return fixedDate - date.getDayOfMonth() + 1;
3141        }
3142
3143        long fixedDateMonth1;
3144        // The cutover happened sometime during the year.
3145        if (date.getMonth() == gCutover.getMonth()) {
3146            // The cutover happened in the month.
3147            BaseCalendar.Date jLastDate = getLastJulianDate();
3148            if (gregorianCutoverYear == gregorianCutoverYearJulian
3149                && gCutover.getMonth() == jLastDate.getMonth()) {
3150                // The "gap" fits in the same month.
3151                fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
3152                                                    date.getMonth(),
3153                                                    1,
3154                                                    null);
3155            } else {
3156                // Use the cutover date as the first day of the month.
3157                fixedDateMonth1 = gregorianCutoverDate;
3158            }
3159        } else {
3160            // The cutover happened before the month.
3161            fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
3162        }
3163
3164        return fixedDateMonth1;
3165    }
3166
3167    /**
3168     * Returns a CalendarDate produced from the specified fixed date.
3169     *
3170     * @param fd the fixed date
3171     */
3172    private final BaseCalendar.Date getCalendarDate(long fd) {
3173        BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
3174        BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
3175        cal.getCalendarDateFromFixedDate(d, fd);
3176        return d;
3177    }
3178
3179    /**
3180     * Returns the Gregorian cutover date as a BaseCalendar.Date. The
3181     * date is a Gregorian date.
3182     */
3183    private final BaseCalendar.Date getGregorianCutoverDate() {
3184        return getCalendarDate(gregorianCutoverDate);
3185    }
3186
3187    /**
3188     * Returns the day before the Gregorian cutover date as a
3189     * BaseCalendar.Date. The date is a Julian date.
3190     */
3191    private final BaseCalendar.Date getLastJulianDate() {
3192        return getCalendarDate(gregorianCutoverDate - 1);
3193    }
3194
3195    /**
3196     * Returns the length of the specified month in the specified
3197     * year. The year number must be normalized.
3198     *
3199     * @see #isLeapYear(int)
3200     */
3201    private final int monthLength(int month, int year) {
3202        return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
3203    }
3204
3205    /**
3206     * Returns the length of the specified month in the year provided
3207     * by internalGet(YEAR).
3208     *
3209     * @see #isLeapYear(int)
3210     */
3211    private final int monthLength(int month) {
3212        int year = internalGet(YEAR);
3213        if (internalGetEra() == BCE) {
3214            year = 1 - year;
3215        }
3216        return monthLength(month, year);
3217    }
3218
3219    private final int actualMonthLength() {
3220        int year = cdate.getNormalizedYear();
3221        if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
3222            return calsys.getMonthLength(cdate);
3223        }
3224        BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
3225        long fd = calsys.getFixedDate(date);
3226        long month1 = getFixedDateMonth1(date, fd);
3227        long next1 = month1 + calsys.getMonthLength(date);
3228        if (next1 < gregorianCutoverDate) {
3229            return (int)(next1 - month1);
3230        }
3231        if (cdate != gdate) {
3232            date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
3233        }
3234        gcal.getCalendarDateFromFixedDate(date, next1);
3235        next1 = getFixedDateMonth1(date, next1);
3236        return (int)(next1 - month1);
3237    }
3238
3239    /**
3240     * Returns the length (in days) of the specified year. The year
3241     * must be normalized.
3242     */
3243    private final int yearLength(int year) {
3244        return isLeapYear(year) ? 366 : 365;
3245    }
3246
3247    /**
3248     * Returns the length (in days) of the year provided by
3249     * internalGet(YEAR).
3250     */
3251    private final int yearLength() {
3252        int year = internalGet(YEAR);
3253        if (internalGetEra() == BCE) {
3254            year = 1 - year;
3255        }
3256        return yearLength(year);
3257    }
3258
3259    /**
3260     * After adjustments such as add(MONTH), add(YEAR), we don't want the
3261     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
3262     * 3, we want it to go to Feb 28.  Adjustments which might run into this
3263     * problem call this method to retain the proper month.
3264     */
3265    private final void pinDayOfMonth() {
3266        int year = internalGet(YEAR);
3267        int monthLen;
3268        if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
3269            monthLen = monthLength(internalGet(MONTH));
3270        } else {
3271            GregorianCalendar gc = getNormalizedCalendar();
3272            monthLen = gc.getActualMaximum(DAY_OF_MONTH);
3273        }
3274        int dom = internalGet(DAY_OF_MONTH);
3275        if (dom > monthLen) {
3276            set(DAY_OF_MONTH, monthLen);
3277        }
3278    }
3279
3280    /**
3281     * Returns the fixed date value of this object. The time value and
3282     * calendar fields must be in synch.
3283     */
3284    private final long getCurrentFixedDate() {
3285        return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
3286    }
3287
3288    /**
3289     * Returns the new value after 'roll'ing the specified value and amount.
3290     */
3291    private static final int getRolledValue(int value, int amount, int min, int max) {
3292        assert value >= min && value <= max;
3293        int range = max - min + 1;
3294        amount %= range;
3295        int n = value + amount;
3296        if (n > max) {
3297            n -= range;
3298        } else if (n < min) {
3299            n += range;
3300        }
3301        assert n >= min && n <= max;
3302        return n;
3303    }
3304
3305    /**
3306     * Returns the ERA.  We need a special method for this because the
3307     * default ERA is CE, but a zero (unset) ERA is BCE.
3308     */
3309    private final int internalGetEra() {
3310        return isSet(ERA) ? internalGet(ERA) : CE;
3311    }
3312
3313    /**
3314     * Updates internal state.
3315     */
3316    private void readObject(ObjectInputStream stream)
3317            throws IOException, ClassNotFoundException {
3318        stream.defaultReadObject();
3319        if (gdate == null) {
3320            gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
3321            cachedFixedDate = Long.MIN_VALUE;
3322        }
3323        setGregorianChange(gregorianCutover);
3324    }
3325}
3326