Source Code Cross Referenced for GregorianCalendar.java in  » 6.0-JDK-Core » Collections-Jar-Zip-Logging-regex » java » util » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » Collections Jar Zip Logging regex » java.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001        /*
0002         * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004         *
0005         * This code is free software; you can redistribute it and/or modify it
0006         * under the terms of the GNU General Public License version 2 only, as
0007         * published by the Free Software Foundation.  Sun designates this
0008         * particular file as subject to the "Classpath" exception as provided
0009         * by Sun in the LICENSE file that accompanied this code.
0010         *
0011         * This code is distributed in the hope that it will be useful, but WITHOUT
0012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014         * version 2 for more details (a copy is included in the LICENSE file that
0015         * accompanied this code).
0016         *
0017         * You should have received a copy of the GNU General Public License version
0018         * 2 along with this work; if not, write to the Free Software Foundation,
0019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020         *
0021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022         * CA 95054 USA or visit www.sun.com if you need additional information or
0023         * have any questions.
0024         */
0025
0026        /*
0027         * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
0028         * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
0029         *
0030         *   The original version of this source code and documentation is copyrighted
0031         * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
0032         * materials are provided under terms of a License Agreement between Taligent
0033         * and Sun. This technology is protected by multiple US and International
0034         * patents. This notice and attribution to Taligent may not be removed.
0035         *   Taligent is a registered trademark of Taligent, Inc.
0036         *
0037         */
0038
0039        package java.util;
0040
0041        import java.io.IOException;
0042        import java.io.ObjectInputStream;
0043        import sun.util.calendar.BaseCalendar;
0044        import sun.util.calendar.CalendarDate;
0045        import sun.util.calendar.CalendarSystem;
0046        import sun.util.calendar.CalendarUtils;
0047        import sun.util.calendar.Era;
0048        import sun.util.calendar.Gregorian;
0049        import sun.util.calendar.JulianCalendar;
0050        import sun.util.calendar.ZoneInfo;
0051
0052        /**
0053         * <code>GregorianCalendar</code> is a concrete subclass of
0054         * <code>Calendar</code> and provides the standard calendar system
0055         * used by most of the world.
0056         *
0057         * <p> <code>GregorianCalendar</code> is a hybrid calendar that
0058         * supports both the Julian and Gregorian calendar systems with the
0059         * support of a single discontinuity, which corresponds by default to
0060         * the Gregorian date when the Gregorian calendar was instituted
0061         * (October 15, 1582 in some countries, later in others).  The cutover
0062         * date may be changed by the caller by calling {@link
0063         * #setGregorianChange(Date) setGregorianChange()}.
0064         *
0065         * <p>
0066         * Historically, in those countries which adopted the Gregorian calendar first,
0067         * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
0068         * this correctly.  Before the Gregorian cutover, <code>GregorianCalendar</code>
0069         * implements the Julian calendar.  The only difference between the Gregorian
0070         * and the Julian calendar is the leap year rule. The Julian calendar specifies
0071         * leap years every four years, whereas the Gregorian calendar omits century
0072         * years which are not divisible by 400.
0073         *
0074         * <p>
0075         * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
0076         * Julian calendars. That is, dates are computed by extrapolating the current
0077         * rules indefinitely far backward and forward in time. As a result,
0078         * <code>GregorianCalendar</code> may be used for all years to generate
0079         * meaningful and consistent results. However, dates obtained using
0080         * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
0081         * AD onward, when modern Julian calendar rules were adopted.  Before this date,
0082         * leap year rules were applied irregularly, and before 45 BC the Julian
0083         * calendar did not even exist.
0084         *
0085         * <p>
0086         * Prior to the institution of the Gregorian calendar, New Year's Day was
0087         * March 25. To avoid confusion, this calendar always uses January 1. A manual
0088         * adjustment may be made if desired for dates that are prior to the Gregorian
0089         * changeover and which fall between January 1 and March 24.
0090         *
0091         * <p>Values calculated for the <code>WEEK_OF_YEAR</code> field range from 1 to
0092         * 53.  Week 1 for a year is the earliest seven day period starting on
0093         * <code>getFirstDayOfWeek()</code> that contains at least
0094         * <code>getMinimalDaysInFirstWeek()</code> days from that year.  It thus
0095         * depends on the values of <code>getMinimalDaysInFirstWeek()</code>,
0096         * <code>getFirstDayOfWeek()</code>, and the day of the week of January 1.
0097         * Weeks between week 1 of one year and week 1 of the following year are
0098         * numbered sequentially from 2 to 52 or 53 (as needed).
0099
0100         * <p>For example, January 1, 1998 was a Thursday.  If
0101         * <code>getFirstDayOfWeek()</code> is <code>MONDAY</code> and
0102         * <code>getMinimalDaysInFirstWeek()</code> is 4 (these are the values
0103         * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts
0104         * on December 29, 1997, and ends on January 4, 1998.  If, however,
0105         * <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>, then week 1 of 1998
0106         * starts on January 4, 1998, and ends on January 10, 1998; the first three days
0107         * of 1998 then are part of week 53 of 1997.
0108         *
0109         * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
0110         * to 6.  Week 1 of a month (the days with <code>WEEK_OF_MONTH =
0111         * 1</code>) is the earliest set of at least
0112         * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
0113         * ending on the day before <code>getFirstDayOfWeek()</code>.  Unlike
0114         * week 1 of a year, week 1 of a month may be shorter than 7 days, need
0115         * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
0116         * the previous month.  Days of a month before week 1 have a
0117         * <code>WEEK_OF_MONTH</code> of 0.
0118         *
0119         * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
0120         * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
0121         * January 1998 is Sunday, January 4 through Saturday, January 10.  These days
0122         * have a <code>WEEK_OF_MONTH</code> of 1.  Thursday, January 1 through
0123         * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0.  If
0124         * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
0125         * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
0126         *
0127         * <p>The <code>clear</code> methods set calendar field(s)
0128         * undefined. <code>GregorianCalendar</code> uses the following
0129         * default value for each calendar field if its value is undefined.
0130         *
0131         * <table cellpadding="0" cellspacing="3" border="0"
0132         *	  summary="GregorianCalendar default field values" 
0133         *	  style="text-align: left; width: 66%;">
0134         *   <tbody>
0135         *     <tr>
0136         *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
0137         *	     text-align: center;">Field<br>
0138         *       </th>
0139         *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
0140         *	     text-align: center;">Default Value<br>
0141         *       </th>
0142         *     </tr>
0143         *     <tr>
0144         *       <td style="vertical-align: middle;">
0145         *		<code>ERA<br></code>
0146         *	 </td>
0147         *       <td style="vertical-align: middle;">
0148         *		<code>AD<br></code>
0149         *	 </td>
0150         *     </tr>
0151         *     <tr>
0152         *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0153         *		<code>YEAR<br></code>
0154         *	 </td>
0155         *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0156         *		<code>1970<br></code>
0157         *	 </td>
0158         *     </tr>
0159         *     <tr>
0160         *       <td style="vertical-align: middle;">
0161         *		<code>MONTH<br></code>
0162         *	 </td>
0163         *       <td style="vertical-align: middle;">
0164         *		<code>JANUARY<br></code>
0165         *	 </td>
0166         *     </tr>
0167         *     <tr>
0168         *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0169         *		<code>DAY_OF_MONTH<br></code>
0170         *	 </td>
0171         *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0172         *		<code>1<br></code>
0173         *	 </td>
0174         *     </tr>
0175         *     <tr>
0176         *       <td style="vertical-align: middle;">
0177         *		<code>DAY_OF_WEEK<br></code>
0178         *	 </td>
0179         *       <td style="vertical-align: middle;">
0180         *		<code>the first day of week<br></code>
0181         *	 </td>
0182         *     </tr>
0183         *     <tr>
0184         *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0185         *		<code>WEEK_OF_MONTH<br></code>
0186         *       </td>
0187         *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
0188         *		<code>0<br></code>
0189         *       </td>
0190         *     </tr>
0191         *     <tr>
0192         *       <td style="vertical-align: top;">
0193         *		<code>DAY_OF_WEEK_IN_MONTH<br></code>
0194         *       </td>
0195         *       <td style="vertical-align: top;">
0196         *		<code>1<br></code>
0197         *       </td>
0198         *     </tr>
0199         *     <tr>
0200         *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0201         *		<code>AM_PM<br></code>
0202         *       </td>
0203         *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
0204         *		<code>AM<br></code>
0205         *       </td>
0206         *     </tr>
0207         *     <tr>
0208         *       <td style="vertical-align: middle;">
0209         *		<code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
0210         *       </td>
0211         *       <td style="vertical-align: middle;">
0212         *		<code>0<br></code>
0213         *       </td>
0214         *     </tr>
0215         *   </tbody>
0216         * </table>
0217         * <br>Default values are not applicable for the fields not listed above.
0218         *
0219         * <p>
0220         * <strong>Example:</strong>
0221         * <blockquote>
0222         * <pre>
0223         * // get the supported ids for GMT-08:00 (Pacific Standard Time)
0224         * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
0225         * // if no ids were returned, something is wrong. get out.
0226         * if (ids.length == 0)
0227         *     System.exit(0);
0228         *
0229         *  // begin output
0230         * System.out.println("Current Time");
0231         *
0232         * // create a Pacific Standard Time time zone
0233         * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
0234         *
0235         * // set up rules for daylight savings time
0236         * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
0237         * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
0238         *
0239         * // create a GregorianCalendar with the Pacific Daylight time zone
0240         * // and the current date and time
0241         * Calendar calendar = new GregorianCalendar(pdt);
0242         * Date trialTime = new Date();
0243         * calendar.setTime(trialTime);
0244         *
0245         * // print out a bunch of interesting things
0246         * System.out.println("ERA: " + calendar.get(Calendar.ERA));
0247         * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
0248         * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
0249         * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
0250         * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
0251         * System.out.println("DATE: " + calendar.get(Calendar.DATE));
0252         * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
0253         * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
0254         * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
0255         * System.out.println("DAY_OF_WEEK_IN_MONTH: "
0256         *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
0257         * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
0258         * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
0259         * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
0260         * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
0261         * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
0262         * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
0263         * System.out.println("ZONE_OFFSET: "
0264         *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
0265         * System.out.println("DST_OFFSET: "
0266         *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
0267
0268         * System.out.println("Current Time, with hour reset to 3");
0269         * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
0270         * calendar.set(Calendar.HOUR, 3);
0271         * System.out.println("ERA: " + calendar.get(Calendar.ERA));
0272         * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
0273         * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
0274         * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
0275         * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
0276         * System.out.println("DATE: " + calendar.get(Calendar.DATE));
0277         * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
0278         * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
0279         * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
0280         * System.out.println("DAY_OF_WEEK_IN_MONTH: "
0281         *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
0282         * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
0283         * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
0284         * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
0285         * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
0286         * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
0287         * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
0288         * System.out.println("ZONE_OFFSET: "
0289         *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
0290         * System.out.println("DST_OFFSET: "
0291         *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
0292         * </pre>
0293         * </blockquote>
0294         *
0295         * @see          TimeZone
0296         * @version      1.99
0297         * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
0298         * @since JDK1.1
0299         */
0300        public class GregorianCalendar extends Calendar {
0301            /*
0302             * Implementation Notes
0303             *
0304             * The epoch is the number of days or milliseconds from some defined
0305             * starting point. The epoch for java.util.Date is used here; that is,
0306             * milliseconds from January 1, 1970 (Gregorian), midnight UTC.  Other
0307             * epochs which are used are January 1, year 1 (Gregorian), which is day 1
0308             * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
0309             * day 1 of the Julian calendar.
0310             *
0311             * We implement the proleptic Julian and Gregorian calendars.  This means we
0312             * implement the modern definition of the calendar even though the
0313             * historical usage differs.  For example, if the Gregorian change is set
0314             * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
0315             * labels dates preceding the invention of the Gregorian calendar in 1582 as
0316             * if the calendar existed then.
0317             *
0318             * Likewise, with the Julian calendar, we assume a consistent
0319             * 4-year leap year rule, even though the historical pattern of
0320             * leap years is irregular, being every 3 years from 45 BCE
0321             * through 9 BCE, then every 4 years from 8 CE onwards, with no
0322             * leap years in-between.  Thus date computations and functions
0323             * such as isLeapYear() are not intended to be historically
0324             * accurate.
0325             */
0326
0327            //////////////////
0328            // Class Variables
0329            //////////////////
0330            /**
0331             * Value of the <code>ERA</code> field indicating
0332             * the period before the common era (before Christ), also known as BCE.
0333             * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
0334             * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
0335             *
0336             * @see #ERA
0337             */
0338            public static final int BC = 0;
0339
0340            /**
0341             * Value of the {@link #ERA} field indicating
0342             * the period before the common era, the same value as {@link #BC}.
0343             *
0344             * @see #CE
0345             */
0346            static final int BCE = 0;
0347
0348            /**
0349             * Value of the <code>ERA</code> field indicating
0350             * the common era (Anno Domini), also known as CE.
0351             * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
0352             * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
0353             *
0354             * @see #ERA
0355             */
0356            public static final int AD = 1;
0357
0358            /**
0359             * Value of the {@link #ERA} field indicating
0360             * the common era, the same value as {@link #AD}.
0361             *
0362             * @see #BCE
0363             */
0364            static final int CE = 1;
0365
0366            private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
0367            private static final int EPOCH_YEAR = 1970;
0368
0369            static final int MONTH_LENGTH[] = { 31, 28, 31, 30, 31, 30, 31, 31,
0370                    30, 31, 30, 31 }; // 0-based
0371            static final int LEAP_MONTH_LENGTH[] = { 31, 29, 31, 30, 31, 30,
0372                    31, 31, 30, 31, 30, 31 }; // 0-based
0373
0374            // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
0375            // into ints, they must be longs in order to prevent arithmetic overflow
0376            // when performing (bug 4173516).
0377            private static final int ONE_SECOND = 1000;
0378            private static final int ONE_MINUTE = 60 * ONE_SECOND;
0379            private static final int ONE_HOUR = 60 * ONE_MINUTE;
0380            private static final long ONE_DAY = 24 * ONE_HOUR;
0381            private static final long ONE_WEEK = 7 * ONE_DAY;
0382
0383            /*
0384             * <pre>
0385             *                            Greatest       Least 
0386             * Field name        Minimum   Minimum     Maximum     Maximum
0387             * ----------        -------   -------     -------     -------
0388             * ERA                     0         0           1           1
0389             * YEAR                    1         1   292269054   292278994
0390             * MONTH                   0         0          11          11
0391             * WEEK_OF_YEAR            1         1          52*         53
0392             * WEEK_OF_MONTH           0         0           4*          6
0393             * DAY_OF_MONTH            1         1          28*         31
0394             * DAY_OF_YEAR             1         1         365*        366
0395             * DAY_OF_WEEK             1         1           7           7
0396             * DAY_OF_WEEK_IN_MONTH   -1        -1           4*          6
0397             * AM_PM                   0         0           1           1
0398             * HOUR                    0         0          11          11
0399             * HOUR_OF_DAY             0         0          23          23
0400             * MINUTE                  0         0          59          59
0401             * SECOND                  0         0          59          59
0402             * MILLISECOND             0         0         999         999
0403             * ZONE_OFFSET        -13:00    -13:00       14:00       14:00
0404             * DST_OFFSET           0:00      0:00        0:20        2:00
0405             * </pre>
0406             * *: depends on the Gregorian change date
0407             */
0408            static final int MIN_VALUES[] = { BCE, // ERA
0409                    1, // YEAR
0410                    JANUARY, // MONTH
0411                    1, // WEEK_OF_YEAR
0412                    0, // WEEK_OF_MONTH
0413                    1, // DAY_OF_MONTH
0414                    1, // DAY_OF_YEAR
0415                    SUNDAY, // DAY_OF_WEEK
0416                    1, // DAY_OF_WEEK_IN_MONTH
0417                    AM, // AM_PM
0418                    0, // HOUR
0419                    0, // HOUR_OF_DAY
0420                    0, // MINUTE
0421                    0, // SECOND
0422                    0, // MILLISECOND
0423                    -13 * ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
0424                    0 // DST_OFFSET
0425            };
0426            static final int LEAST_MAX_VALUES[] = { CE, // ERA
0427                    292269054, // YEAR
0428                    DECEMBER, // MONTH
0429                    52, // WEEK_OF_YEAR
0430                    4, // WEEK_OF_MONTH
0431                    28, // DAY_OF_MONTH
0432                    365, // DAY_OF_YEAR
0433                    SATURDAY, // DAY_OF_WEEK
0434                    4, // DAY_OF_WEEK_IN
0435                    PM, // AM_PM
0436                    11, // HOUR
0437                    23, // HOUR_OF_DAY
0438                    59, // MINUTE
0439                    59, // SECOND
0440                    999, // MILLISECOND
0441                    14 * ONE_HOUR, // ZONE_OFFSET
0442                    20 * ONE_MINUTE // DST_OFFSET (historical least maximum)
0443            };
0444            static final int MAX_VALUES[] = { CE, // ERA
0445                    292278994, // YEAR
0446                    DECEMBER, // MONTH
0447                    53, // WEEK_OF_YEAR
0448                    6, // WEEK_OF_MONTH
0449                    31, // DAY_OF_MONTH
0450                    366, // DAY_OF_YEAR
0451                    SATURDAY, // DAY_OF_WEEK
0452                    6, // DAY_OF_WEEK_IN
0453                    PM, // AM_PM
0454                    11, // HOUR
0455                    23, // HOUR_OF_DAY
0456                    59, // MINUTE
0457                    59, // SECOND
0458                    999, // MILLISECOND
0459                    14 * ONE_HOUR, // ZONE_OFFSET
0460                    2 * ONE_HOUR // DST_OFFSET (double summer time)
0461            };
0462
0463            // Proclaim serialization compatibility with JDK 1.1
0464            static final long serialVersionUID = -8125100834729963327L;
0465
0466            // Reference to the sun.util.calendar.Gregorian instance (singleton).
0467            private static final Gregorian gcal = CalendarSystem
0468                    .getGregorianCalendar();
0469
0470            // Reference to the JulianCalendar instance (singleton), set as needed. See
0471            // getJulianCalendarSystem().
0472            private static JulianCalendar jcal;
0473
0474            // JulianCalendar eras. See getJulianCalendarSystem().
0475            private static Era[] jeras;
0476
0477            // The default value of gregorianCutover.
0478            static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
0479
0480            /////////////////////
0481            // Instance Variables
0482            /////////////////////
0483
0484            /**
0485             * The point at which the Gregorian calendar rules are used, measured in
0486             * milliseconds from the standard epoch.  Default is October 15, 1582
0487             * (Gregorian) 00:00:00 UTC or -12219292800000L.  For this value, October 4,
0488             * 1582 (Julian) is followed by October 15, 1582 (Gregorian).  This
0489             * corresponds to Julian day number 2299161.
0490             * @serial
0491             */
0492            private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
0493
0494            /**
0495             * The fixed date of the gregorianCutover.
0496             */
0497            private transient long gregorianCutoverDate = (((DEFAULT_GREGORIAN_CUTOVER + 1) / ONE_DAY) - 1)
0498                    + EPOCH_OFFSET; // == 577736
0499
0500            /**
0501             * The normalized year of the gregorianCutover in Gregorian, with
0502             * 0 representing 1 BCE, -1 representing 2 BCE, etc.
0503             */
0504            private transient int gregorianCutoverYear = 1582;
0505
0506            /**
0507             * The normalized year of the gregorianCutover in Julian, with 0
0508             * representing 1 BCE, -1 representing 2 BCE, etc.
0509             */
0510            private transient int gregorianCutoverYearJulian = 1582;
0511
0512            /**
0513             * gdate always has a sun.util.calendar.Gregorian.Date instance to
0514             * avoid overhead of creating it. The assumption is that most
0515             * applications will need only Gregorian calendar calculations.
0516             */
0517            private transient BaseCalendar.Date gdate;
0518
0519            /**
0520             * Reference to either gdate or a JulianCalendar.Date
0521             * instance. After calling complete(), this value is guaranteed to
0522             * be set.
0523             */
0524            private transient BaseCalendar.Date cdate;
0525
0526            /**
0527             * The CalendarSystem used to calculate the date in cdate. After
0528             * calling complete(), this value is guaranteed to be set and
0529             * consistent with the cdate value.
0530             */
0531            private transient BaseCalendar calsys;
0532
0533            /**
0534             * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
0535             * the GMT offset value and zoneOffsets[1] gets the DST saving
0536             * value.
0537             */
0538            private transient int[] zoneOffsets;
0539
0540            /**
0541             * Temporary storage for saving original fields[] values in
0542             * non-lenient mode.
0543             */
0544            private transient int[] originalFields;
0545
0546            ///////////////
0547            // Constructors
0548            ///////////////
0549
0550            /**
0551             * Constructs a default <code>GregorianCalendar</code> using the current time
0552             * in the default time zone with the default locale.
0553             */
0554            public GregorianCalendar() {
0555                this (TimeZone.getDefaultRef(), Locale.getDefault());
0556                setZoneShared(true);
0557            }
0558
0559            /**
0560             * Constructs a <code>GregorianCalendar</code> based on the current time
0561             * in the given time zone with the default locale.
0562             *
0563             * @param zone the given time zone.
0564             */
0565            public GregorianCalendar(TimeZone zone) {
0566                this (zone, Locale.getDefault());
0567            }
0568
0569            /**
0570             * Constructs a <code>GregorianCalendar</code> based on the current time
0571             * in the default time zone with the given locale.
0572             *
0573             * @param aLocale the given locale.
0574             */
0575            public GregorianCalendar(Locale aLocale) {
0576                this (TimeZone.getDefaultRef(), aLocale);
0577                setZoneShared(true);
0578            }
0579
0580            /**
0581             * Constructs a <code>GregorianCalendar</code> based on the current time
0582             * in the given time zone with the given locale.
0583             *
0584             * @param zone the given time zone.
0585             * @param aLocale the given locale.
0586             */
0587            public GregorianCalendar(TimeZone zone, Locale aLocale) {
0588                super (zone, aLocale);
0589                gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
0590                setTimeInMillis(System.currentTimeMillis());
0591            }
0592
0593            /**
0594             * Constructs a <code>GregorianCalendar</code> with the given date set
0595             * in the default time zone with the default locale.
0596             *
0597             * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0598             * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0599             * Month value is 0-based. e.g., 0 for January.
0600             * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0601             */
0602            public GregorianCalendar(int year, int month, int dayOfMonth) {
0603                this (year, month, dayOfMonth, 0, 0, 0, 0);
0604            }
0605
0606            /**
0607             * Constructs a <code>GregorianCalendar</code> with the given date
0608             * and time set for the default time zone with the default locale.
0609             *
0610             * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0611             * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0612             * Month value is 0-based. e.g., 0 for January.
0613             * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0614             * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
0615             * in the calendar.
0616             * @param minute the value used to set the <code>MINUTE</code> calendar field
0617             * in the calendar.
0618             */
0619            public GregorianCalendar(int year, int month, int dayOfMonth,
0620                    int hourOfDay, int minute) {
0621                this (year, month, dayOfMonth, hourOfDay, minute, 0, 0);
0622            }
0623
0624            /**
0625             * Constructs a GregorianCalendar with the given date
0626             * and time set for the default time zone with the default locale.
0627             *
0628             * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0629             * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0630             * Month value is 0-based. e.g., 0 for January.
0631             * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0632             * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
0633             * in the calendar.
0634             * @param minute the value used to set the <code>MINUTE</code> calendar field
0635             * in the calendar.
0636             * @param second the value used to set the <code>SECOND</code> calendar field
0637             * in the calendar.
0638             */
0639            public GregorianCalendar(int year, int month, int dayOfMonth,
0640                    int hourOfDay, int minute, int second) {
0641                this (year, month, dayOfMonth, hourOfDay, minute, second, 0);
0642            }
0643
0644            /**
0645             * Constructs a <code>GregorianCalendar</code> with the given date
0646             * and time set for the default time zone with the default locale.
0647             *
0648             * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
0649             * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
0650             * Month value is 0-based. e.g., 0 for January.
0651             * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
0652             * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
0653             * in the calendar.
0654             * @param minute the value used to set the <code>MINUTE</code> calendar field
0655             * in the calendar.
0656             * @param second the value used to set the <code>SECOND</code> calendar field
0657             * in the calendar.
0658             * @param millis the value used to set the <code>MILLISECOND</code> calendar field
0659             */
0660            GregorianCalendar(int year, int month, int dayOfMonth,
0661                    int hourOfDay, int minute, int second, int millis) {
0662                super ();
0663                gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
0664                this .set(YEAR, year);
0665                this .set(MONTH, month);
0666                this .set(DAY_OF_MONTH, dayOfMonth);
0667
0668                // Set AM_PM and HOUR here to set their stamp values before
0669                // setting HOUR_OF_DAY (6178071).
0670                if (hourOfDay >= 12 && hourOfDay <= 23) {
0671                    // If hourOfDay is a valid PM hour, set the correct PM values
0672                    // so that it won't throw an exception in case it's set to
0673                    // non-lenient later.
0674                    this .internalSet(AM_PM, PM);
0675                    this .internalSet(HOUR, hourOfDay - 12);
0676                } else {
0677                    // The default value for AM_PM is AM.
0678                    // We don't care any out of range value here for leniency.
0679                    this .internalSet(HOUR, hourOfDay);
0680                }
0681                // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
0682                setFieldsComputed(HOUR_MASK | AM_PM_MASK);
0683
0684                this .set(HOUR_OF_DAY, hourOfDay);
0685                this .set(MINUTE, minute);
0686                this .set(SECOND, second);
0687                // should be changed to set() when this constructor is made
0688                // public.
0689                this .internalSet(MILLISECOND, millis);
0690            }
0691
0692            /////////////////
0693            // Public methods
0694            /////////////////
0695
0696            /**
0697             * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
0698             * from Julian dates to Gregorian dates occurred. Default is October 15,
0699             * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
0700             * <p>
0701             * To obtain a pure Julian calendar, set the change date to
0702             * <code>Date(Long.MAX_VALUE)</code>.  To obtain a pure Gregorian calendar,
0703             * set the change date to <code>Date(Long.MIN_VALUE)</code>.
0704             *
0705             * @param date the given Gregorian cutover date.
0706             */
0707            public void setGregorianChange(Date date) {
0708                long cutoverTime = date.getTime();
0709                if (cutoverTime == gregorianCutover) {
0710                    return;
0711                }
0712                // Before changing the cutover date, make sure to have the
0713                // time of this calendar.
0714                complete();
0715                setGregorianChange(cutoverTime);
0716            }
0717
0718            private void setGregorianChange(long cutoverTime) {
0719                gregorianCutover = cutoverTime;
0720                gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime,
0721                        ONE_DAY)
0722                        + EPOCH_OFFSET;
0723
0724                // To provide the "pure" Julian calendar as advertised.
0725                // Strictly speaking, the last millisecond should be a
0726                // Gregorian date. However, the API doc specifies that setting
0727                // the cutover date to Long.MAX_VALUE will make this calendar
0728                // a pure Julian calendar. (See 4167995)
0729                if (cutoverTime == Long.MAX_VALUE) {
0730                    gregorianCutoverDate++;
0731                }
0732
0733                BaseCalendar.Date d = getGregorianCutoverDate();
0734
0735                // Set the cutover year (in the Gregorian year numbering)
0736                gregorianCutoverYear = d.getYear();
0737
0738                BaseCalendar jcal = getJulianCalendarSystem();
0739                d = (BaseCalendar.Date) jcal
0740                        .newCalendarDate(TimeZone.NO_TIMEZONE);
0741                jcal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
0742                gregorianCutoverYearJulian = d.getNormalizedYear();
0743
0744                if (time < gregorianCutover) {
0745                    // The field values are no longer valid under the new
0746                    // cutover date.
0747                    setUnnormalized();
0748                }
0749            }
0750
0751            /**
0752             * Gets the Gregorian Calendar change date.  This is the point when the
0753             * switch from Julian dates to Gregorian dates occurred. Default is
0754             * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
0755             * calendar.
0756             *
0757             * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
0758             */
0759            public final Date getGregorianChange() {
0760                return new Date(gregorianCutover);
0761            }
0762
0763            /**
0764             * Determines if the given year is a leap year. Returns <code>true</code> if
0765             * the given year is a leap year. To specify BC year numbers,
0766             * <code>1 - year number</code> must be given. For example, year BC 4 is
0767             * specified as -3.
0768             *
0769             * @param year the given year.
0770             * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
0771             */
0772            public boolean isLeapYear(int year) {
0773                if ((year & 3) != 0) {
0774                    return false;
0775                }
0776
0777                if (year > gregorianCutoverYear) {
0778                    return (year % 100 != 0) || (year % 400 == 0); // Gregorian
0779                }
0780                if (year < gregorianCutoverYearJulian) {
0781                    return true; // Julian
0782                }
0783                boolean gregorian;
0784                // If the given year is the Gregorian cutover year, we need to
0785                // determine which calendar system to be applied to February in the year.
0786                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
0787                    BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
0788                    gregorian = d.getMonth() < BaseCalendar.MARCH;
0789                } else {
0790                    gregorian = year == gregorianCutoverYear;
0791                }
0792                return gregorian ? (year % 100 != 0) || (year % 400 == 0)
0793                        : true;
0794            }
0795
0796            /**
0797             * Compares this <code>GregorianCalendar</code> to the specified
0798             * <code>Object</code>. The result is <code>true</code> if and
0799             * only if the argument is a <code>GregorianCalendar</code> object
0800             * that represents the same time value (millisecond offset from
0801             * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
0802             * <code>Calendar</code> parameters and Gregorian change date as
0803             * this object.
0804             *
0805             * @param obj the object to compare with.
0806             * @return <code>true</code> if this object is equal to <code>obj</code>;
0807             * <code>false</code> otherwise.
0808             * @see Calendar#compareTo(Calendar)
0809             */
0810            public boolean equals(Object obj) {
0811                return obj instanceof  GregorianCalendar
0812                        && super .equals(obj)
0813                        && gregorianCutover == ((GregorianCalendar) obj).gregorianCutover;
0814            }
0815
0816            /**
0817             * Generates the hash code for this <code>GregorianCalendar</code> object.
0818             */
0819            public int hashCode() {
0820                return super .hashCode() ^ (int) gregorianCutoverDate;
0821            }
0822
0823            /**
0824             * Adds the specified (signed) amount of time to the given calendar field,
0825             * based on the calendar's rules.
0826             *
0827             * <p><em>Add rule 1</em>. The value of <code>field</code>
0828             * after the call minus the value of <code>field</code> before the
0829             * call is <code>amount</code>, modulo any overflow that has occurred in
0830             * <code>field</code>. Overflow occurs when a field value exceeds its
0831             * range and, as a result, the next larger field is incremented or
0832             * decremented and the field value is adjusted back into its range.</p>
0833             *
0834             * <p><em>Add rule 2</em>. If a smaller field is expected to be
0835             * invariant, but it is impossible for it to be equal to its
0836             * prior value because of changes in its minimum or maximum after
0837             * <code>field</code> is changed, then its value is adjusted to be as close
0838             * as possible to its expected value. A smaller field represents a
0839             * smaller unit of time. <code>HOUR</code> is a smaller field than
0840             * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
0841             * that are not expected to be invariant. The calendar system
0842             * determines what fields are expected to be invariant.</p>
0843             *
0844             * @param field the calendar field.
0845             * @param amount the amount of date or time to be added to the field.
0846             * @exception IllegalArgumentException if <code>field</code> is
0847             * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
0848             * or if any calendar fields have out-of-range values in
0849             * non-lenient mode.
0850             */
0851            public void add(int field, int amount) {
0852                // If amount == 0, do nothing even the given field is out of
0853                // range. This is tested by JCK.
0854                if (amount == 0) {
0855                    return; // Do nothing!
0856                }
0857
0858                if (field < 0 || field >= ZONE_OFFSET) {
0859                    throw new IllegalArgumentException();
0860                }
0861
0862                // Sync the time and calendar fields.
0863                complete();
0864
0865                if (field == YEAR) {
0866                    int year = internalGet(YEAR);
0867                    if (internalGetEra() == CE) {
0868                        year += amount;
0869                        if (year > 0) {
0870                            set(YEAR, year);
0871                        } else { // year <= 0
0872                            set(YEAR, 1 - year);
0873                            // if year == 0, you get 1 BCE.
0874                            set(ERA, BCE);
0875                        }
0876                    } else { // era == BCE
0877                        year -= amount;
0878                        if (year > 0) {
0879                            set(YEAR, year);
0880                        } else { // year <= 0
0881                            set(YEAR, 1 - year);
0882                            // if year == 0, you get 1 CE
0883                            set(ERA, CE);
0884                        }
0885                    }
0886                    pinDayOfMonth();
0887                } else if (field == MONTH) {
0888                    int month = internalGet(MONTH) + amount;
0889                    int year = internalGet(YEAR);
0890                    int y_amount;
0891
0892                    if (month >= 0) {
0893                        y_amount = month / 12;
0894                    } else {
0895                        y_amount = (month + 1) / 12 - 1;
0896                    }
0897                    if (y_amount != 0) {
0898                        if (internalGetEra() == CE) {
0899                            year += y_amount;
0900                            if (year > 0) {
0901                                set(YEAR, year);
0902                            } else { // year <= 0
0903                                set(YEAR, 1 - year);
0904                                // if year == 0, you get 1 BCE
0905                                set(ERA, BCE);
0906                            }
0907                        } else { // era == BCE
0908                            year -= y_amount;
0909                            if (year > 0) {
0910                                set(YEAR, year);
0911                            } else { // year <= 0
0912                                set(YEAR, 1 - year);
0913                                // if year == 0, you get 1 CE
0914                                set(ERA, CE);
0915                            }
0916                        }
0917                    }
0918
0919                    if (month >= 0) {
0920                        set(MONTH, (int) (month % 12));
0921                    } else {
0922                        // month < 0
0923                        month %= 12;
0924                        if (month < 0) {
0925                            month += 12;
0926                        }
0927                        set(MONTH, JANUARY + month);
0928                    }
0929                    pinDayOfMonth();
0930                } else if (field == ERA) {
0931                    int era = internalGet(ERA) + amount;
0932                    if (era < 0) {
0933                        era = 0;
0934                    }
0935                    if (era > 1) {
0936                        era = 1;
0937                    }
0938                    set(ERA, era);
0939                } else {
0940                    long delta = amount;
0941                    long timeOfDay = 0;
0942                    switch (field) {
0943                    // Handle the time fields here. Convert the given
0944                    // amount to milliseconds and call setTimeInMillis.
0945                    case HOUR:
0946                    case HOUR_OF_DAY:
0947                        delta *= 60 * 60 * 1000; // hours to minutes
0948                        break;
0949
0950                    case MINUTE:
0951                        delta *= 60 * 1000; // minutes to seconds
0952                        break;
0953
0954                    case SECOND:
0955                        delta *= 1000; // seconds to milliseconds
0956                        break;
0957
0958                    case MILLISECOND:
0959                        break;
0960
0961                    // Handle week, day and AM_PM fields which involves
0962                    // time zone offset change adjustment. Convert the
0963                    // given amount to the number of days.
0964                    case WEEK_OF_YEAR:
0965                    case WEEK_OF_MONTH:
0966                    case DAY_OF_WEEK_IN_MONTH:
0967                        delta *= 7;
0968                        break;
0969
0970                    case DAY_OF_MONTH: // synonym of DATE
0971                    case DAY_OF_YEAR:
0972                    case DAY_OF_WEEK:
0973                        break;
0974
0975                    case AM_PM:
0976                        // Convert the amount to the number of days (delta)
0977                        // and +12 or -12 hours (timeOfDay).
0978                        delta = amount / 2;
0979                        timeOfDay = 12 * (amount % 2);
0980                        break;
0981                    }
0982
0983                    // The time fields don't require time zone offset change
0984                    // adjustment.
0985                    if (field >= HOUR) {
0986                        setTimeInMillis(time + delta);
0987                        return;
0988                    }
0989
0990                    // The rest of the fields (week, day or AM_PM fields)
0991                    // require time zone offset (both GMT and DST) change
0992                    // adjustment.
0993
0994                    // Translate the current time to the fixed date and time
0995                    // of the day.
0996                    long fd = getCurrentFixedDate();
0997                    timeOfDay += internalGet(HOUR_OF_DAY);
0998                    timeOfDay *= 60;
0999                    timeOfDay += internalGet(MINUTE);
1000                    timeOfDay *= 60;
1001                    timeOfDay += internalGet(SECOND);
1002                    timeOfDay *= 1000;
1003                    timeOfDay += internalGet(MILLISECOND);
1004                    if (timeOfDay >= ONE_DAY) {
1005                        fd++;
1006                        timeOfDay -= ONE_DAY;
1007                    } else if (timeOfDay < 0) {
1008                        fd--;
1009                        timeOfDay += ONE_DAY;
1010                    }
1011
1012                    fd += delta; // fd is the expected fixed date after the calculation
1013                    int zoneOffset = internalGet(ZONE_OFFSET)
1014                            + internalGet(DST_OFFSET);
1015                    setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay
1016                            - zoneOffset);
1017                    zoneOffset -= internalGet(ZONE_OFFSET)
1018                            + internalGet(DST_OFFSET);
1019                    // If the time zone offset has changed, then adjust the difference.
1020                    if (zoneOffset != 0) {
1021                        setTimeInMillis(time + zoneOffset);
1022                        long fd2 = getCurrentFixedDate();
1023                        // If the adjustment has changed the date, then take
1024                        // the previous one.
1025                        if (fd2 != fd) {
1026                            setTimeInMillis(time - zoneOffset);
1027                        }
1028                    }
1029                }
1030            }
1031
1032            /**
1033             * Adds or subtracts (up/down) a single unit of time on the given time
1034             * field without changing larger fields. 
1035             * <p>
1036             * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1037             * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
1038             * sets the calendar to January 31, 1999.  The <code>YEAR</code> field is unchanged
1039             * because it is a larger field than <code>MONTH</code>.</p>
1040             *
1041             * @param up indicates if the value of the specified calendar field is to be
1042             * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
1043             * @exception IllegalArgumentException if <code>field</code> is
1044             * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1045             * or if any calendar fields have out-of-range values in
1046             * non-lenient mode.
1047             * @see #add(int,int)
1048             * @see #set(int,int)
1049             */
1050            public void roll(int field, boolean up) {
1051                roll(field, up ? +1 : -1);
1052            }
1053
1054            /**
1055             * Adds a signed amount to the specified calendar field without changing larger fields.
1056             * A negative roll amount means to subtract from field without changing 
1057             * larger fields. If the specified amount is 0, this method performs nothing.
1058             *
1059             * <p>This method calls {@link #complete()} before adding the
1060             * amount so that all the calendar fields are normalized. If there
1061             * is any calendar field having an out-of-range value in non-lenient mode, then an
1062             * <code>IllegalArgumentException</code> is thrown.
1063             *
1064             * <p>
1065             * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1066             * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
1067             * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
1068             * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
1069             * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
1070             * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
1071             * is a larger field than <code>MONTH</code>.
1072             * <p>
1073             * <em>Example</em>: Consider a <code>GregorianCalendar</code>
1074             * originally set to Sunday June 6, 1999. Calling
1075             * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1076             * Tuesday June 1, 1999, whereas calling
1077             * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
1078             * Sunday May 30, 1999. This is because the roll rule imposes an
1079             * additional constraint: The <code>MONTH</code> must not change when the
1080             * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
1081             * the resultant date must be between Tuesday June 1 and Saturday June
1082             * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
1083             * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
1084             * closest possible value to Sunday (where Sunday is the first day of the
1085             * week).</p>
1086             *
1087             * @param field the calendar field.
1088             * @param amount the signed amount to add to <code>field</code>.
1089             * @exception IllegalArgumentException if <code>field</code> is
1090             * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
1091             * or if any calendar fields have out-of-range values in
1092             * non-lenient mode.
1093             * @see #roll(int,boolean)
1094             * @see #add(int,int)
1095             * @see #set(int,int)
1096             * @since 1.2
1097             */
1098            public void roll(int field, int amount) {
1099                // If amount == 0, do nothing even the given field is out of
1100                // range. This is tested by JCK.
1101                if (amount == 0) {
1102                    return;
1103                }
1104
1105                if (field < 0 || field >= ZONE_OFFSET) {
1106                    throw new IllegalArgumentException();
1107                }
1108
1109                // Sync the time and calendar fields.
1110                complete();
1111
1112                int min = getMinimum(field);
1113                int max = getMaximum(field);
1114
1115                switch (field) {
1116                case AM_PM:
1117                case ERA:
1118                case YEAR:
1119                case MINUTE:
1120                case SECOND:
1121                case MILLISECOND:
1122                    // These fields are handled simply, since they have fixed minima
1123                    // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
1124                    // fields are complicated, since the range within they must roll
1125                    // varies depending on the date.
1126                    break;
1127
1128                case HOUR:
1129                case HOUR_OF_DAY: {
1130                    int unit = max + 1; // 12 or 24 hours
1131                    int h = internalGet(field);
1132                    int nh = (h + amount) % unit;
1133                    if (nh < 0) {
1134                        nh += unit;
1135                    }
1136                    time += ONE_HOUR * (nh - h);
1137
1138                    // The day might have changed, which could happen if
1139                    // the daylight saving time transition brings it to
1140                    // the next day, although it's very unlikely. But we
1141                    // have to make sure not to change the larger fields.
1142                    CalendarDate d = calsys.getCalendarDate(time, getZone());
1143                    if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
1144                        d.setDate(internalGet(YEAR), internalGet(MONTH) + 1,
1145                                internalGet(DAY_OF_MONTH));
1146                        if (field == HOUR) {
1147                            assert (internalGet(AM_PM) == PM);
1148                            d.addHours(+12); // restore PM
1149                        }
1150                        time = calsys.getTime(d);
1151                    }
1152                    int hourOfDay = d.getHours();
1153                    internalSet(field, hourOfDay % unit);
1154                    if (field == HOUR) {
1155                        internalSet(HOUR_OF_DAY, hourOfDay);
1156                    } else {
1157                        internalSet(AM_PM, hourOfDay / 12);
1158                        internalSet(HOUR, hourOfDay % 12);
1159                    }
1160
1161                    // Time zone offset and/or daylight saving might have changed.
1162                    int zoneOffset = d.getZoneOffset();
1163                    int saving = d.getDaylightSaving();
1164                    internalSet(ZONE_OFFSET, zoneOffset - saving);
1165                    internalSet(DST_OFFSET, saving);
1166                    return;
1167                }
1168
1169                case MONTH:
1170                    // Rolling the month involves both pinning the final value to [0, 11]
1171                    // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
1172                    // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
1173                    // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
1174                {
1175                    if (!isCutoverYear(cdate.getNormalizedYear())) {
1176                        int mon = (internalGet(MONTH) + amount) % 12;
1177                        if (mon < 0) {
1178                            mon += 12;
1179                        }
1180                        set(MONTH, mon);
1181
1182                        // Keep the day of month in the range.  We don't want to spill over
1183                        // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
1184                        // mar3.
1185                        int monthLen = monthLength(mon);
1186                        if (internalGet(DAY_OF_MONTH) > monthLen) {
1187                            set(DAY_OF_MONTH, monthLen);
1188                        }
1189                    } else {
1190                        // We need to take care of different lengths in
1191                        // year and month due to the cutover.
1192                        int yearLength = getActualMaximum(MONTH) + 1;
1193                        int mon = (internalGet(MONTH) + amount) % yearLength;
1194                        if (mon < 0) {
1195                            mon += yearLength;
1196                        }
1197                        set(MONTH, mon);
1198                        int monthLen = getActualMaximum(DAY_OF_MONTH);
1199                        if (internalGet(DAY_OF_MONTH) > monthLen) {
1200                            set(DAY_OF_MONTH, monthLen);
1201                        }
1202                    }
1203                    return;
1204                }
1205
1206                case WEEK_OF_YEAR: {
1207                    int y = cdate.getNormalizedYear();
1208                    max = getActualMaximum(WEEK_OF_YEAR);
1209                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1210                    int woy = internalGet(WEEK_OF_YEAR);
1211                    int value = woy + amount;
1212                    if (!isCutoverYear(y)) {
1213                        // If the new value is in between min and max
1214                        // (exclusive), then we can use the value.
1215                        if (value > min && value < max) {
1216                            set(WEEK_OF_YEAR, value);
1217                            return;
1218                        }
1219                        long fd = getCurrentFixedDate();
1220                        // Make sure that the min week has the current DAY_OF_WEEK
1221                        long day1 = fd - (7 * (woy - min));
1222                        if (calsys.getYearFromFixedDate(day1) != y) {
1223                            min++;
1224                        }
1225
1226                        // Make sure the same thing for the max week
1227                        fd += 7 * (max - internalGet(WEEK_OF_YEAR));
1228                        if (calsys.getYearFromFixedDate(fd) != y) {
1229                            max--;
1230                        }
1231                        break;
1232                    }
1233
1234                    // Handle cutover here.
1235                    long fd = getCurrentFixedDate();
1236                    BaseCalendar cal;
1237                    if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1238                        cal = getCutoverCalendarSystem();
1239                    } else if (y == gregorianCutoverYear) {
1240                        cal = gcal;
1241                    } else {
1242                        cal = getJulianCalendarSystem();
1243                    }
1244                    long day1 = fd - (7 * (woy - min));
1245                    // Make sure that the min week has the current DAY_OF_WEEK
1246                    if (cal.getYearFromFixedDate(day1) != y) {
1247                        min++;
1248                    }
1249
1250                    // Make sure the same thing for the max week
1251                    fd += 7 * (max - woy);
1252                    cal = (fd >= gregorianCutoverDate) ? gcal
1253                            : getJulianCalendarSystem();
1254                    if (cal.getYearFromFixedDate(fd) != y) {
1255                        max--;
1256                    }
1257                    // value: the new WEEK_OF_YEAR which must be converted
1258                    // to month and day of month.
1259                    value = getRolledValue(woy, amount, min, max) - 1;
1260                    BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
1261                    set(MONTH, d.getMonth() - 1);
1262                    set(DAY_OF_MONTH, d.getDayOfMonth());
1263                    return;
1264                }
1265
1266                case WEEK_OF_MONTH: {
1267                    boolean isCutoverYear = isCutoverYear(cdate
1268                            .getNormalizedYear());
1269                    // dow: relative day of week from first day of week
1270                    int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
1271                    if (dow < 0) {
1272                        dow += 7;
1273                    }
1274
1275                    long fd = getCurrentFixedDate();
1276                    long month1; // fixed date of the first day (usually 1) of the month
1277                    int monthLength; // actual month length
1278                    if (isCutoverYear) {
1279                        month1 = getFixedDateMonth1(cdate, fd);
1280                        monthLength = actualMonthLength();
1281                    } else {
1282                        month1 = fd - internalGet(DAY_OF_MONTH) + 1;
1283                        monthLength = calsys.getMonthLength(cdate);
1284                    }
1285
1286                    // the first day of week of the month.
1287                    long monthDay1st = calsys.getDayOfWeekDateOnOrBefore(
1288                            month1 + 6, getFirstDayOfWeek());
1289                    // if the week has enough days to form a week, the
1290                    // week starts from the previous month.
1291                    if ((int) (monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
1292                        monthDay1st -= 7;
1293                    }
1294                    max = getActualMaximum(field);
1295
1296                    // value: the new WEEK_OF_MONTH value
1297                    int value = getRolledValue(internalGet(field), amount, 1,
1298                            max) - 1;
1299
1300                    // nfd: fixed date of the rolled date
1301                    long nfd = monthDay1st + value * 7 + dow;
1302
1303                    // Unlike WEEK_OF_YEAR, we need to change day of week if the
1304                    // nfd is out of the month.
1305                    if (nfd < month1) {
1306                        nfd = month1;
1307                    } else if (nfd >= (month1 + monthLength)) {
1308                        nfd = month1 + monthLength - 1;
1309                    }
1310                    int dayOfMonth;
1311                    if (isCutoverYear) {
1312                        // If we are in the cutover year, convert nfd to
1313                        // its calendar date and use dayOfMonth.
1314                        BaseCalendar.Date d = getCalendarDate(nfd);
1315                        dayOfMonth = d.getDayOfMonth();
1316                    } else {
1317                        dayOfMonth = (int) (nfd - month1) + 1;
1318                    }
1319                    set(DAY_OF_MONTH, dayOfMonth);
1320                    return;
1321                }
1322
1323                case DAY_OF_MONTH: {
1324                    if (!isCutoverYear(cdate.getNormalizedYear())) {
1325                        max = calsys.getMonthLength(cdate);
1326                        break;
1327                    }
1328
1329                    // Cutover year handling
1330                    long fd = getCurrentFixedDate();
1331                    long month1 = getFixedDateMonth1(cdate, fd);
1332                    // It may not be a regular month. Convert the date and range to
1333                    // the relative values, perform the roll, and
1334                    // convert the result back to the rolled date.
1335                    int value = getRolledValue((int) (fd - month1), amount, 0,
1336                            actualMonthLength() - 1);
1337                    BaseCalendar.Date d = getCalendarDate(month1 + value);
1338                    assert d.getMonth() - 1 == internalGet(MONTH);
1339                    set(DAY_OF_MONTH, d.getDayOfMonth());
1340                    return;
1341                }
1342
1343                case DAY_OF_YEAR: {
1344                    max = getActualMaximum(field);
1345                    if (!isCutoverYear(cdate.getNormalizedYear())) {
1346                        break;
1347                    }
1348
1349                    // Handle cutover here.
1350                    long fd = getCurrentFixedDate();
1351                    long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
1352                    int value = getRolledValue((int) (fd - jan1) + 1, amount,
1353                            min, max);
1354                    BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
1355                    set(MONTH, d.getMonth() - 1);
1356                    set(DAY_OF_MONTH, d.getDayOfMonth());
1357                    return;
1358                }
1359
1360                case DAY_OF_WEEK: {
1361                    if (!isCutoverYear(cdate.getNormalizedYear())) {
1362                        // If the week of year is in the same year, we can
1363                        // just change DAY_OF_WEEK.
1364                        int weekOfYear = internalGet(WEEK_OF_YEAR);
1365                        if (weekOfYear > 1 && weekOfYear < 52) {
1366                            set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
1367                            max = SATURDAY;
1368                            break;
1369                        }
1370                    }
1371
1372                    // We need to handle it in a different way around year
1373                    // boundaries and in the cutover year. Note that
1374                    // changing era and year values violates the roll
1375                    // rule: not changing larger calendar fields...
1376                    amount %= 7;
1377                    if (amount == 0) {
1378                        return;
1379                    }
1380                    long fd = getCurrentFixedDate();
1381                    long dowFirst = calsys.getDayOfWeekDateOnOrBefore(fd,
1382                            getFirstDayOfWeek());
1383                    fd += amount;
1384                    if (fd < dowFirst) {
1385                        fd += 7;
1386                    } else if (fd >= dowFirst + 7) {
1387                        fd -= 7;
1388                    }
1389                    BaseCalendar.Date d = getCalendarDate(fd);
1390                    set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
1391                    set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
1392                    return;
1393                }
1394
1395                case DAY_OF_WEEK_IN_MONTH: {
1396                    min = 1; // after normalized, min should be 1.
1397                    if (!isCutoverYear(cdate.getNormalizedYear())) {
1398                        int dom = internalGet(DAY_OF_MONTH);
1399                        int monthLength = calsys.getMonthLength(cdate);
1400                        int lastDays = monthLength % 7;
1401                        max = monthLength / 7;
1402                        int x = (dom - 1) % 7;
1403                        if (x < lastDays) {
1404                            max++;
1405                        }
1406                        set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
1407                        break;
1408                    }
1409
1410                    // Cutover year handling
1411                    long fd = getCurrentFixedDate();
1412                    long month1 = getFixedDateMonth1(cdate, fd);
1413                    int monthLength = actualMonthLength();
1414                    int lastDays = monthLength % 7;
1415                    max = monthLength / 7;
1416                    int x = (int) (fd - month1) % 7;
1417                    if (x < lastDays) {
1418                        max++;
1419                    }
1420                    int value = getRolledValue(internalGet(field), amount, min,
1421                            max) - 1;
1422                    fd = month1 + value * 7 + x;
1423                    BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal
1424                            : getJulianCalendarSystem();
1425                    BaseCalendar.Date d = (BaseCalendar.Date) cal
1426                            .newCalendarDate(TimeZone.NO_TIMEZONE);
1427                    cal.getCalendarDateFromFixedDate(d, fd);
1428                    set(DAY_OF_MONTH, d.getDayOfMonth());
1429                    return;
1430                }
1431                }
1432
1433                set(field, getRolledValue(internalGet(field), amount, min, max));
1434            }
1435
1436            /**
1437             * Returns the minimum value for the given calendar field of this
1438             * <code>GregorianCalendar</code> instance. The minimum value is
1439             * defined as the smallest value returned by the {@link
1440             * Calendar#get(int) get} method for any possible time value,
1441             * taking into consideration the current values of the
1442             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1443             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1444             * {@link #getGregorianChange() getGregorianChange} and
1445             * {@link Calendar#getTimeZone() getTimeZone} methods.
1446             *
1447             * @param field the calendar field.
1448             * @return the minimum value for the given calendar field.
1449             * @see #getMaximum(int)
1450             * @see #getGreatestMinimum(int)
1451             * @see #getLeastMaximum(int)
1452             * @see #getActualMinimum(int)
1453             * @see #getActualMaximum(int)
1454             */
1455            public int getMinimum(int field) {
1456                return MIN_VALUES[field];
1457            }
1458
1459            /**
1460             * Returns the maximum value for the given calendar field of this
1461             * <code>GregorianCalendar</code> instance. The maximum value is
1462             * defined as the largest value returned by the {@link
1463             * Calendar#get(int) get} method for any possible time value,
1464             * taking into consideration the current values of the
1465             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1466             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1467             * {@link #getGregorianChange() getGregorianChange} and
1468             * {@link Calendar#getTimeZone() getTimeZone} methods.
1469             *
1470             * @param field the calendar field.
1471             * @return the maximum value for the given calendar field.
1472             * @see #getMinimum(int)
1473             * @see #getGreatestMinimum(int)
1474             * @see #getLeastMaximum(int)
1475             * @see #getActualMinimum(int)
1476             * @see #getActualMaximum(int)
1477             */
1478            public int getMaximum(int field) {
1479                switch (field) {
1480                case MONTH:
1481                case DAY_OF_MONTH:
1482                case DAY_OF_YEAR:
1483                case WEEK_OF_YEAR:
1484                case WEEK_OF_MONTH:
1485                case DAY_OF_WEEK_IN_MONTH:
1486                case YEAR: {
1487                    // On or after Gregorian 200-3-1, Julian and Gregorian
1488                    // calendar dates are the same or Gregorian dates are
1489                    // larger (i.e., there is a "gap") after 300-3-1.
1490                    if (gregorianCutoverYear > 200) {
1491                        break;
1492                    }
1493                    // There might be "overlapping" dates.
1494                    GregorianCalendar gc = (GregorianCalendar) clone();
1495                    gc.setLenient(true);
1496                    gc.setTimeInMillis(gregorianCutover);
1497                    int v1 = gc.getActualMaximum(field);
1498                    gc.setTimeInMillis(gregorianCutover - 1);
1499                    int v2 = gc.getActualMaximum(field);
1500                    return Math.max(MAX_VALUES[field], Math.max(v1, v2));
1501                }
1502                }
1503                return MAX_VALUES[field];
1504            }
1505
1506            /**
1507             * Returns the highest minimum value for the given calendar field
1508             * of this <code>GregorianCalendar</code> instance. The highest
1509             * minimum value is defined as the largest value returned by
1510             * {@link #getActualMinimum(int)} for any possible time value,
1511             * taking into consideration the current values of the
1512             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1513             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1514             * {@link #getGregorianChange() getGregorianChange} and
1515             * {@link Calendar#getTimeZone() getTimeZone} methods.
1516             *
1517             * @param field the calendar field.
1518             * @return the highest minimum value for the given calendar field.
1519             * @see #getMinimum(int)
1520             * @see #getMaximum(int)
1521             * @see #getLeastMaximum(int)
1522             * @see #getActualMinimum(int)
1523             * @see #getActualMaximum(int)
1524             */
1525            public int getGreatestMinimum(int field) {
1526                if (field == DAY_OF_MONTH) {
1527                    BaseCalendar.Date d = getGregorianCutoverDate();
1528                    long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
1529                    d = getCalendarDate(mon1);
1530                    return Math.max(MIN_VALUES[field], d.getDayOfMonth());
1531                }
1532                return MIN_VALUES[field];
1533            }
1534
1535            /**
1536             * Returns the lowest maximum value for the given calendar field
1537             * of this <code>GregorianCalendar</code> instance. The lowest
1538             * maximum value is defined as the smallest value returned by
1539             * {@link #getActualMaximum(int)} for any possible time value,
1540             * taking into consideration the current values of the
1541             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1542             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1543             * {@link #getGregorianChange() getGregorianChange} and
1544             * {@link Calendar#getTimeZone() getTimeZone} methods.
1545             *
1546             * @param field the calendar field
1547             * @return the lowest maximum value for the given calendar field.
1548             * @see #getMinimum(int)
1549             * @see #getMaximum(int)
1550             * @see #getGreatestMinimum(int)
1551             * @see #getActualMinimum(int)
1552             * @see #getActualMaximum(int)
1553             */
1554            public int getLeastMaximum(int field) {
1555                switch (field) {
1556                case MONTH:
1557                case DAY_OF_MONTH:
1558                case DAY_OF_YEAR:
1559                case WEEK_OF_YEAR:
1560                case WEEK_OF_MONTH:
1561                case DAY_OF_WEEK_IN_MONTH:
1562                case YEAR: {
1563                    GregorianCalendar gc = (GregorianCalendar) clone();
1564                    gc.setLenient(true);
1565                    gc.setTimeInMillis(gregorianCutover);
1566                    int v1 = gc.getActualMaximum(field);
1567                    gc.setTimeInMillis(gregorianCutover - 1);
1568                    int v2 = gc.getActualMaximum(field);
1569                    return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
1570                }
1571                }
1572                return LEAST_MAX_VALUES[field];
1573            }
1574
1575            /**
1576             * Returns the minimum value that this calendar field could have,
1577             * taking into consideration the given time value and the current
1578             * values of the
1579             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1580             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1581             * {@link #getGregorianChange() getGregorianChange} and
1582             * {@link Calendar#getTimeZone() getTimeZone} methods.
1583             *
1584             * <p>For example, if the Gregorian change date is January 10,
1585             * 1970 and the date of this <code>GregorianCalendar</code> is
1586             * January 20, 1970, the actual minimum value of the
1587             * <code>DAY_OF_MONTH</code> field is 10 because the previous date
1588             * of January 10, 1970 is December 27, 1996 (in the Julian
1589             * calendar). Therefore, December 28, 1969 to January 9, 1970
1590             * don't exist.
1591             *
1592             * @param field the calendar field
1593             * @return the minimum of the given field for the time value of
1594             * this <code>GregorianCalendar</code>
1595             * @see #getMinimum(int)
1596             * @see #getMaximum(int)
1597             * @see #getGreatestMinimum(int)
1598             * @see #getLeastMaximum(int)
1599             * @see #getActualMaximum(int)
1600             * @since 1.2
1601             */
1602            public int getActualMinimum(int field) {
1603                if (field == DAY_OF_MONTH) {
1604                    GregorianCalendar gc = getNormalizedCalendar();
1605                    int year = gc.cdate.getNormalizedYear();
1606                    if (year == gregorianCutoverYear
1607                            || year == gregorianCutoverYearJulian) {
1608                        long month1 = getFixedDateMonth1(gc.cdate, gc.calsys
1609                                .getFixedDate(gc.cdate));
1610                        BaseCalendar.Date d = getCalendarDate(month1);
1611                        return d.getDayOfMonth();
1612                    }
1613                }
1614                return getMinimum(field);
1615            }
1616
1617            /**
1618             * Returns the maximum value that this calendar field could have,
1619             * taking into consideration the given time value and the current
1620             * values of the
1621             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1622             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1623             * {@link #getGregorianChange() getGregorianChange} and
1624             * {@link Calendar#getTimeZone() getTimeZone} methods.
1625             * For example, if the date of this instance is February 1, 2004,
1626             * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1627             * is 29 because 2004 is a leap year, and if the date of this
1628             * instance is February 1, 2005, it's 28.
1629             *
1630             * @param field the calendar field
1631             * @return the maximum of the given field for the time value of
1632             * this <code>GregorianCalendar</code>
1633             * @see #getMinimum(int)
1634             * @see #getMaximum(int)
1635             * @see #getGreatestMinimum(int)
1636             * @see #getLeastMaximum(int)
1637             * @see #getActualMinimum(int)
1638             * @since 1.2
1639             */
1640            public int getActualMaximum(int field) {
1641                final int fieldsForFixedMax = ERA_MASK | DAY_OF_WEEK_MASK
1642                        | HOUR_MASK | AM_PM_MASK | HOUR_OF_DAY_MASK
1643                        | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK
1644                        | ZONE_OFFSET_MASK | DST_OFFSET_MASK;
1645                if ((fieldsForFixedMax & (1 << field)) != 0) {
1646                    return getMaximum(field);
1647                }
1648
1649                GregorianCalendar gc = getNormalizedCalendar();
1650                BaseCalendar.Date date = gc.cdate;
1651                BaseCalendar cal = gc.calsys;
1652                int normalizedYear = date.getNormalizedYear();
1653
1654                int value = -1;
1655                switch (field) {
1656                case MONTH: {
1657                    if (!gc.isCutoverYear(normalizedYear)) {
1658                        value = DECEMBER;
1659                        break;
1660                    }
1661
1662                    // January 1 of the next year may or may not exist.
1663                    long nextJan1;
1664                    do {
1665                        nextJan1 = gcal.getFixedDate(++normalizedYear,
1666                                BaseCalendar.JANUARY, 1, null);
1667                    } while (nextJan1 < gregorianCutoverDate);
1668                    BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1669                    cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
1670                    value = d.getMonth() - 1;
1671                }
1672                    break;
1673
1674                case DAY_OF_MONTH: {
1675                    value = cal.getMonthLength(date);
1676                    if (!gc.isCutoverYear(normalizedYear)
1677                            || date.getDayOfMonth() == value) {
1678                        break;
1679                    }
1680
1681                    // Handle cutover year.
1682                    long fd = gc.getCurrentFixedDate();
1683                    if (fd >= gregorianCutoverDate) {
1684                        break;
1685                    }
1686                    int monthLength = gc.actualMonthLength();
1687                    long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd)
1688                            + monthLength - 1;
1689                    // Convert the fixed date to its calendar date.
1690                    BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
1691                    value = d.getDayOfMonth();
1692                }
1693                    break;
1694
1695                case DAY_OF_YEAR: {
1696                    if (!gc.isCutoverYear(normalizedYear)) {
1697                        value = cal.getYearLength(date);
1698                        break;
1699                    }
1700
1701                    // Handle cutover year.
1702                    long jan1;
1703                    if (gregorianCutoverYear == gregorianCutoverYearJulian) {
1704                        BaseCalendar cocal = gc.getCutoverCalendarSystem();
1705                        jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
1706                    } else if (normalizedYear == gregorianCutoverYearJulian) {
1707                        jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
1708                    } else {
1709                        jan1 = gregorianCutoverDate;
1710                    }
1711                    // January 1 of the next year may or may not exist.
1712                    long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1,
1713                            null);
1714                    if (nextJan1 < gregorianCutoverDate) {
1715                        nextJan1 = gregorianCutoverDate;
1716                    }
1717                    assert jan1 <= cal.getFixedDate(date.getNormalizedYear(),
1718                            date.getMonth(), date.getDayOfMonth(), date);
1719                    assert nextJan1 >= cal.getFixedDate(date
1720                            .getNormalizedYear(), date.getMonth(), date
1721                            .getDayOfMonth(), date);
1722                    value = (int) (nextJan1 - jan1);
1723                }
1724                    break;
1725
1726                case WEEK_OF_YEAR: {
1727                    if (!gc.isCutoverYear(normalizedYear)) {
1728                        // Get the day of week of January 1 of the year
1729                        CalendarDate d = cal
1730                                .newCalendarDate(TimeZone.NO_TIMEZONE);
1731                        d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
1732                        int dayOfWeek = cal.getDayOfWeek(d);
1733                        // Normalize the day of week with the firstDayOfWeek value
1734                        dayOfWeek -= getFirstDayOfWeek();
1735                        if (dayOfWeek < 0) {
1736                            dayOfWeek += 7;
1737                        }
1738                        value = 52;
1739                        int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
1740                        if ((magic == 6)
1741                                || (date.isLeapYear() && (magic == 5 || magic == 12))) {
1742                            value++;
1743                        }
1744                        break;
1745                    }
1746
1747                    if (gc == this ) {
1748                        gc = (GregorianCalendar) gc.clone();
1749                    }
1750                    gc.set(DAY_OF_YEAR, getActualMaximum(DAY_OF_YEAR));
1751                    value = gc.get(WEEK_OF_YEAR);
1752                }
1753                    break;
1754
1755                case WEEK_OF_MONTH: {
1756                    if (!gc.isCutoverYear(normalizedYear)) {
1757                        CalendarDate d = cal.newCalendarDate(null);
1758                        d.setDate(date.getYear(), date.getMonth(), 1);
1759                        int dayOfWeek = cal.getDayOfWeek(d);
1760                        int monthLength = cal.getMonthLength(d);
1761                        dayOfWeek -= getFirstDayOfWeek();
1762                        if (dayOfWeek < 0) {
1763                            dayOfWeek += 7;
1764                        }
1765                        int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1766                        value = 3;
1767                        if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1768                            value++;
1769                        }
1770                        monthLength -= nDaysFirstWeek + 7 * 3;
1771                        if (monthLength > 0) {
1772                            value++;
1773                            if (monthLength > 7) {
1774                                value++;
1775                            }
1776                        }
1777                        break;
1778                    }
1779
1780                    // Cutover year handling
1781                    if (gc == this ) {
1782                        gc = (GregorianCalendar) gc.clone();
1783                    }
1784                    int y = gc.internalGet(YEAR);
1785                    int m = gc.internalGet(MONTH);
1786                    do {
1787                        value = gc.get(WEEK_OF_MONTH);
1788                        gc.add(WEEK_OF_MONTH, +1);
1789                    } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
1790                }
1791                    break;
1792
1793                case DAY_OF_WEEK_IN_MONTH: {
1794                    // may be in the Gregorian cutover month
1795                    int ndays, dow1;
1796                    int dow = date.getDayOfWeek();
1797                    if (!gc.isCutoverYear(normalizedYear)) {
1798                        BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1799                        ndays = cal.getMonthLength(d);
1800                        d.setDayOfMonth(1);
1801                        cal.normalize(d);
1802                        dow1 = d.getDayOfWeek();
1803                    } else {
1804                        // Let a cloned GregorianCalendar take care of the cutover cases.
1805                        if (gc == this ) {
1806                            gc = (GregorianCalendar) clone();
1807                        }
1808                        ndays = gc.actualMonthLength();
1809                        gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
1810                        dow1 = gc.get(DAY_OF_WEEK);
1811                    }
1812                    int x = dow - dow1;
1813                    if (x < 0) {
1814                        x += 7;
1815                    }
1816                    ndays -= x;
1817                    value = (ndays + 6) / 7;
1818                }
1819                    break;
1820
1821                case YEAR:
1822                    /* The year computation is no different, in principle, from the
1823                     * others, however, the range of possible maxima is large.  In
1824                     * addition, the way we know we've exceeded the range is different.
1825                     * For these reasons, we use the special case code below to handle
1826                     * this field.
1827                     *
1828                     * The actual maxima for YEAR depend on the type of calendar:
1829                     *
1830                     *     Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
1831                     *     Julian    = Dec  2, 292269055 BCE - Jan  3, 292272993 CE
1832                     *     Hybrid    = Dec  2, 292269055 BCE - Aug 17, 292278994 CE
1833                     *
1834                     * We know we've exceeded the maximum when either the month, date,
1835                     * time, or era changes in response to setting the year.  We don't
1836                     * check for month, date, and time here because the year and era are
1837                     * sufficient to detect an invalid year setting.  NOTE: If code is
1838                     * added to check the month and date in the future for some reason,
1839                     * Feb 29 must be allowed to shift to Mar 1 when setting the year.
1840                     */
1841                {
1842                    if (gc == this ) {
1843                        gc = (GregorianCalendar) clone();
1844                    }
1845
1846                    // Calculate the millisecond offset from the beginning
1847                    // of the year of this calendar and adjust the max
1848                    // year value if we are beyond the limit in the max
1849                    // year.
1850                    long current = gc.getYearOffsetInMillis();
1851
1852                    if (gc.internalGetEra() == CE) {
1853                        gc.setTimeInMillis(Long.MAX_VALUE);
1854                        value = gc.get(YEAR);
1855                        long maxEnd = gc.getYearOffsetInMillis();
1856                        if (current > maxEnd) {
1857                            value--;
1858                        }
1859                    } else {
1860                        CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ? gcal
1861                                : getJulianCalendarSystem();
1862                        CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE,
1863                                getZone());
1864                        long maxEnd = (cal.getDayOfYear(d) - 1) * 24
1865                                + d.getHours();
1866                        maxEnd *= 60;
1867                        maxEnd += d.getMinutes();
1868                        maxEnd *= 60;
1869                        maxEnd += d.getSeconds();
1870                        maxEnd *= 1000;
1871                        maxEnd += d.getMillis();
1872                        value = d.getYear();
1873                        if (value <= 0) {
1874                            assert mincal == gcal;
1875                            value = 1 - value;
1876                        }
1877                        if (current < maxEnd) {
1878                            value--;
1879                        }
1880                    }
1881                }
1882                    break;
1883
1884                default:
1885                    throw new ArrayIndexOutOfBoundsException(field);
1886                }
1887                return value;
1888            }
1889
1890            /**
1891             * Returns the millisecond offset from the beginning of this
1892             * year. This Calendar object must have been normalized.
1893             */
1894            private final long getYearOffsetInMillis() {
1895                long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
1896                t += internalGet(HOUR_OF_DAY);
1897                t *= 60;
1898                t += internalGet(MINUTE);
1899                t *= 60;
1900                t += internalGet(SECOND);
1901                t *= 1000;
1902                return t + internalGet(MILLISECOND)
1903                        - (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
1904            }
1905
1906            public Object clone() {
1907                GregorianCalendar other = (GregorianCalendar) super .clone();
1908
1909                other.gdate = (BaseCalendar.Date) gdate.clone();
1910                if (cdate != null) {
1911                    if (cdate != gdate) {
1912                        other.cdate = (BaseCalendar.Date) cdate.clone();
1913                    } else {
1914                        other.cdate = other.gdate;
1915                    }
1916                }
1917                other.originalFields = null;
1918                other.zoneOffsets = null;
1919                return other;
1920            }
1921
1922            public TimeZone getTimeZone() {
1923                TimeZone zone = super .getTimeZone();
1924                // To share the zone by CalendarDates
1925                gdate.setZone(zone);
1926                if (cdate != null && cdate != gdate) {
1927                    cdate.setZone(zone);
1928                }
1929                return zone;
1930            }
1931
1932            public void setTimeZone(TimeZone zone) {
1933                super .setTimeZone(zone);
1934                // To share the zone by CalendarDates
1935                gdate.setZone(zone);
1936                if (cdate != null && cdate != gdate) {
1937                    cdate.setZone(zone);
1938                }
1939            }
1940
1941            //////////////////////
1942            // Proposed public API
1943            //////////////////////
1944
1945            /**
1946             * Returns the year that corresponds to the <code>WEEK_OF_YEAR</code> field.
1947             * This may be one year before or after the Gregorian or Julian year stored
1948             * in the <code>YEAR</code> field.  For example, January 1, 1999 is considered
1949             * Friday of week 53 of 1998 (if minimal days in first week is
1950             * 2 or less, and the first day of the week is Sunday).  Given
1951             * these same settings, the ISO year of January 1, 1999 is
1952             * 1998.
1953             * 
1954             * <p>This method calls {@link Calendar#complete} before
1955             * calculating the week-based year.
1956             *
1957             * @return the year corresponding to the <code>WEEK_OF_YEAR</code> field, which
1958             * may be one year before or after the <code>YEAR</code> field.
1959             * @see #YEAR
1960             * @see #WEEK_OF_YEAR
1961             */
1962            /*
1963            public int getWeekBasedYear() {
1964                complete();
1965            // TODO: Below doesn't work for gregorian cutover...
1966                int weekOfYear = internalGet(WEEK_OF_YEAR);
1967                int year = internalGet(YEAR);
1968                if (internalGet(MONTH) == Calendar.JANUARY) {
1969                    if (weekOfYear >= 52) {
1970                        --year;
1971                    }
1972                } else {
1973                    if (weekOfYear == 1) {
1974                        ++year;
1975                    }
1976                }
1977                return year;
1978            }
1979             */
1980
1981            /////////////////////////////
1982            // Time => Fields computation
1983            /////////////////////////////
1984            /**
1985             * The fixed date corresponding to gdate. If the value is
1986             * Long.MIN_VALUE, the fixed date value is unknown. Currently,
1987             * Julian calendar dates are not cached.
1988             */
1989            transient private long cachedFixedDate = Long.MIN_VALUE;
1990
1991            /**
1992             * Converts the time value (millisecond offset from the <a
1993             * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
1994             * The time is <em>not</em>
1995             * recomputed first; to recompute the time, then the fields, call the
1996             * <code>complete</code> method.
1997             *
1998             * @see Calendar#complete
1999             */
2000            protected void computeFields() {
2001                int mask = 0;
2002                if (isPartiallyNormalized()) {
2003                    // Determine which calendar fields need to be computed.
2004                    mask = getSetStateFields();
2005                    int fieldMask = ~mask & ALL_FIELDS;
2006                    // We have to call computTime in case calsys == null in
2007                    // order to set calsys and cdate. (6263644)
2008                    if (fieldMask != 0 || calsys == null) {
2009                        mask |= computeFields(fieldMask, mask
2010                                & (ZONE_OFFSET_MASK | DST_OFFSET_MASK));
2011                        assert mask == ALL_FIELDS;
2012                    }
2013                } else {
2014                    mask = ALL_FIELDS;
2015                    computeFields(mask, 0);
2016                }
2017                // After computing all the fields, set the field state to `COMPUTED'.
2018                setFieldsComputed(mask);
2019            }
2020
2021            /**
2022             * This computeFields implements the conversion from UTC
2023             * (millisecond offset from the Epoch) to calendar
2024             * field values. fieldMask specifies which fields to change the
2025             * setting state to COMPUTED, although all fields are set to
2026             * the correct values. This is required to fix 4685354.
2027             *
2028             * @param fieldMask a bit mask to specify which fields to change
2029             * the setting state.
2030             * @param tzMask a bit mask to specify which time zone offset
2031             * fields to be used for time calculations
2032             * @return a new field mask that indicates what field values have
2033             * actually been set.
2034             */
2035            private int computeFields(int fieldMask, int tzMask) {
2036                int zoneOffset = 0;
2037                TimeZone tz = getZone();
2038                if (zoneOffsets == null) {
2039                    zoneOffsets = new int[2];
2040                }
2041                if (tzMask != (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) {
2042                    if (tz instanceof  ZoneInfo) {
2043                        zoneOffset = ((ZoneInfo) tz).getOffsets(time,
2044                                zoneOffsets);
2045                    } else {
2046                        zoneOffset = tz.getOffset(time);
2047                        zoneOffsets[0] = tz.getRawOffset();
2048                        zoneOffsets[1] = zoneOffset - zoneOffsets[0];
2049                    }
2050                }
2051                if (tzMask != 0) {
2052                    if (isFieldSet(tzMask, ZONE_OFFSET)) {
2053                        zoneOffsets[0] = internalGet(ZONE_OFFSET);
2054                    }
2055                    if (isFieldSet(tzMask, DST_OFFSET)) {
2056                        zoneOffsets[1] = internalGet(DST_OFFSET);
2057                    }
2058                    zoneOffset = zoneOffsets[0] + zoneOffsets[1];
2059                }
2060
2061                // By computing time and zoneOffset separately, we can take
2062                // the wider range of time+zoneOffset than the previous
2063                // implementation.
2064                long fixedDate = zoneOffset / ONE_DAY;
2065                int timeOfDay = zoneOffset % (int) ONE_DAY;
2066                fixedDate += time / ONE_DAY;
2067                timeOfDay += (int) (time % ONE_DAY);
2068                if (timeOfDay >= ONE_DAY) {
2069                    timeOfDay -= ONE_DAY;
2070                    ++fixedDate;
2071                } else {
2072                    while (timeOfDay < 0) {
2073                        timeOfDay += ONE_DAY;
2074                        --fixedDate;
2075                    }
2076                }
2077                fixedDate += EPOCH_OFFSET;
2078
2079                int era = CE;
2080                int year;
2081                if (fixedDate >= gregorianCutoverDate) {
2082                    // Handle Gregorian dates.
2083                    assert cachedFixedDate == Long.MIN_VALUE
2084                            || gdate.isNormalized() : "cache control: not normalized";
2085                    assert cachedFixedDate == Long.MIN_VALUE
2086                            || gcal.getFixedDate(gdate.getNormalizedYear(),
2087                                    gdate.getMonth(), gdate.getDayOfMonth(),
2088                                    gdate) == cachedFixedDate : "cache control: inconsictency"
2089                            + ", cachedFixedDate="
2090                            + cachedFixedDate
2091                            + ", computed="
2092                            + gcal.getFixedDate(gdate.getNormalizedYear(),
2093                                    gdate.getMonth(), gdate.getDayOfMonth(),
2094                                    gdate) + ", date=" + gdate;
2095
2096                    // See if we can use gdate to avoid date calculation.
2097                    if (fixedDate != cachedFixedDate) {
2098                        gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
2099                        cachedFixedDate = fixedDate;
2100                    }
2101
2102                    year = gdate.getYear();
2103                    if (year <= 0) {
2104                        year = 1 - year;
2105                        era = BCE;
2106                    }
2107                    calsys = gcal;
2108                    cdate = gdate;
2109                    assert cdate.getDayOfWeek() > 0 : "dow="
2110                            + cdate.getDayOfWeek() + ", date=" + cdate;
2111                } else {
2112                    // Handle Julian calendar dates.
2113                    calsys = getJulianCalendarSystem();
2114                    cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
2115                    jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
2116                    Era e = cdate.getEra();
2117                    if (e == jeras[0]) {
2118                        era = BCE;
2119                    }
2120                    year = cdate.getYear();
2121                }
2122
2123                // Always set the ERA and YEAR values.
2124                internalSet(ERA, era);
2125                internalSet(YEAR, year);
2126                int mask = fieldMask | (ERA_MASK | YEAR_MASK);
2127
2128                int month = cdate.getMonth() - 1; // 0-based
2129                int dayOfMonth = cdate.getDayOfMonth();
2130
2131                // Set the basic date fields.
2132                if ((fieldMask & (MONTH_MASK | DAY_OF_MONTH_MASK | DAY_OF_WEEK_MASK)) != 0) {
2133                    internalSet(MONTH, month);
2134                    internalSet(DAY_OF_MONTH, dayOfMonth);
2135                    internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
2136                    mask |= MONTH_MASK | DAY_OF_MONTH_MASK | DAY_OF_WEEK_MASK;
2137                }
2138
2139                if ((fieldMask & (HOUR_OF_DAY_MASK | AM_PM_MASK | HOUR_MASK
2140                        | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK)) != 0) {
2141                    if (timeOfDay != 0) {
2142                        int hours = timeOfDay / ONE_HOUR;
2143                        internalSet(HOUR_OF_DAY, hours);
2144                        internalSet(AM_PM, hours / 12); // Assume AM == 0
2145                        internalSet(HOUR, hours % 12);
2146                        int r = timeOfDay % ONE_HOUR;
2147                        internalSet(MINUTE, r / ONE_MINUTE);
2148                        r %= ONE_MINUTE;
2149                        internalSet(SECOND, r / ONE_SECOND);
2150                        internalSet(MILLISECOND, r % ONE_SECOND);
2151                    } else {
2152                        internalSet(HOUR_OF_DAY, 0);
2153                        internalSet(AM_PM, AM);
2154                        internalSet(HOUR, 0);
2155                        internalSet(MINUTE, 0);
2156                        internalSet(SECOND, 0);
2157                        internalSet(MILLISECOND, 0);
2158                    }
2159                    mask |= (HOUR_OF_DAY_MASK | AM_PM_MASK | HOUR_MASK
2160                            | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK);
2161                }
2162
2163                if ((fieldMask & (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) != 0) {
2164                    internalSet(ZONE_OFFSET, zoneOffsets[0]);
2165                    internalSet(DST_OFFSET, zoneOffsets[1]);
2166                    mask |= (ZONE_OFFSET_MASK | DST_OFFSET_MASK);
2167                }
2168
2169                if ((fieldMask & (DAY_OF_YEAR_MASK | WEEK_OF_YEAR_MASK
2170                        | WEEK_OF_MONTH_MASK | DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
2171                    int normalizedYear = cdate.getNormalizedYear();
2172                    long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1,
2173                            1, cdate);
2174                    int dayOfYear = (int) (fixedDate - fixedDateJan1) + 1;
2175                    long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
2176                    int cutoverGap = 0;
2177                    int cutoverYear = (calsys == gcal) ? gregorianCutoverYear
2178                            : gregorianCutoverYearJulian;
2179                    int relativeDayOfMonth = dayOfMonth - 1;
2180
2181                    // If we are in the cutover year, we need some special handling.
2182                    if (normalizedYear == cutoverYear) {
2183                        // Need to take care of the "missing" days.
2184                        if (getCutoverCalendarSystem() == jcal) {
2185                            // We need to find out where we are. The cutover
2186                            // gap could even be more than one year.  (One
2187                            // year difference in ~48667 years.)
2188                            fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
2189                            if (fixedDate >= gregorianCutoverDate) {
2190                                fixedDateMonth1 = getFixedDateMonth1(cdate,
2191                                        fixedDate);
2192                            }
2193                        }
2194                        int realDayOfYear = (int) (fixedDate - fixedDateJan1) + 1;
2195                        cutoverGap = dayOfYear - realDayOfYear;
2196                        dayOfYear = realDayOfYear;
2197                        relativeDayOfMonth = (int) (fixedDate - fixedDateMonth1);
2198                    }
2199                    internalSet(DAY_OF_YEAR, dayOfYear);
2200                    internalSet(DAY_OF_WEEK_IN_MONTH,
2201                            relativeDayOfMonth / 7 + 1);
2202
2203                    int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
2204
2205                    // The spec is to calculate WEEK_OF_YEAR in the
2206                    // ISO8601-style. This creates problems, though.
2207                    if (weekOfYear == 0) {
2208                        // If the date belongs to the last week of the
2209                        // previous year, use the week number of "12/31" of
2210                        // the "previous" year. Again, if the previous year is
2211                        // the Gregorian cutover year, we need to take care of
2212                        // it.  Usually the previous day of January 1 is
2213                        // December 31, which is not always true in
2214                        // GregorianCalendar.
2215                        long fixedDec31 = fixedDateJan1 - 1;
2216                        long prevJan1;
2217                        if (normalizedYear > (cutoverYear + 1)) {
2218                            prevJan1 = fixedDateJan1 - 365;
2219                            if (CalendarUtils
2220                                    .isGregorianLeapYear(normalizedYear - 1)) {
2221                                --prevJan1;
2222                            }
2223                        } else {
2224                            BaseCalendar calForJan1 = calsys;
2225                            int prevYear = normalizedYear - 1;
2226                            if (prevYear == cutoverYear) {
2227                                calForJan1 = getCutoverCalendarSystem();
2228                            }
2229                            prevJan1 = calForJan1.getFixedDate(prevYear,
2230                                    BaseCalendar.JANUARY, 1, null);
2231                            while (prevJan1 > fixedDec31) {
2232                                prevJan1 = getJulianCalendarSystem()
2233                                        .getFixedDate(--prevYear,
2234                                                BaseCalendar.JANUARY, 1, null);
2235                            }
2236                        }
2237                        weekOfYear = getWeekNumber(prevJan1, fixedDec31);
2238                    } else {
2239                        if (normalizedYear > gregorianCutoverYear
2240                                || normalizedYear < (gregorianCutoverYearJulian - 1)) {
2241                            // Regular years
2242                            if (weekOfYear >= 52) {
2243                                long nextJan1 = fixedDateJan1 + 365;
2244                                if (cdate.isLeapYear()) {
2245                                    nextJan1++;
2246                                }
2247                                long nextJan1st = calsys
2248                                        .getDayOfWeekDateOnOrBefore(
2249                                                nextJan1 + 6,
2250                                                getFirstDayOfWeek());
2251                                int ndays = (int) (nextJan1st - nextJan1);
2252                                if (ndays >= getMinimalDaysInFirstWeek()
2253                                        && fixedDate >= (nextJan1st - 7)) {
2254                                    // The first days forms a week in which the date is included.
2255                                    weekOfYear = 1;
2256                                }
2257                            }
2258                        } else {
2259                            BaseCalendar calForJan1 = calsys;
2260                            int nextYear = normalizedYear + 1;
2261                            if (nextYear == (gregorianCutoverYearJulian + 1)
2262                                    && nextYear < gregorianCutoverYear) {
2263                                // In case the gap is more than one year.
2264                                nextYear = gregorianCutoverYear;
2265                            }
2266                            if (nextYear == gregorianCutoverYear) {
2267                                calForJan1 = getCutoverCalendarSystem();
2268                            }
2269                            long nextJan1 = calForJan1.getFixedDate(nextYear,
2270                                    BaseCalendar.JANUARY, 1, null);
2271                            if (nextJan1 < fixedDate) {
2272                                nextJan1 = gregorianCutoverDate;
2273                                calForJan1 = gcal;
2274                            }
2275                            long nextJan1st = calForJan1
2276                                    .getDayOfWeekDateOnOrBefore(nextJan1 + 6,
2277                                            getFirstDayOfWeek());
2278                            int ndays = (int) (nextJan1st - nextJan1);
2279                            if (ndays >= getMinimalDaysInFirstWeek()
2280                                    && fixedDate >= (nextJan1st - 7)) {
2281                                // The first days forms a week in which the date is included.
2282                                weekOfYear = 1;
2283                            }
2284                        }
2285                    }
2286                    internalSet(WEEK_OF_YEAR, weekOfYear);
2287                    internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1,
2288                            fixedDate));
2289                    mask |= (DAY_OF_YEAR_MASK | WEEK_OF_YEAR_MASK
2290                            | WEEK_OF_MONTH_MASK | DAY_OF_WEEK_IN_MONTH_MASK);
2291                }
2292                return mask;
2293            }
2294
2295            /**
2296             * Returns the number of weeks in a period between fixedDay1 and
2297             * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
2298             * is applied to calculate the number of weeks.
2299             *
2300             * @param fixedDay1 the fixed date of the first day of the period
2301             * @param fixedDate the fixed date of the last day of the period
2302             * @return the number of weeks of the given period
2303             */
2304            private final int getWeekNumber(long fixedDay1, long fixedDate) {
2305                // We can always use `gcal' since Julian and Gregorian are the
2306                // same thing for this calculation.
2307                long fixedDay1st = gcal.getDayOfWeekDateOnOrBefore(
2308                        fixedDay1 + 6, getFirstDayOfWeek());
2309                int ndays = (int) (fixedDay1st - fixedDay1);
2310                assert ndays <= 7;
2311                if (ndays >= getMinimalDaysInFirstWeek()) {
2312                    fixedDay1st -= 7;
2313                }
2314                int normalizedDayOfPeriod = (int) (fixedDate - fixedDay1st);
2315                if (normalizedDayOfPeriod >= 0) {
2316                    return normalizedDayOfPeriod / 7 + 1;
2317                }
2318                return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
2319            }
2320
2321            /**
2322             * Converts calendar field values to the time value (millisecond
2323             * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
2324             *
2325             * @exception IllegalArgumentException if any calendar fields are invalid.
2326             */
2327            protected void computeTime() {
2328                // In non-lenient mode, perform brief checking of calendar
2329                // fields which have been set externally. Through this
2330                // checking, the field values are stored in originalFields[]
2331                // to see if any of them are normalized later.
2332                if (!isLenient()) {
2333                    if (originalFields == null) {
2334                        originalFields = new int[FIELD_COUNT];
2335                    }
2336                    for (int field = 0; field < FIELD_COUNT; field++) {
2337                        int value = internalGet(field);
2338                        if (isExternallySet(field)) {
2339                            // Quick validation for any out of range values
2340                            if (value < getMinimum(field)
2341                                    || value > getMaximum(field)) {
2342                                throw new IllegalArgumentException(
2343                                        getFieldName(field));
2344                            }
2345                        }
2346                        originalFields[field] = value;
2347                    }
2348                }
2349
2350                // Let the super class determine which calendar fields to be
2351                // used to calculate the time.
2352                int fieldMask = selectFields();
2353
2354                // The year defaults to the epoch start. We don't check
2355                // fieldMask for YEAR because YEAR is a mandatory field to
2356                // determine the date.
2357                int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
2358
2359                int era = internalGetEra();
2360                if (era == BCE) {
2361                    year = 1 - year;
2362                } else if (era != CE) {
2363                    // Even in lenient mode we disallow ERA values other than CE & BCE.
2364                    // (The same normalization rule as add()/roll() could be
2365                    // applied here in lenient mode. But this checking is kept
2366                    // unchanged for compatibility as of 1.5.)
2367                    throw new IllegalArgumentException("Invalid era");
2368                }
2369
2370                // If year is 0 or negative, we need to set the ERA value later.
2371                if (year <= 0 && !isSet(ERA)) {
2372                    fieldMask |= ERA_MASK;
2373                    setFieldsComputed(ERA_MASK);
2374                }
2375
2376                // Calculate the time of day. We rely on the convention that
2377                // an UNSET field has 0.
2378                long timeOfDay = 0;
2379                if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
2380                    timeOfDay += (long) internalGet(HOUR_OF_DAY);
2381                } else {
2382                    timeOfDay += internalGet(HOUR);
2383                    // The default value of AM_PM is 0 which designates AM.
2384                    if (isFieldSet(fieldMask, AM_PM)) {
2385                        timeOfDay += 12 * internalGet(AM_PM);
2386                    }
2387                }
2388                timeOfDay *= 60;
2389                timeOfDay += internalGet(MINUTE);
2390                timeOfDay *= 60;
2391                timeOfDay += internalGet(SECOND);
2392                timeOfDay *= 1000;
2393                timeOfDay += internalGet(MILLISECOND);
2394
2395                // Convert the time of day to the number of days and the
2396                // millisecond offset from midnight.
2397                long fixedDate = timeOfDay / ONE_DAY;
2398                timeOfDay %= ONE_DAY;
2399                while (timeOfDay < 0) {
2400                    timeOfDay += ONE_DAY;
2401                    --fixedDate;
2402                }
2403
2404                // Calculate the fixed date since January 1, 1 (Gregorian).
2405                calculateFixedDate: {
2406                    long gfd, jfd;
2407                    if (year > gregorianCutoverYear
2408                            && year > gregorianCutoverYearJulian) {
2409                        gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2410                        if (gfd >= gregorianCutoverDate) {
2411                            fixedDate = gfd;
2412                            break calculateFixedDate;
2413                        }
2414                        jfd = fixedDate
2415                                + getFixedDate(getJulianCalendarSystem(), year,
2416                                        fieldMask);
2417                    } else if (year < gregorianCutoverYear
2418                            && year < gregorianCutoverYearJulian) {
2419                        jfd = fixedDate
2420                                + getFixedDate(getJulianCalendarSystem(), year,
2421                                        fieldMask);
2422                        if (jfd < gregorianCutoverDate) {
2423                            fixedDate = jfd;
2424                            break calculateFixedDate;
2425                        }
2426                        gfd = jfd;
2427                    } else {
2428                        gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
2429                        jfd = fixedDate
2430                                + getFixedDate(getJulianCalendarSystem(), year,
2431                                        fieldMask);
2432                    }
2433                    // Now we have to determine which calendar date it is.
2434                    if (gfd >= gregorianCutoverDate) {
2435                        if (jfd >= gregorianCutoverDate) {
2436                            fixedDate = gfd;
2437                        } else {
2438                            // The date is in an "overlapping" period. No way
2439                            // to disambiguate it. Determine it using the
2440                            // previous date calculation.
2441                            if (calsys == gcal || calsys == null) {
2442                                fixedDate = gfd;
2443                            } else {
2444                                fixedDate = jfd;
2445                            }
2446                        }
2447                    } else {
2448                        if (jfd < gregorianCutoverDate) {
2449                            fixedDate = jfd;
2450                        } else {
2451                            // The date is in a "missing" period.
2452                            if (!isLenient()) {
2453                                throw new IllegalArgumentException(
2454                                        "the specified date doesn't exist");
2455                            }
2456                            // Take the Julian date for compatibility, which
2457                            // will produce a Gregorian date.
2458                            fixedDate = jfd;
2459                        }
2460                    }
2461                }
2462
2463                // millis represents local wall-clock time in milliseconds.
2464                long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
2465
2466                // Compute the time zone offset and DST offset.  There are two potential
2467                // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
2468                // for discussion purposes here.
2469                // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
2470                //    can be in standard or in DST depending.  However, 2:00 am is an invalid
2471                //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
2472                //    We assume standard time.
2473                // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
2474                //    can be in standard or DST.  Both are valid representations (the rep
2475                //    jumps from 1:59:59 DST to 1:00:00 Std).
2476                //    Again, we assume standard time.
2477                // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
2478                // or DST_OFFSET fields; then we use those fields.
2479                TimeZone zone = getZone();
2480                if (zoneOffsets == null) {
2481                    zoneOffsets = new int[2];
2482                }
2483                int tzMask = fieldMask & (ZONE_OFFSET_MASK | DST_OFFSET_MASK);
2484                if (tzMask != (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) {
2485                    if (zone instanceof  ZoneInfo) {
2486                        ((ZoneInfo) zone).getOffsetsByWall(millis, zoneOffsets);
2487                    } else {
2488                        int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ? internalGet(ZONE_OFFSET)
2489                                : zone.getRawOffset();
2490                        zone.getOffsets(millis - gmtOffset, zoneOffsets);
2491                    }
2492                }
2493                if (tzMask != 0) {
2494                    if (isFieldSet(tzMask, ZONE_OFFSET)) {
2495                        zoneOffsets[0] = internalGet(ZONE_OFFSET);
2496                    }
2497                    if (isFieldSet(tzMask, DST_OFFSET)) {
2498                        zoneOffsets[1] = internalGet(DST_OFFSET);
2499                    }
2500                }
2501
2502                // Adjust the time zone offset values to get the UTC time.
2503                millis -= zoneOffsets[0] + zoneOffsets[1];
2504
2505                // Set this calendar's time in milliseconds
2506                time = millis;
2507
2508                int mask = computeFields(fieldMask | getSetStateFields(),
2509                        tzMask);
2510
2511                if (!isLenient()) {
2512                    for (int field = 0; field < FIELD_COUNT; field++) {
2513                        if (!isExternallySet(field)) {
2514                            continue;
2515                        }
2516                        if (originalFields[field] != internalGet(field)) {
2517                            // Restore the original field values
2518                            System.arraycopy(originalFields, 0, fields, 0,
2519                                    fields.length);
2520                            throw new IllegalArgumentException(
2521                                    getFieldName(field));
2522                        }
2523                    }
2524                }
2525                setFieldsNormalized(mask);
2526            }
2527
2528            /**
2529             * Computes the fixed date under either the Gregorian or the
2530             * Julian calendar, using the given year and the specified calendar fields.
2531             *
2532             * @param cal the CalendarSystem to be used for the date calculation
2533             * @param year the normalized year number, with 0 indicating the
2534             * year 1 BCE, -1 indicating 2 BCE, etc.
2535             * @param fieldMask the calendar fields to be used for the date calculation
2536             * @return the fixed date
2537             * @see Calendar#selectFields
2538             */
2539            private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
2540                int month = JANUARY;
2541                if (isFieldSet(fieldMask, MONTH)) {
2542                    // No need to check if MONTH has been set (no isSet(MONTH)
2543                    // call) since its unset value happens to be JANUARY (0).
2544                    month = internalGet(MONTH);
2545
2546                    // If the month is out of range, adjust it into range
2547                    if (month > DECEMBER) {
2548                        year += month / 12;
2549                        month %= 12;
2550                    } else if (month < JANUARY) {
2551                        int[] rem = new int[1];
2552                        year += CalendarUtils.floorDivide(month, 12, rem);
2553                        month = rem[0];
2554                    }
2555                }
2556
2557                // Get the fixed date since Jan 1, 1 (Gregorian). We are on
2558                // the first day of either `month' or January in 'year'.
2559                long fixedDate = cal.getFixedDate(year, month + 1, 1,
2560                        cal == gcal ? gdate : null);
2561                if (isFieldSet(fieldMask, MONTH)) {
2562                    // Month-based calculations
2563                    if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
2564                        // We are on the first day of the month. Just add the
2565                        // offset if DAY_OF_MONTH is set. If the isSet call
2566                        // returns false, that means DAY_OF_MONTH has been
2567                        // selected just because of the selected
2568                        // combination. We don't need to add any since the
2569                        // default value is the 1st.
2570                        if (isSet(DAY_OF_MONTH)) {
2571                            // To avoid underflow with DAY_OF_MONTH-1, add
2572                            // DAY_OF_MONTH, then subtract 1.
2573                            fixedDate += internalGet(DAY_OF_MONTH);
2574                            fixedDate--;
2575                        }
2576                    } else {
2577                        if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2578                            long firstDayOfWeek = cal
2579                                    .getDayOfWeekDateOnOrBefore(fixedDate + 6,
2580                                            getFirstDayOfWeek());
2581                            // If we have enough days in the first week, then
2582                            // move to the previous week.
2583                            if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2584                                firstDayOfWeek -= 7;
2585                            }
2586                            if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2587                                firstDayOfWeek = cal
2588                                        .getDayOfWeekDateOnOrBefore(
2589                                                firstDayOfWeek + 6,
2590                                                internalGet(DAY_OF_WEEK));
2591                            }
2592                            // In lenient mode, we treat days of the previous
2593                            // months as a part of the specified
2594                            // WEEK_OF_MONTH. See 4633646.
2595                            fixedDate = firstDayOfWeek + 7
2596                                    * (internalGet(WEEK_OF_MONTH) - 1);
2597                        } else {
2598                            int dayOfWeek;
2599                            if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2600                                dayOfWeek = internalGet(DAY_OF_WEEK);
2601                            } else {
2602                                dayOfWeek = getFirstDayOfWeek();
2603                            }
2604                            // We are basing this on the day-of-week-in-month.  The only
2605                            // trickiness occurs if the day-of-week-in-month is
2606                            // negative.
2607                            int dowim;
2608                            if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2609                                dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2610                            } else {
2611                                dowim = 1;
2612                            }
2613                            if (dowim >= 0) {
2614                                fixedDate = cal.getDayOfWeekDateOnOrBefore(
2615                                        fixedDate + (7 * dowim) - 1, dayOfWeek);
2616                            } else {
2617                                // Go to the first day of the next week of
2618                                // the specified week boundary.
2619                                int lastDate = monthLength(month, year)
2620                                        + (7 * (dowim + 1));
2621                                // Then, get the day of week date on or before the last date.
2622                                fixedDate = cal.getDayOfWeekDateOnOrBefore(
2623                                        fixedDate + lastDate - 1, dayOfWeek);
2624                            }
2625                        }
2626                    }
2627                } else {
2628                    if (year == gregorianCutoverYear
2629                            && cal == gcal
2630                            && fixedDate < gregorianCutoverDate
2631                            && gregorianCutoverYear != gregorianCutoverYearJulian) {
2632                        // January 1 of the year doesn't exist.  Use
2633                        // gregorianCutoverDate as the first day of the
2634                        // year.
2635                        fixedDate = gregorianCutoverDate;
2636                    }
2637                    // We are on the first day of the year.
2638                    if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
2639                        // Add the offset, then subtract 1. (Make sure to avoid underflow.)
2640                        fixedDate += internalGet(DAY_OF_YEAR);
2641                        fixedDate--;
2642                    } else {
2643                        long firstDayOfWeek = cal.getDayOfWeekDateOnOrBefore(
2644                                fixedDate + 6, getFirstDayOfWeek());
2645                        // If we have enough days in the first week, then move
2646                        // to the previous week.
2647                        if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2648                            firstDayOfWeek -= 7;
2649                        }
2650                        if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2651                            int dayOfWeek = internalGet(DAY_OF_WEEK);
2652                            if (dayOfWeek != getFirstDayOfWeek()) {
2653                                firstDayOfWeek = cal
2654                                        .getDayOfWeekDateOnOrBefore(
2655                                                firstDayOfWeek + 6, dayOfWeek);
2656                            }
2657                        }
2658                        fixedDate = firstDayOfWeek + 7
2659                                * ((long) internalGet(WEEK_OF_YEAR) - 1);
2660                    }
2661                }
2662
2663                return fixedDate;
2664            }
2665
2666            /**
2667             * Returns this object if it's normalized (all fields and time are
2668             * in sync). Otherwise, a cloned object is returned after calling
2669             * complete() in lenient mode.
2670             */
2671            private final GregorianCalendar getNormalizedCalendar() {
2672                GregorianCalendar gc;
2673                if (isFullyNormalized()) {
2674                    gc = this ;
2675                } else {
2676                    // Create a clone and normalize the calendar fields
2677                    gc = (GregorianCalendar) this .clone();
2678                    gc.setLenient(true);
2679                    gc.complete();
2680                }
2681                return gc;
2682            }
2683
2684            /**
2685             * Returns the Julian calendar system instance (singleton). 'jcal'
2686             * and 'jeras' are set upon the return.
2687             */
2688            synchronized private static final BaseCalendar getJulianCalendarSystem() {
2689                if (jcal == null) {
2690                    jcal = (JulianCalendar) CalendarSystem.forName("julian");
2691                    jeras = jcal.getEras();
2692                }
2693                return jcal;
2694            }
2695
2696            /**
2697             * Returns the calendar system for dates before the cutover date
2698             * in the cutover year. If the cutover date is January 1, the
2699             * method returns Gregorian. Otherwise, Julian.
2700             */
2701            private BaseCalendar getCutoverCalendarSystem() {
2702                CalendarDate date = getGregorianCutoverDate();
2703                if (date.getMonth() == BaseCalendar.JANUARY
2704                        && date.getDayOfMonth() == 1) {
2705                    return gcal;
2706                }
2707                return getJulianCalendarSystem();
2708            }
2709
2710            /**
2711             * Determines if the specified year (normalized) is the Gregorian
2712             * cutover year. This object must have been normalized.
2713             */
2714            private final boolean isCutoverYear(int normalizedYear) {
2715                int cutoverYear = (calsys == gcal) ? gregorianCutoverYear
2716                        : gregorianCutoverYearJulian;
2717                return normalizedYear == cutoverYear;
2718            }
2719
2720            /**
2721             * Returns the fixed date of the first day of the year (usually
2722             * January 1) before the specified date.
2723             *
2724             * @param date the date for which the first day of the year is
2725             * calculated. The date has to be in the cut-over year (Gregorian
2726             * or Julian).
2727             * @param fixedDate the fixed date representation of the date
2728             */
2729            private final long getFixedDateJan1(BaseCalendar.Date date,
2730                    long fixedDate) {
2731                assert date.getNormalizedYear() == gregorianCutoverYear
2732                        || date.getNormalizedYear() == gregorianCutoverYearJulian;
2733                if (gregorianCutoverYear != gregorianCutoverYearJulian) {
2734                    if (fixedDate >= gregorianCutoverDate) {
2735                        // Dates before the cutover date don't exist
2736                        // in the same (Gregorian) year. So, no
2737                        // January 1 exists in the year. Use the
2738                        // cutover date as the first day of the year.
2739                        return gregorianCutoverDate;
2740                    }
2741                }
2742                // January 1 of the normalized year should exist.
2743                BaseCalendar jcal = getJulianCalendarSystem();
2744                return jcal.getFixedDate(date.getNormalizedYear(),
2745                        BaseCalendar.JANUARY, 1, null);
2746            }
2747
2748            /**
2749             * Returns the fixed date of the first date of the month (usually
2750             * the 1st of the month) before the specified date.
2751             *
2752             * @param date the date for which the first day of the month is
2753             * calculated. The date has to be in the cut-over year (Gregorian
2754             * or Julian).
2755             * @param fixedDate the fixed date representation of the date
2756             */
2757            private final long getFixedDateMonth1(BaseCalendar.Date date,
2758                    long fixedDate) {
2759                assert date.getNormalizedYear() == gregorianCutoverYear
2760                        || date.getNormalizedYear() == gregorianCutoverYearJulian;
2761                BaseCalendar.Date gCutover = getGregorianCutoverDate();
2762                if (gCutover.getMonth() == BaseCalendar.JANUARY
2763                        && gCutover.getDayOfMonth() == 1) {
2764                    // The cutover happened on January 1.
2765                    return fixedDate - date.getDayOfMonth() + 1;
2766                }
2767
2768                long fixedDateMonth1;
2769                // The cutover happened sometime during the year.
2770                if (date.getMonth() == gCutover.getMonth()) {
2771                    // The cutover happened in the month.
2772                    BaseCalendar.Date jLastDate = getLastJulianDate();
2773                    if (gregorianCutoverYear == gregorianCutoverYearJulian
2774                            && gCutover.getMonth() == jLastDate.getMonth()) {
2775                        // The "gap" fits in the same month.
2776                        fixedDateMonth1 = jcal.getFixedDate(date
2777                                .getNormalizedYear(), date.getMonth(), 1, null);
2778                    } else {
2779                        // Use the cutover date as the first day of the month.
2780                        fixedDateMonth1 = gregorianCutoverDate;
2781                    }
2782                } else {
2783                    // The cutover happened before the month.
2784                    fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
2785                }
2786
2787                return fixedDateMonth1;
2788            }
2789
2790            /**
2791             * Returns a CalendarDate produced from the specified fixed date.
2792             *
2793             * @param fd the fixed date
2794             */
2795            private final BaseCalendar.Date getCalendarDate(long fd) {
2796                BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal
2797                        : getJulianCalendarSystem();
2798                BaseCalendar.Date d = (BaseCalendar.Date) cal
2799                        .newCalendarDate(TimeZone.NO_TIMEZONE);
2800                cal.getCalendarDateFromFixedDate(d, fd);
2801                return d;
2802            }
2803
2804            /**
2805             * Returns the Gregorian cutover date as a BaseCalendar.Date. The
2806             * date is a Gregorian date.
2807             */
2808            private final BaseCalendar.Date getGregorianCutoverDate() {
2809                return getCalendarDate(gregorianCutoverDate);
2810            }
2811
2812            /**
2813             * Returns the day before the Gregorian cutover date as a
2814             * BaseCalendar.Date. The date is a Julian date.
2815             */
2816            private final BaseCalendar.Date getLastJulianDate() {
2817                return getCalendarDate(gregorianCutoverDate - 1);
2818            }
2819
2820            /**
2821             * Returns the length of the specified month in the specified
2822             * year. The year number must be normalized.
2823             *
2824             * @see #isLeapYear(int)
2825             */
2826            private final int monthLength(int month, int year) {
2827                return isLeapYear(year) ? LEAP_MONTH_LENGTH[month]
2828                        : MONTH_LENGTH[month];
2829            }
2830
2831            /**
2832             * Returns the length of the specified month in the year provided
2833             * by internalGet(YEAR).
2834             *
2835             * @see #isLeapYear(int)
2836             */
2837            private final int monthLength(int month) {
2838                int year = internalGet(YEAR);
2839                if (internalGetEra() == BCE) {
2840                    year = 1 - year;
2841                }
2842                return monthLength(month, year);
2843            }
2844
2845            private final int actualMonthLength() {
2846                int year = cdate.getNormalizedYear();
2847                if (year != gregorianCutoverYear
2848                        && year != gregorianCutoverYearJulian) {
2849                    return calsys.getMonthLength(cdate);
2850                }
2851                BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
2852                long fd = calsys.getFixedDate(date);
2853                long month1 = getFixedDateMonth1(date, fd);
2854                long next1 = month1 + calsys.getMonthLength(date);
2855                if (next1 < gregorianCutoverDate) {
2856                    return (int) (next1 - month1);
2857                }
2858                if (cdate != gdate) {
2859                    date = (BaseCalendar.Date) gcal
2860                            .newCalendarDate(TimeZone.NO_TIMEZONE);
2861                }
2862                gcal.getCalendarDateFromFixedDate(date, next1);
2863                next1 = getFixedDateMonth1(date, next1);
2864                return (int) (next1 - month1);
2865            }
2866
2867            /**
2868             * Returns the length (in days) of the specified year. The year
2869             * must be normalized.
2870             */
2871            private final int yearLength(int year) {
2872                return isLeapYear(year) ? 366 : 365;
2873            }
2874
2875            /**
2876             * Returns the length (in days) of the year provided by
2877             * internalGet(YEAR).
2878             */
2879            private final int yearLength() {
2880                int year = internalGet(YEAR);
2881                if (internalGetEra() == BCE) {
2882                    year = 1 - year;
2883                }
2884                return yearLength(year);
2885            }
2886
2887            /**
2888             * After adjustments such as add(MONTH), add(YEAR), we don't want the
2889             * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
2890             * 3, we want it to go to Feb 28.  Adjustments which might run into this
2891             * problem call this method to retain the proper month.
2892             */
2893            private final void pinDayOfMonth() {
2894                int year = internalGet(YEAR);
2895                int monthLen;
2896                if (year > gregorianCutoverYear
2897                        || year < gregorianCutoverYearJulian) {
2898                    monthLen = monthLength(internalGet(MONTH));
2899                } else {
2900                    GregorianCalendar gc = getNormalizedCalendar();
2901                    monthLen = gc.getActualMaximum(DAY_OF_MONTH);
2902                }
2903                int dom = internalGet(DAY_OF_MONTH);
2904                if (dom > monthLen) {
2905                    set(DAY_OF_MONTH, monthLen);
2906                }
2907            }
2908
2909            /**
2910             * Returns the fixed date value of this object. The time value and
2911             * calendar fields must be in synch.
2912             */
2913            private final long getCurrentFixedDate() {
2914                return (calsys == gcal) ? cachedFixedDate : calsys
2915                        .getFixedDate(cdate);
2916            }
2917
2918            /**
2919             * Returns the new value after 'roll'ing the specified value and amount.
2920             */
2921            private static final int getRolledValue(int value, int amount,
2922                    int min, int max) {
2923                assert value >= min && value <= max;
2924                int range = max - min + 1;
2925                amount %= range;
2926                int n = value + amount;
2927                if (n > max) {
2928                    n -= range;
2929                } else if (n < min) {
2930                    n += range;
2931                }
2932                assert n >= min && n <= max;
2933                return n;
2934            }
2935
2936            /**
2937             * Returns the ERA.  We need a special method for this because the
2938             * default ERA is CE, but a zero (unset) ERA is BCE.
2939             */
2940            private final int internalGetEra() {
2941                return isSet(ERA) ? internalGet(ERA) : CE;
2942            }
2943
2944            /**
2945             * Updates internal state.
2946             */
2947            private void readObject(ObjectInputStream stream)
2948                    throws IOException, ClassNotFoundException {
2949                stream.defaultReadObject();
2950                if (gdate == null) {
2951                    gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
2952                    cachedFixedDate = Long.MIN_VALUE;
2953                }
2954                setGregorianChange(gregorianCutover);
2955            }
2956        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.