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