Home | History | Annotate | Download | only in util
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    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 
    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      */
    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      */
    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
   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
   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
   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
   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
   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
   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
   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
   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      */
   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
   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
   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
   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
   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
   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
   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
   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
   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      */
   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      */
   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
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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 
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   3395     private int internalGetEra() {
   3396         return isSet(ERA) ? internalGet(ERA) : CE;
   3397     }
   3398 
   3399     /**
   3400      * Updates internal state.
   3401      */
   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      */
   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      */
   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