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