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