Source Code Cross Referenced for JapaneseImperialCalendar.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 2005-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        package java.util;
0027
0028        import java.io.IOException;
0029        import java.io.ObjectInputStream;
0030        import sun.util.calendar.BaseCalendar;
0031        import sun.util.calendar.CalendarDate;
0032        import sun.util.calendar.CalendarSystem;
0033        import sun.util.calendar.CalendarUtils;
0034        import sun.util.calendar.Era;
0035        import sun.util.calendar.Gregorian;
0036        import sun.util.calendar.LocalGregorianCalendar;
0037        import sun.util.calendar.ZoneInfo;
0038        import sun.util.resources.LocaleData;
0039
0040        /**
0041         * <code>JapaneseImperialCalendar</code> implements a Japanese
0042         * calendar system in which the imperial era-based year numbering is
0043         * supported from the Meiji era. The following are the eras supported
0044         * by this calendar system.
0045         * <pre><tt>
0046         * ERA value   Era name    Since (in Gregorian)	    
0047         * ------------------------------------------------------
0048         *     0       N/A         N/A
0049         *     1       Meiji       1868-01-01 midnight local time
0050         *     2       Taisho      1912-07-30 midnight local time
0051         *     3       Showa       1926-12-25 midnight local time
0052         *     4       Heisei      1989-01-08 midnight local time
0053         * ------------------------------------------------------
0054         * </tt></pre>
0055         *
0056         * <p><code>ERA</code> value 0 specifies the years before Meiji and
0057         * the Gregorian year values are used. Unlike {@link
0058         * GregorianCalendar}, the Julian to Gregorian transition is not
0059         * supported because it doesn't make any sense to the Japanese
0060         * calendar systems used before Meiji. To represent the years before
0061         * Gregorian year 1, 0 and negative values are used. The Japanese
0062         * Imperial rescripts and government decrees don't specify how to deal
0063         * with time differences for applying the era transitions. This
0064         * calendar implementation assumes local time for all transitions.
0065         *
0066         * @author Masayoshi Okutsu
0067         * @since 1.6
0068         */
0069        class JapaneseImperialCalendar extends Calendar {
0070            /*
0071             * Implementation Notes
0072             *
0073             * This implementation uses
0074             * sun.util.calendar.LocalGregorianCalendar to perform most of the
0075             * calendar calculations. LocalGregorianCalendar is configurable
0076             * and reads <JRE_HOME>/lib/calendars.properties at the start-up.
0077             */
0078
0079            /**
0080             * The ERA constant designating the era before Meiji.
0081             */
0082            public static final int BEFORE_MEIJI = 0;
0083
0084            /**
0085             * The ERA constant designating the Meiji era.
0086             */
0087            public static final int MEIJI = 1;
0088
0089            /**
0090             * The ERA constant designating the Taisho era.
0091             */
0092            public static final int TAISHO = 2;
0093
0094            /**
0095             * The ERA constant designating the Showa era.
0096             */
0097            public static final int SHOWA = 3;
0098
0099            /**
0100             * The ERA constant designating the Heisei era.
0101             */
0102            public static final int HEISEI = 4;
0103
0104            private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
0105            private static final int EPOCH_YEAR = 1970;
0106
0107            // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
0108            // into ints, they must be longs in order to prevent arithmetic overflow
0109            // when performing (bug 4173516).
0110            private static final int ONE_SECOND = 1000;
0111            private static final int ONE_MINUTE = 60 * ONE_SECOND;
0112            private static final int ONE_HOUR = 60 * ONE_MINUTE;
0113            private static final long ONE_DAY = 24 * ONE_HOUR;
0114            private static final long ONE_WEEK = 7 * ONE_DAY;
0115
0116            // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
0117            private static final LocalGregorianCalendar jcal = (LocalGregorianCalendar) CalendarSystem
0118                    .forName("japanese");
0119
0120            // Gregorian calendar instance. This is required because era
0121            // transition dates are given in Gregorian dates.
0122            private static final Gregorian gcal = CalendarSystem
0123                    .getGregorianCalendar();
0124
0125            // The Era instance representing "before Meiji".
0126            private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji",
0127                    "BM", Long.MIN_VALUE, false);
0128
0129            // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
0130            // doesn't have an Era representing before Meiji, which is
0131            // inconvenient for a Calendar. So, era[0] is a reference to
0132            // BEFORE_MEIJI_ERA.
0133            private static final Era[] eras;
0134
0135            // Fixed date of the first date of each era.
0136            private static final long[] sinceFixedDates;
0137
0138            /*
0139             * <pre>
0140             *                                 Greatest       Least 
0141             * Field name             Minimum   Minimum     Maximum     Maximum
0142             * ----------             -------   -------     -------     -------
0143             * ERA                          0         0           1           1
0144             * YEAR                -292275055         1           ?           ?
0145             * MONTH                        0         0          11          11
0146             * WEEK_OF_YEAR                 1         1          52*         53
0147             * WEEK_OF_MONTH                0         0           4*          6
0148             * DAY_OF_MONTH                 1         1          28*         31
0149             * DAY_OF_YEAR                  1         1         365*        366
0150             * DAY_OF_WEEK                  1         1           7           7
0151             * DAY_OF_WEEK_IN_MONTH        -1        -1           4*          6
0152             * AM_PM                        0         0           1           1
0153             * HOUR                         0         0          11          11
0154             * HOUR_OF_DAY                  0         0          23          23
0155             * MINUTE                       0         0          59          59
0156             * SECOND                       0         0          59          59
0157             * MILLISECOND                  0         0         999         999
0158             * ZONE_OFFSET             -13:00    -13:00       14:00       14:00
0159             * DST_OFFSET                0:00      0:00        0:20        2:00
0160             * </pre>
0161             * *: depends on eras
0162             */
0163            static final int MIN_VALUES[] = { 0, // ERA
0164                    -292275055, // YEAR
0165                    JANUARY, // MONTH
0166                    1, // WEEK_OF_YEAR
0167                    0, // WEEK_OF_MONTH
0168                    1, // DAY_OF_MONTH
0169                    1, // DAY_OF_YEAR
0170                    SUNDAY, // DAY_OF_WEEK
0171                    1, // DAY_OF_WEEK_IN_MONTH
0172                    AM, // AM_PM
0173                    0, // HOUR
0174                    0, // HOUR_OF_DAY
0175                    0, // MINUTE
0176                    0, // SECOND
0177                    0, // MILLISECOND
0178                    -13 * ONE_HOUR, // ZONE_OFFSET (UNIX compatibility)
0179                    0 // DST_OFFSET
0180            };
0181            static final int LEAST_MAX_VALUES[] = { 0, // ERA (initialized later)
0182                    0, // YEAR (initialized later)
0183                    JANUARY, // MONTH (Showa 64 ended in January.)
0184                    0, // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.)
0185                    4, // WEEK_OF_MONTH
0186                    28, // DAY_OF_MONTH
0187                    0, // DAY_OF_YEAR (initialized later)
0188                    SATURDAY, // DAY_OF_WEEK
0189                    4, // DAY_OF_WEEK_IN
0190                    PM, // AM_PM
0191                    11, // HOUR
0192                    23, // HOUR_OF_DAY
0193                    59, // MINUTE
0194                    59, // SECOND
0195                    999, // MILLISECOND
0196                    14 * ONE_HOUR, // ZONE_OFFSET
0197                    20 * ONE_MINUTE // DST_OFFSET (historical least maximum)
0198            };
0199            static final int MAX_VALUES[] = { 0, // ERA
0200                    292278994, // YEAR
0201                    DECEMBER, // MONTH
0202                    53, // WEEK_OF_YEAR
0203                    6, // WEEK_OF_MONTH
0204                    31, // DAY_OF_MONTH
0205                    366, // DAY_OF_YEAR
0206                    SATURDAY, // DAY_OF_WEEK
0207                    6, // DAY_OF_WEEK_IN
0208                    PM, // AM_PM
0209                    11, // HOUR
0210                    23, // HOUR_OF_DAY
0211                    59, // MINUTE
0212                    59, // SECOND
0213                    999, // MILLISECOND
0214                    14 * ONE_HOUR, // ZONE_OFFSET
0215                    2 * ONE_HOUR // DST_OFFSET (double summer time)
0216            };
0217
0218            // Proclaim serialization compatibility with JDK 1.6
0219            private static final long serialVersionUID = -3364572813905467929L;
0220
0221            static {
0222                Era[] es = jcal.getEras();
0223                int length = es.length + 1;
0224                eras = new Era[length];
0225                sinceFixedDates = new long[length];
0226
0227                // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
0228                // same as Gregorian.
0229                int index = BEFORE_MEIJI;
0230                sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA
0231                        .getSinceDate());
0232                eras[index++] = BEFORE_MEIJI_ERA;
0233                for (Era e : es) {
0234                    CalendarDate d = e.getSinceDate();
0235                    sinceFixedDates[index] = gcal.getFixedDate(d);
0236                    eras[index++] = e;
0237                }
0238
0239                LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;
0240
0241                // Calculate the least maximum year and least day of Year
0242                // values. The following code assumes that there's at most one
0243                // era transition in a Gregorian year.
0244                int year = Integer.MAX_VALUE;
0245                int dayOfYear = Integer.MAX_VALUE;
0246                CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
0247                for (int i = 1; i < eras.length; i++) {
0248                    long fd = sinceFixedDates[i];
0249                    CalendarDate transitionDate = eras[i].getSinceDate();
0250                    date.setDate(transitionDate.getYear(),
0251                            BaseCalendar.JANUARY, 1);
0252                    long fdd = gcal.getFixedDate(date);
0253                    dayOfYear = Math.min((int) (fdd - fd), dayOfYear);
0254                    date.setDate(transitionDate.getYear(),
0255                            BaseCalendar.DECEMBER, 31);
0256                    fdd = gcal.getFixedDate(date) + 1;
0257                    dayOfYear = Math.min((int) (fd - fdd), dayOfYear);
0258
0259                    LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
0260                    int y = lgd.getYear();
0261                    // Unless the first year starts from January 1, the actual
0262                    // max value could be one year short. For example, if it's
0263                    // Showa 63 January 8, 63 is the actual max value since
0264                    // Showa 64 January 8 doesn't exist.
0265                    if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd
0266                            .getDayOfMonth() == 1))
0267                        y--;
0268                    year = Math.min(y, year);
0269                }
0270                LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value.
0271                LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear;
0272            }
0273
0274            /**
0275             * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to
0276             * avoid overhead of creating it for each calculation.
0277             */
0278            private transient LocalGregorianCalendar.Date jdate;
0279
0280            /**
0281             * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
0282             * the GMT offset value and zoneOffsets[1] gets the daylight saving
0283             * value.
0284             */
0285            private transient int[] zoneOffsets;
0286
0287            /**
0288             * Temporary storage for saving original fields[] values in
0289             * non-lenient mode.
0290             */
0291            private transient int[] originalFields;
0292
0293            /**
0294             * Constructs a <code>JapaneseImperialCalendar</code> based on the current time
0295             * in the given time zone with the given locale.
0296             *
0297             * @param zone the given time zone.
0298             * @param aLocale the given locale.
0299             */
0300            public JapaneseImperialCalendar(TimeZone zone, Locale aLocale) {
0301                super (zone, aLocale);
0302                jdate = jcal.newCalendarDate(zone);
0303                setTimeInMillis(System.currentTimeMillis());
0304            }
0305
0306            /**
0307             * Compares this <code>JapaneseImperialCalendar</code> to the specified
0308             * <code>Object</code>. The result is <code>true</code> if and
0309             * only if the argument is a <code>JapaneseImperialCalendar</code> object
0310             * that represents the same time value (millisecond offset from
0311             * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
0312             * <code>Calendar</code> parameters.
0313             *
0314             * @param obj the object to compare with.
0315             * @return <code>true</code> if this object is equal to <code>obj</code>;
0316             * <code>false</code> otherwise.
0317             * @see Calendar#compareTo(Calendar)
0318             */
0319            public boolean equals(Object obj) {
0320                return obj instanceof  JapaneseImperialCalendar
0321                        && super .equals(obj);
0322            }
0323
0324            /**
0325             * Generates the hash code for this
0326             * <code>JapaneseImperialCalendar</code> object.
0327             */
0328            public int hashCode() {
0329                return super .hashCode() ^ jdate.hashCode();
0330            }
0331
0332            /**
0333             * Adds the specified (signed) amount of time to the given calendar field,
0334             * based on the calendar's rules.
0335             *
0336             * <p><em>Add rule 1</em>. The value of <code>field</code>
0337             * after the call minus the value of <code>field</code> before the
0338             * call is <code>amount</code>, modulo any overflow that has occurred in
0339             * <code>field</code>. Overflow occurs when a field value exceeds its
0340             * range and, as a result, the next larger field is incremented or
0341             * decremented and the field value is adjusted back into its range.</p>
0342             *
0343             * <p><em>Add rule 2</em>. If a smaller field is expected to be
0344             * invariant, but it is impossible for it to be equal to its
0345             * prior value because of changes in its minimum or maximum after
0346             * <code>field</code> is changed, then its value is adjusted to be as close
0347             * as possible to its expected value. A smaller field represents a
0348             * smaller unit of time. <code>HOUR</code> is a smaller field than
0349             * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
0350             * that are not expected to be invariant. The calendar system
0351             * determines what fields are expected to be invariant.</p>
0352             *
0353             * @param field the calendar field.
0354             * @param amount the amount of date or time to be added to the field.
0355             * @exception IllegalArgumentException if <code>field</code> is
0356             * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
0357             * or if any calendar fields have out-of-range values in
0358             * non-lenient mode.
0359             */
0360            public void add(int field, int amount) {
0361                // If amount == 0, do nothing even the given field is out of
0362                // range. This is tested by JCK.
0363                if (amount == 0) {
0364                    return; // Do nothing!
0365                }
0366
0367                if (field < 0 || field >= ZONE_OFFSET) {
0368                    throw new IllegalArgumentException();
0369                }
0370
0371                // Sync the time and calendar fields.
0372                complete();
0373
0374                if (field == YEAR) {
0375                    LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate
0376                            .clone();
0377                    d.addYear(amount);
0378                    pinDayOfMonth(d);
0379                    set(ERA, getEraIndex(d));
0380                    set(YEAR, d.getYear());
0381                    set(MONTH, d.getMonth() - 1);
0382                    set(DAY_OF_MONTH, d.getDayOfMonth());
0383                } else if (field == MONTH) {
0384                    LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate
0385                            .clone();
0386                    d.addMonth(amount);
0387                    pinDayOfMonth(d);
0388                    set(ERA, getEraIndex(d));
0389                    set(YEAR, d.getYear());
0390                    set(MONTH, d.getMonth() - 1);
0391                    set(DAY_OF_MONTH, d.getDayOfMonth());
0392                } else if (field == ERA) {
0393                    int era = internalGet(ERA) + amount;
0394                    if (era < 0) {
0395                        era = 0;
0396                    } else if (era > eras.length - 1) {
0397                        era = eras.length - 1;
0398                    }
0399                    set(ERA, era);
0400                } else {
0401                    long delta = amount;
0402                    long timeOfDay = 0;
0403                    switch (field) {
0404                    // Handle the time fields here. Convert the given
0405                    // amount to milliseconds and call setTimeInMillis.
0406                    case HOUR:
0407                    case HOUR_OF_DAY:
0408                        delta *= 60 * 60 * 1000; // hours to milliseconds
0409                        break;
0410
0411                    case MINUTE:
0412                        delta *= 60 * 1000; // minutes to milliseconds
0413                        break;
0414
0415                    case SECOND:
0416                        delta *= 1000; // seconds to milliseconds
0417                        break;
0418
0419                    case MILLISECOND:
0420                        break;
0421
0422                    // Handle week, day and AM_PM fields which involves
0423                    // time zone offset change adjustment. Convert the
0424                    // given amount to the number of days.
0425                    case WEEK_OF_YEAR:
0426                    case WEEK_OF_MONTH:
0427                    case DAY_OF_WEEK_IN_MONTH:
0428                        delta *= 7;
0429                        break;
0430
0431                    case DAY_OF_MONTH: // synonym of DATE
0432                    case DAY_OF_YEAR:
0433                    case DAY_OF_WEEK:
0434                        break;
0435
0436                    case AM_PM:
0437                        // Convert the amount to the number of days (delta)
0438                        // and +12 or -12 hours (timeOfDay).
0439                        delta = amount / 2;
0440                        timeOfDay = 12 * (amount % 2);
0441                        break;
0442                    }
0443
0444                    // The time fields don't require time zone offset change
0445                    // adjustment.
0446                    if (field >= HOUR) {
0447                        setTimeInMillis(time + delta);
0448                        return;
0449                    }
0450
0451                    // The rest of the fields (week, day or AM_PM fields)
0452                    // require time zone offset (both GMT and DST) change
0453                    // adjustment.
0454
0455                    // Translate the current time to the fixed date and time
0456                    // of the day.
0457                    long fd = cachedFixedDate;
0458                    timeOfDay += internalGet(HOUR_OF_DAY);
0459                    timeOfDay *= 60;
0460                    timeOfDay += internalGet(MINUTE);
0461                    timeOfDay *= 60;
0462                    timeOfDay += internalGet(SECOND);
0463                    timeOfDay *= 1000;
0464                    timeOfDay += internalGet(MILLISECOND);
0465                    if (timeOfDay >= ONE_DAY) {
0466                        fd++;
0467                        timeOfDay -= ONE_DAY;
0468                    } else if (timeOfDay < 0) {
0469                        fd--;
0470                        timeOfDay += ONE_DAY;
0471                    }
0472
0473                    fd += delta; // fd is the expected fixed date after the calculation
0474                    int zoneOffset = internalGet(ZONE_OFFSET)
0475                            + internalGet(DST_OFFSET);
0476                    setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay
0477                            - zoneOffset);
0478                    zoneOffset -= internalGet(ZONE_OFFSET)
0479                            + internalGet(DST_OFFSET);
0480                    // If the time zone offset has changed, then adjust the difference.
0481                    if (zoneOffset != 0) {
0482                        setTimeInMillis(time + zoneOffset);
0483                        long fd2 = cachedFixedDate;
0484                        // If the adjustment has changed the date, then take
0485                        // the previous one.
0486                        if (fd2 != fd) {
0487                            setTimeInMillis(time - zoneOffset);
0488                        }
0489                    }
0490                }
0491            }
0492
0493            public void roll(int field, boolean up) {
0494                roll(field, up ? +1 : -1);
0495            }
0496
0497            /**
0498             * Adds a signed amount to the specified calendar field without changing larger fields.
0499             * A negative roll amount means to subtract from field without changing 
0500             * larger fields. If the specified amount is 0, this method performs nothing.
0501             *
0502             * <p>This method calls {@link #complete()} before adding the
0503             * amount so that all the calendar fields are normalized. If there
0504             * is any calendar field having an out-of-range value in non-lenient mode, then an
0505             * <code>IllegalArgumentException</code> is thrown.
0506             *
0507             * @param field the calendar field.
0508             * @param amount the signed amount to add to <code>field</code>.
0509             * @exception IllegalArgumentException if <code>field</code> is
0510             * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
0511             * or if any calendar fields have out-of-range values in
0512             * non-lenient mode.
0513             * @see #roll(int,boolean)
0514             * @see #add(int,int)
0515             * @see #set(int,int)
0516             */
0517            public void roll(int field, int amount) {
0518                // If amount == 0, do nothing even the given field is out of
0519                // range. This is tested by JCK.
0520                if (amount == 0) {
0521                    return;
0522                }
0523
0524                if (field < 0 || field >= ZONE_OFFSET) {
0525                    throw new IllegalArgumentException();
0526                }
0527
0528                // Sync the time and calendar fields.
0529                complete();
0530
0531                int min = getMinimum(field);
0532                int max = getMaximum(field);
0533
0534                switch (field) {
0535                case ERA:
0536                case AM_PM:
0537                case MINUTE:
0538                case SECOND:
0539                case MILLISECOND:
0540                    // These fields are handled simply, since they have fixed
0541                    // minima and maxima. Other fields are complicated, since
0542                    // the range within they must roll varies depending on the
0543                    // date, a time zone and the era transitions.
0544                    break;
0545
0546                case HOUR:
0547                case HOUR_OF_DAY: {
0548                    int unit = max + 1; // 12 or 24 hours
0549                    int h = internalGet(field);
0550                    int nh = (h + amount) % unit;
0551                    if (nh < 0) {
0552                        nh += unit;
0553                    }
0554                    time += ONE_HOUR * (nh - h);
0555
0556                    // The day might have changed, which could happen if
0557                    // the daylight saving time transition brings it to
0558                    // the next day, although it's very unlikely. But we
0559                    // have to make sure not to change the larger fields.
0560                    CalendarDate d = jcal.getCalendarDate(time, getZone());
0561                    if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
0562                        d.setEra(jdate.getEra());
0563                        d.setDate(internalGet(YEAR), internalGet(MONTH) + 1,
0564                                internalGet(DAY_OF_MONTH));
0565                        if (field == HOUR) {
0566                            assert (internalGet(AM_PM) == PM);
0567                            d.addHours(+12); // restore PM
0568                        }
0569                        time = jcal.getTime(d);
0570                    }
0571                    int hourOfDay = d.getHours();
0572                    internalSet(field, hourOfDay % unit);
0573                    if (field == HOUR) {
0574                        internalSet(HOUR_OF_DAY, hourOfDay);
0575                    } else {
0576                        internalSet(AM_PM, hourOfDay / 12);
0577                        internalSet(HOUR, hourOfDay % 12);
0578                    }
0579
0580                    // Time zone offset and/or daylight saving might have changed.
0581                    int zoneOffset = d.getZoneOffset();
0582                    int saving = d.getDaylightSaving();
0583                    internalSet(ZONE_OFFSET, zoneOffset - saving);
0584                    internalSet(DST_OFFSET, saving);
0585                    return;
0586                }
0587
0588                case YEAR:
0589                    min = getActualMinimum(field);
0590                    max = getActualMaximum(field);
0591                    break;
0592
0593                case MONTH:
0594                    // Rolling the month involves both pinning the final value to [0, 11]
0595                    // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
0596                    // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
0597                    // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
0598                {
0599                    if (!isTransitionYear(jdate.getNormalizedYear())) {
0600                        int year = jdate.getYear();
0601                        if (year == getMaximum(YEAR)) {
0602                            CalendarDate jd = jcal.getCalendarDate(time,
0603                                    getZone());
0604                            CalendarDate d = jcal.getCalendarDate(
0605                                    Long.MAX_VALUE, getZone());
0606                            max = d.getMonth() - 1;
0607                            int n = getRolledValue(internalGet(field), amount,
0608                                    min, max);
0609                            if (n == max) {
0610                                // To avoid overflow, use an equivalent year.
0611                                jd.addYear(-400);
0612                                jd.setMonth(n + 1);
0613                                if (jd.getDayOfMonth() > d.getDayOfMonth()) {
0614                                    jd.setDayOfMonth(d.getDayOfMonth());
0615                                    jcal.normalize(jd);
0616                                }
0617                                if (jd.getDayOfMonth() == d.getDayOfMonth()
0618                                        && jd.getTimeOfDay() > d.getTimeOfDay()) {
0619                                    jd.setMonth(n + 1);
0620                                    jd.setDayOfMonth(d.getDayOfMonth() - 1);
0621                                    jcal.normalize(jd);
0622                                    // Month may have changed by the normalization.
0623                                    n = jd.getMonth() - 1;
0624                                }
0625                                set(DAY_OF_MONTH, jd.getDayOfMonth());
0626                            }
0627                            set(MONTH, n);
0628                        } else if (year == getMinimum(YEAR)) {
0629                            CalendarDate jd = jcal.getCalendarDate(time,
0630                                    getZone());
0631                            CalendarDate d = jcal.getCalendarDate(
0632                                    Long.MIN_VALUE, getZone());
0633                            min = d.getMonth() - 1;
0634                            int n = getRolledValue(internalGet(field), amount,
0635                                    min, max);
0636                            if (n == min) {
0637                                // To avoid underflow, use an equivalent year.
0638                                jd.addYear(+400);
0639                                jd.setMonth(n + 1);
0640                                if (jd.getDayOfMonth() < d.getDayOfMonth()) {
0641                                    jd.setDayOfMonth(d.getDayOfMonth());
0642                                    jcal.normalize(jd);
0643                                }
0644                                if (jd.getDayOfMonth() == d.getDayOfMonth()
0645                                        && jd.getTimeOfDay() < d.getTimeOfDay()) {
0646                                    jd.setMonth(n + 1);
0647                                    jd.setDayOfMonth(d.getDayOfMonth() + 1);
0648                                    jcal.normalize(jd);
0649                                    // Month may have changed by the normalization.
0650                                    n = jd.getMonth() - 1;
0651                                }
0652                                set(DAY_OF_MONTH, jd.getDayOfMonth());
0653                            }
0654                            set(MONTH, n);
0655                        } else {
0656                            int mon = (internalGet(MONTH) + amount) % 12;
0657                            if (mon < 0) {
0658                                mon += 12;
0659                            }
0660                            set(MONTH, mon);
0661
0662                            // Keep the day of month in the range.  We
0663                            // don't want to spill over into the next
0664                            // month; e.g., we don't want jan31 + 1 mo ->
0665                            // feb31 -> mar3.
0666                            int monthLen = monthLength(mon);
0667                            if (internalGet(DAY_OF_MONTH) > monthLen) {
0668                                set(DAY_OF_MONTH, monthLen);
0669                            }
0670                        }
0671                    } else {
0672                        int eraIndex = getEraIndex(jdate);
0673                        CalendarDate transition = null;
0674                        if (jdate.getYear() == 1) {
0675                            transition = eras[eraIndex].getSinceDate();
0676                            min = transition.getMonth() - 1;
0677                        } else {
0678                            if (eraIndex < eras.length - 1) {
0679                                transition = eras[eraIndex + 1].getSinceDate();
0680                                if (transition.getYear() == jdate
0681                                        .getNormalizedYear()) {
0682                                    max = transition.getMonth() - 1;
0683                                    if (transition.getDayOfMonth() == 1) {
0684                                        max--;
0685                                    }
0686                                }
0687                            }
0688                        }
0689
0690                        if (min == max) {
0691                            // The year has only one month. No need to
0692                            // process further. (Showa Gan-nen (year 1)
0693                            // and the last year have only one month.)
0694                            return;
0695                        }
0696                        int n = getRolledValue(internalGet(field), amount, min,
0697                                max);
0698                        set(MONTH, n);
0699                        if (n == min) {
0700                            if (!(transition.getMonth() == BaseCalendar.JANUARY && transition
0701                                    .getDayOfMonth() == 1)) {
0702                                if (jdate.getDayOfMonth() < transition
0703                                        .getDayOfMonth()) {
0704                                    set(DAY_OF_MONTH, transition
0705                                            .getDayOfMonth());
0706                                }
0707                            }
0708                        } else if (n == max && (transition.getMonth() - 1 == n)) {
0709                            int dom = transition.getDayOfMonth();
0710                            if (jdate.getDayOfMonth() >= dom) {
0711                                set(DAY_OF_MONTH, dom - 1);
0712                            }
0713                        }
0714                    }
0715                    return;
0716                }
0717
0718                case WEEK_OF_YEAR: {
0719                    int y = jdate.getNormalizedYear();
0720                    max = getActualMaximum(WEEK_OF_YEAR);
0721                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK)); // update stamp[field]
0722                    int woy = internalGet(WEEK_OF_YEAR);
0723                    int value = woy + amount;
0724                    if (!isTransitionYear(jdate.getNormalizedYear())) {
0725                        int year = jdate.getYear();
0726                        if (year == getMaximum(YEAR)) {
0727                            max = getActualMaximum(WEEK_OF_YEAR);
0728                        } else if (year == getMinimum(YEAR)) {
0729                            min = getActualMinimum(WEEK_OF_YEAR);
0730                            max = getActualMaximum(WEEK_OF_YEAR);
0731                            if (value > min && value < max) {
0732                                set(WEEK_OF_YEAR, value);
0733                                return;
0734                            }
0735
0736                        }
0737                        // If the new value is in between min and max
0738                        // (exclusive), then we can use the value.
0739                        if (value > min && value < max) {
0740                            set(WEEK_OF_YEAR, value);
0741                            return;
0742                        }
0743                        long fd = cachedFixedDate;
0744                        // Make sure that the min week has the current DAY_OF_WEEK
0745                        long day1 = fd - (7 * (woy - min));
0746                        if (year != getMinimum(YEAR)) {
0747                            if (gcal.getYearFromFixedDate(day1) != y) {
0748                                min++;
0749                            }
0750                        } else {
0751                            CalendarDate d = jcal.getCalendarDate(
0752                                    Long.MIN_VALUE, getZone());
0753                            if (day1 < jcal.getFixedDate(d)) {
0754                                min++;
0755                            }
0756                        }
0757
0758                        // Make sure the same thing for the max week
0759                        fd += 7 * (max - internalGet(WEEK_OF_YEAR));
0760                        if (gcal.getYearFromFixedDate(fd) != y) {
0761                            max--;
0762                        }
0763                        break;
0764                    }
0765
0766                    // Handle transition here.
0767                    long fd = cachedFixedDate;
0768                    long day1 = fd - (7 * (woy - min));
0769                    // Make sure that the min week has the current DAY_OF_WEEK
0770                    LocalGregorianCalendar.Date d = getCalendarDate(day1);
0771                    if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate
0772                            .getYear())) {
0773                        min++;
0774                    }
0775
0776                    // Make sure the same thing for the max week
0777                    fd += 7 * (max - woy);
0778                    jcal.getCalendarDateFromFixedDate(d, fd);
0779                    if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate
0780                            .getYear())) {
0781                        max--;
0782                    }
0783                    // value: the new WEEK_OF_YEAR which must be converted
0784                    // to month and day of month.
0785                    value = getRolledValue(woy, amount, min, max) - 1;
0786                    d = getCalendarDate(day1 + value * 7);
0787                    set(MONTH, d.getMonth() - 1);
0788                    set(DAY_OF_MONTH, d.getDayOfMonth());
0789                    return;
0790                }
0791
0792                case WEEK_OF_MONTH: {
0793                    boolean isTransitionYear = isTransitionYear(jdate
0794                            .getNormalizedYear());
0795                    // dow: relative day of week from the first day of week
0796                    int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
0797                    if (dow < 0) {
0798                        dow += 7;
0799                    }
0800
0801                    long fd = cachedFixedDate;
0802                    long month1; // fixed date of the first day (usually 1) of the month
0803                    int monthLength; // actual month length
0804                    if (isTransitionYear) {
0805                        month1 = getFixedDateMonth1(jdate, fd);
0806                        monthLength = actualMonthLength();
0807                    } else {
0808                        month1 = fd - internalGet(DAY_OF_MONTH) + 1;
0809                        monthLength = jcal.getMonthLength(jdate);
0810                    }
0811
0812                    // the first day of week of the month.
0813                    long monthDay1st = jcal.getDayOfWeekDateOnOrBefore(
0814                            month1 + 6, getFirstDayOfWeek());
0815                    // if the week has enough days to form a week, the
0816                    // week starts from the previous month.
0817                    if ((int) (monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
0818                        monthDay1st -= 7;
0819                    }
0820                    max = getActualMaximum(field);
0821
0822                    // value: the new WEEK_OF_MONTH value
0823                    int value = getRolledValue(internalGet(field), amount, 1,
0824                            max) - 1;
0825
0826                    // nfd: fixed date of the rolled date
0827                    long nfd = monthDay1st + value * 7 + dow;
0828
0829                    // Unlike WEEK_OF_YEAR, we need to change day of week if the
0830                    // nfd is out of the month.
0831                    if (nfd < month1) {
0832                        nfd = month1;
0833                    } else if (nfd >= (month1 + monthLength)) {
0834                        nfd = month1 + monthLength - 1;
0835                    }
0836                    set(DAY_OF_MONTH, (int) (nfd - month1) + 1);
0837                    return;
0838                }
0839
0840                case DAY_OF_MONTH: {
0841                    if (!isTransitionYear(jdate.getNormalizedYear())) {
0842                        max = jcal.getMonthLength(jdate);
0843                        break;
0844                    }
0845
0846                    // TODO: Need to change the spec to be usable DAY_OF_MONTH rolling...
0847
0848                    // Transition handling. We can't change year and era
0849                    // values here due to the Calendar roll spec!
0850                    long month1 = getFixedDateMonth1(jdate, cachedFixedDate);
0851
0852                    // It may not be a regular month. Convert the date and range to
0853                    // the relative values, perform the roll, and
0854                    // convert the result back to the rolled date.
0855                    int value = getRolledValue(
0856                            (int) (cachedFixedDate - month1), amount, 0,
0857                            actualMonthLength() - 1);
0858                    LocalGregorianCalendar.Date d = getCalendarDate(month1
0859                            + value);
0860                    assert getEraIndex(d) == internalGetEra()
0861                            && d.getYear() == internalGet(YEAR)
0862                            && d.getMonth() - 1 == internalGet(MONTH);
0863                    set(DAY_OF_MONTH, d.getDayOfMonth());
0864                    return;
0865                }
0866
0867                case DAY_OF_YEAR: {
0868                    max = getActualMaximum(field);
0869                    if (!isTransitionYear(jdate.getNormalizedYear())) {
0870                        break;
0871                    }
0872
0873                    // Handle transition. We can't change year and era values
0874                    // here due to the Calendar roll spec.
0875                    int value = getRolledValue(internalGet(DAY_OF_YEAR),
0876                            amount, min, max);
0877                    long jan0 = cachedFixedDate - internalGet(DAY_OF_YEAR);
0878                    LocalGregorianCalendar.Date d = getCalendarDate(jan0
0879                            + value);
0880                    assert getEraIndex(d) == internalGetEra()
0881                            && d.getYear() == internalGet(YEAR);
0882                    set(MONTH, d.getMonth() - 1);
0883                    set(DAY_OF_MONTH, d.getDayOfMonth());
0884                    return;
0885                }
0886
0887                case DAY_OF_WEEK: {
0888                    int normalizedYear = jdate.getNormalizedYear();
0889                    if (!isTransitionYear(normalizedYear)
0890                            && !isTransitionYear(normalizedYear - 1)) {
0891                        // If the week of year is in the same year, we can
0892                        // just change DAY_OF_WEEK.
0893                        int weekOfYear = internalGet(WEEK_OF_YEAR);
0894                        if (weekOfYear > 1 && weekOfYear < 52) {
0895                            set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
0896                            max = SATURDAY;
0897                            break;
0898                        }
0899                    }
0900
0901                    // We need to handle it in a different way around year
0902                    // boundaries and in the transition year. Note that
0903                    // changing era and year values violates the roll
0904                    // rule: not changing larger calendar fields...
0905                    amount %= 7;
0906                    if (amount == 0) {
0907                        return;
0908                    }
0909                    long fd = cachedFixedDate;
0910                    long dowFirst = jcal.getDayOfWeekDateOnOrBefore(fd,
0911                            getFirstDayOfWeek());
0912                    fd += amount;
0913                    if (fd < dowFirst) {
0914                        fd += 7;
0915                    } else if (fd >= dowFirst + 7) {
0916                        fd -= 7;
0917                    }
0918                    LocalGregorianCalendar.Date d = getCalendarDate(fd);
0919                    set(ERA, getEraIndex(d));
0920                    set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
0921                    return;
0922                }
0923
0924                case DAY_OF_WEEK_IN_MONTH: {
0925                    min = 1; // after having normalized, min should be 1.
0926                    if (!isTransitionYear(jdate.getNormalizedYear())) {
0927                        int dom = internalGet(DAY_OF_MONTH);
0928                        int monthLength = jcal.getMonthLength(jdate);
0929                        int lastDays = monthLength % 7;
0930                        max = monthLength / 7;
0931                        int x = (dom - 1) % 7;
0932                        if (x < lastDays) {
0933                            max++;
0934                        }
0935                        set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
0936                        break;
0937                    }
0938
0939                    // Transition year handling.
0940                    long fd = cachedFixedDate;
0941                    long month1 = getFixedDateMonth1(jdate, fd);
0942                    int monthLength = actualMonthLength();
0943                    int lastDays = monthLength % 7;
0944                    max = monthLength / 7;
0945                    int x = (int) (fd - month1) % 7;
0946                    if (x < lastDays) {
0947                        max++;
0948                    }
0949                    int value = getRolledValue(internalGet(field), amount, min,
0950                            max) - 1;
0951                    fd = month1 + value * 7 + x;
0952                    LocalGregorianCalendar.Date d = getCalendarDate(fd);
0953                    set(DAY_OF_MONTH, d.getDayOfMonth());
0954                    return;
0955                }
0956                }
0957
0958                set(field, getRolledValue(internalGet(field), amount, min, max));
0959            }
0960
0961            public String getDisplayName(int field, int style, Locale locale) {
0962                if (!checkDisplayNameParams(field, style, SHORT, LONG, locale,
0963                        ERA_MASK | YEAR_MASK | MONTH_MASK | DAY_OF_WEEK_MASK
0964                                | AM_PM_MASK)) {
0965                    return null;
0966                }
0967
0968                // "GanNen" is supported only in the LONG style.
0969                if (field == YEAR
0970                        && (style == SHORT || get(YEAR) != 1 || get(ERA) == 0)) {
0971                    return null;
0972                }
0973
0974                ResourceBundle rb = LocaleData.getDateFormatData(locale);
0975                String name = null;
0976                String key = getKey(field, style);
0977                if (key != null) {
0978                    String[] strings = rb.getStringArray(key);
0979                    if (field == YEAR) {
0980                        if (strings.length > 0) {
0981                            name = strings[0];
0982                        }
0983                    } else {
0984                        int index = get(field);
0985                        // If the ERA value is out of range for strings, then
0986                        // try to get its name or abbreviation from the Era instance.
0987                        if (field == ERA && index >= strings.length
0988                                && index < eras.length) {
0989                            Era era = eras[index];
0990                            name = (style == SHORT) ? era.getAbbreviation()
0991                                    : era.getName();
0992                        } else {
0993                            if (field == DAY_OF_WEEK)
0994                                --index;
0995                            name = strings[index];
0996                        }
0997                    }
0998                }
0999                return name;
1000            }
1001
1002            public Map<String, Integer> getDisplayNames(int field, int style,
1003                    Locale locale) {
1004                if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG,
1005                        locale, ERA_MASK | YEAR_MASK | MONTH_MASK
1006                                | DAY_OF_WEEK_MASK | AM_PM_MASK)) {
1007                    return null;
1008                }
1009
1010                if (style == ALL_STYLES) {
1011                    Map<String, Integer> shortNames = getDisplayNamesImpl(
1012                            field, SHORT, locale);
1013                    if (field == AM_PM) {
1014                        return shortNames;
1015                    }
1016                    Map<String, Integer> longNames = getDisplayNamesImpl(field,
1017                            LONG, locale);
1018                    if (shortNames == null) {
1019                        return longNames;
1020                    }
1021                    if (longNames != null) {
1022                        shortNames.putAll(longNames);
1023                    }
1024                    return shortNames;
1025                }
1026
1027                // SHORT or LONG
1028                return getDisplayNamesImpl(field, style, locale);
1029            }
1030
1031            private Map<String, Integer> getDisplayNamesImpl(int field,
1032                    int style, Locale locale) {
1033                ResourceBundle rb = LocaleData.getDateFormatData(locale);
1034                String key = getKey(field, style);
1035                Map<String, Integer> map = new HashMap<String, Integer>();
1036                if (key != null) {
1037                    String[] strings = rb.getStringArray(key);
1038                    if (field == YEAR) {
1039                        if (strings.length > 0) {
1040                            map.put(strings[0], 1);
1041                        }
1042                    } else {
1043                        int base = (field == DAY_OF_WEEK) ? 1 : 0;
1044                        for (int i = 0; i < strings.length; i++) {
1045                            map.put(strings[i], base + i);
1046                        }
1047                        // If strings[] has fewer than eras[], get more names from eras[].
1048                        if (field == ERA && strings.length < eras.length) {
1049                            for (int i = strings.length; i < eras.length; i++) {
1050                                Era era = eras[i];
1051                                String name = (style == SHORT) ? era
1052                                        .getAbbreviation() : era.getName();
1053                                map.put(name, i);
1054                            }
1055                        }
1056                    }
1057                }
1058                return map.size() > 0 ? map : null;
1059            }
1060
1061            private String getKey(int field, int style) {
1062                String className = JapaneseImperialCalendar.class.getName();
1063                StringBuilder key = new StringBuilder();
1064                switch (field) {
1065                case ERA:
1066                    key.append(className);
1067                    if (style == SHORT) {
1068                        key.append(".short");
1069                    }
1070                    key.append(".Eras");
1071                    break;
1072
1073                case YEAR:
1074                    key.append(className).append(".FirstYear");
1075                    break;
1076
1077                case MONTH:
1078                    key.append(style == SHORT ? "MonthAbbreviations"
1079                            : "MonthNames");
1080                    break;
1081
1082                case DAY_OF_WEEK:
1083                    key
1084                            .append(style == SHORT ? "DayAbbreviations"
1085                                    : "DayNames");
1086                    break;
1087
1088                case AM_PM:
1089                    key.append("AmPmMarkers");
1090                    break;
1091                }
1092                return key.length() > 0 ? key.toString() : null;
1093            }
1094
1095            /**
1096             * Returns the minimum value for the given calendar field of this
1097             * <code>Calendar</code> instance. The minimum value is
1098             * defined as the smallest value returned by the {@link
1099             * Calendar#get(int) get} method for any possible time value,
1100             * taking into consideration the current values of the
1101             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1102             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1103             * and {@link Calendar#getTimeZone() getTimeZone} methods.
1104             *
1105             * @param field the calendar field.
1106             * @return the minimum value for the given calendar field.
1107             * @see #getMaximum(int)
1108             * @see #getGreatestMinimum(int)
1109             * @see #getLeastMaximum(int)
1110             * @see #getActualMinimum(int)
1111             * @see #getActualMaximum(int)
1112             */
1113            public int getMinimum(int field) {
1114                return MIN_VALUES[field];
1115            }
1116
1117            /**
1118             * Returns the maximum value for the given calendar field of this
1119             * <code>GregorianCalendar</code> instance. The maximum value is
1120             * defined as the largest value returned by the {@link
1121             * Calendar#get(int) get} method for any possible time value,
1122             * taking into consideration the current values of the
1123             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1124             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1125             * and {@link Calendar#getTimeZone() getTimeZone} methods.
1126             *
1127             * @param field the calendar field.
1128             * @return the maximum value for the given calendar field.
1129             * @see #getMinimum(int)
1130             * @see #getGreatestMinimum(int)
1131             * @see #getLeastMaximum(int)
1132             * @see #getActualMinimum(int)
1133             * @see #getActualMaximum(int)
1134             */
1135            public int getMaximum(int field) {
1136                switch (field) {
1137                case YEAR: {
1138                    // The value should depend on the time zone of this calendar.
1139                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(
1140                            Long.MAX_VALUE, getZone());
1141                    return Math.max(LEAST_MAX_VALUES[YEAR], d.getYear());
1142                }
1143                }
1144                return MAX_VALUES[field];
1145            }
1146
1147            /**
1148             * Returns the highest minimum value for the given calendar field
1149             * of this <code>GregorianCalendar</code> instance. The highest
1150             * minimum value is defined as the largest value returned by
1151             * {@link #getActualMinimum(int)} for any possible time value,
1152             * taking into consideration the current values of the
1153             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1154             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1155             * and {@link Calendar#getTimeZone() getTimeZone} methods.
1156             *
1157             * @param field the calendar field.
1158             * @return the highest minimum value for the given calendar field.
1159             * @see #getMinimum(int)
1160             * @see #getMaximum(int)
1161             * @see #getLeastMaximum(int)
1162             * @see #getActualMinimum(int)
1163             * @see #getActualMaximum(int)
1164             */
1165            public int getGreatestMinimum(int field) {
1166                return field == YEAR ? 1 : MIN_VALUES[field];
1167            }
1168
1169            /**
1170             * Returns the lowest maximum value for the given calendar field
1171             * of this <code>GregorianCalendar</code> instance. The lowest
1172             * maximum value is defined as the smallest value returned by
1173             * {@link #getActualMaximum(int)} for any possible time value,
1174             * taking into consideration the current values of the
1175             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1176             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1177             * and {@link Calendar#getTimeZone() getTimeZone} methods.
1178             *
1179             * @param field the calendar field
1180             * @return the lowest maximum value for the given calendar field.
1181             * @see #getMinimum(int)
1182             * @see #getMaximum(int)
1183             * @see #getGreatestMinimum(int)
1184             * @see #getActualMinimum(int)
1185             * @see #getActualMaximum(int)
1186             */
1187            public int getLeastMaximum(int field) {
1188                switch (field) {
1189                case YEAR: {
1190                    return Math.min(LEAST_MAX_VALUES[YEAR], getMaximum(YEAR));
1191                }
1192                }
1193                return LEAST_MAX_VALUES[field];
1194            }
1195
1196            /**
1197             * Returns the minimum value that this calendar field could have,
1198             * taking into consideration the given time value and the current
1199             * values of the
1200             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1201             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1202             * and {@link Calendar#getTimeZone() getTimeZone} methods.
1203             *
1204             * @param field the calendar field
1205             * @return the minimum of the given field for the time value of
1206             * this <code>JapaneseImperialCalendar</code>
1207             * @see #getMinimum(int)
1208             * @see #getMaximum(int)
1209             * @see #getGreatestMinimum(int)
1210             * @see #getLeastMaximum(int)
1211             * @see #getActualMaximum(int)
1212             */
1213            public int getActualMinimum(int field) {
1214                if (!isFieldSet(YEAR_MASK | MONTH_MASK | WEEK_OF_YEAR_MASK,
1215                        field)) {
1216                    return getMinimum(field);
1217                }
1218
1219                int value = 0;
1220                JapaneseImperialCalendar jc = getNormalizedCalendar();
1221                // Get a local date which includes time of day and time zone,
1222                // which are missing in jc.jdate.
1223                LocalGregorianCalendar.Date jd = jcal.getCalendarDate(jc
1224                        .getTimeInMillis(), getZone());
1225                int eraIndex = getEraIndex(jd);
1226                switch (field) {
1227                case YEAR: {
1228                    if (eraIndex > BEFORE_MEIJI) {
1229                        value = 1;
1230                        long since = eras[eraIndex].getSince(getZone());
1231                        CalendarDate d = jcal.getCalendarDate(since, getZone());
1232                        // Use the same year in jd to take care of leap
1233                        // years. i.e., both jd and d must agree on leap
1234                        // or common years.
1235                        jd.setYear(d.getYear());
1236                        jcal.normalize(jd);
1237                        assert jd.isLeapYear() == d.isLeapYear();
1238                        if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
1239                            value++;
1240                        }
1241                    } else {
1242                        value = getMinimum(field);
1243                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE,
1244                                getZone());
1245                        // Use an equvalent year of d.getYear() if
1246                        // possible. Otherwise, ignore the leap year and
1247                        // common year difference.
1248                        int y = d.getYear();
1249                        if (y > 400) {
1250                            y -= 400;
1251                        }
1252                        jd.setYear(y);
1253                        jcal.normalize(jd);
1254                        if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
1255                            value++;
1256                        }
1257                    }
1258                }
1259                    break;
1260
1261                case MONTH: {
1262                    // In Before Meiji and Meiji, January is the first month.
1263                    if (eraIndex > MEIJI && jd.getYear() == 1) {
1264                        long since = eras[eraIndex].getSince(getZone());
1265                        CalendarDate d = jcal.getCalendarDate(since, getZone());
1266                        value = d.getMonth() - 1;
1267                        if (jd.getDayOfMonth() < d.getDayOfMonth()) {
1268                            value++;
1269                        }
1270                    }
1271                }
1272                    break;
1273
1274                case WEEK_OF_YEAR: {
1275                    value = 1;
1276                    CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE,
1277                            getZone());
1278                    // shift 400 years to avoid underflow
1279                    d.addYear(+400);
1280                    jcal.normalize(d);
1281                    jd.setEra(d.getEra());
1282                    jd.setYear(d.getYear());
1283                    jcal.normalize(jd);
1284
1285                    long jan1 = jcal.getFixedDate(d);
1286                    long fd = jcal.getFixedDate(jd);
1287                    int woy = getWeekNumber(jan1, fd);
1288                    long day1 = fd - (7 * (woy - 1));
1289                    if ((day1 < jan1)
1290                            || (day1 == jan1 && jd.getTimeOfDay() < d
1291                                    .getTimeOfDay())) {
1292                        value++;
1293                    }
1294                }
1295                    break;
1296                }
1297                return value;
1298            }
1299
1300            /**
1301             * Returns the maximum value that this calendar field could have,
1302             * taking into consideration the given time value and the current
1303             * values of the
1304             * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1305             * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1306             * and
1307             * {@link Calendar#getTimeZone() getTimeZone} methods.
1308             * For example, if the date of this instance is Heisei 16February 1,
1309             * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1310             * is 29 because Heisei 16 is a leap year, and if the date of this
1311             * instance is Heisei 17 February 1, it's 28.
1312             *
1313             * @param field the calendar field
1314             * @return the maximum of the given field for the time value of
1315             * this <code>JapaneseImperialCalendar</code>
1316             * @see #getMinimum(int)
1317             * @see #getMaximum(int)
1318             * @see #getGreatestMinimum(int)
1319             * @see #getLeastMaximum(int)
1320             * @see #getActualMinimum(int)
1321             */
1322            public int getActualMaximum(int field) {
1323                final int fieldsForFixedMax = ERA_MASK | DAY_OF_WEEK_MASK
1324                        | HOUR_MASK | AM_PM_MASK | HOUR_OF_DAY_MASK
1325                        | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK
1326                        | ZONE_OFFSET_MASK | DST_OFFSET_MASK;
1327                if ((fieldsForFixedMax & (1 << field)) != 0) {
1328                    return getMaximum(field);
1329                }
1330
1331                JapaneseImperialCalendar jc = getNormalizedCalendar();
1332                LocalGregorianCalendar.Date date = jc.jdate;
1333                int normalizedYear = date.getNormalizedYear();
1334
1335                int value = -1;
1336                switch (field) {
1337                case MONTH: {
1338                    value = DECEMBER;
1339                    if (isTransitionYear(date.getNormalizedYear())) {
1340                        // TODO: there may be multiple transitions in a year.
1341                        int eraIndex = getEraIndex(date);
1342                        if (date.getYear() != 1) {
1343                            eraIndex++;
1344                            assert eraIndex < eras.length;
1345                        }
1346                        long transition = sinceFixedDates[eraIndex];
1347                        long fd = jc.cachedFixedDate;
1348                        if (fd < transition) {
1349                            LocalGregorianCalendar.Date ldate = (LocalGregorianCalendar.Date) date
1350                                    .clone();
1351                            jcal.getCalendarDateFromFixedDate(ldate,
1352                                    transition - 1);
1353                            value = ldate.getMonth() - 1;
1354                        }
1355                    } else {
1356                        LocalGregorianCalendar.Date d = jcal.getCalendarDate(
1357                                Long.MAX_VALUE, getZone());
1358                        if (date.getEra() == d.getEra()
1359                                && date.getYear() == d.getYear()) {
1360                            value = d.getMonth() - 1;
1361                        }
1362                    }
1363                }
1364                    break;
1365
1366                case DAY_OF_MONTH:
1367                    value = jcal.getMonthLength(date);
1368                    break;
1369
1370                case DAY_OF_YEAR: {
1371                    if (isTransitionYear(date.getNormalizedYear())) {
1372                        // Handle transition year.
1373                        // TODO: there may be multiple transitions in a year.
1374                        int eraIndex = getEraIndex(date);
1375                        if (date.getYear() != 1) {
1376                            eraIndex++;
1377                            assert eraIndex < eras.length;
1378                        }
1379                        long transition = sinceFixedDates[eraIndex];
1380                        long fd = jc.cachedFixedDate;
1381                        CalendarDate d = gcal
1382                                .newCalendarDate(TimeZone.NO_TIMEZONE);
1383                        d.setDate(date.getNormalizedYear(),
1384                                BaseCalendar.JANUARY, 1);
1385                        if (fd < transition) {
1386                            value = (int) (transition - gcal.getFixedDate(d));
1387                        } else {
1388                            d.addYear(+1);
1389                            value = (int) (gcal.getFixedDate(d) - transition);
1390                        }
1391                    } else {
1392                        LocalGregorianCalendar.Date d = jcal.getCalendarDate(
1393                                Long.MAX_VALUE, getZone());
1394                        if (date.getEra() == d.getEra()
1395                                && date.getYear() == d.getYear()) {
1396                            long fd = jcal.getFixedDate(d);
1397                            long jan1 = getFixedDateJan1(d, fd);
1398                            value = (int) (fd - jan1) + 1;
1399                        } else if (date.getYear() == getMinimum(YEAR)) {
1400                            CalendarDate d1 = jcal.getCalendarDate(
1401                                    Long.MIN_VALUE, getZone());
1402                            long fd1 = jcal.getFixedDate(d1);
1403                            d1.addYear(1);
1404                            d1.setMonth(BaseCalendar.JANUARY).setDayOfMonth(1);
1405                            jcal.normalize(d1);
1406                            long fd2 = jcal.getFixedDate(d1);
1407                            value = (int) (fd2 - fd1);
1408                        } else {
1409                            value = jcal.getYearLength(date);
1410                        }
1411                    }
1412                }
1413                    break;
1414
1415                case WEEK_OF_YEAR: {
1416                    if (!isTransitionYear(date.getNormalizedYear())) {
1417                        LocalGregorianCalendar.Date jd = jcal.getCalendarDate(
1418                                Long.MAX_VALUE, getZone());
1419                        if (date.getEra() == jd.getEra()
1420                                && date.getYear() == jd.getYear()) {
1421                            long fd = jcal.getFixedDate(jd);
1422                            long jan1 = getFixedDateJan1(jd, fd);
1423                            value = getWeekNumber(jan1, fd);
1424                        } else if (date.getEra() == null
1425                                && date.getYear() == getMinimum(YEAR)) {
1426                            CalendarDate d = jcal.getCalendarDate(
1427                                    Long.MIN_VALUE, getZone());
1428                            // shift 400 years to avoid underflow
1429                            d.addYear(+400);
1430                            jcal.normalize(d);
1431                            jd.setEra(d.getEra());
1432                            jd
1433                                    .setDate(d.getYear() + 1,
1434                                            BaseCalendar.JANUARY, 1);
1435                            jcal.normalize(jd);
1436                            long jan1 = jcal.getFixedDate(d);
1437                            long nextJan1 = jcal.getFixedDate(jd);
1438                            long nextJan1st = jcal.getDayOfWeekDateOnOrBefore(
1439                                    nextJan1 + 6, getFirstDayOfWeek());
1440                            int ndays = (int) (nextJan1st - nextJan1);
1441                            if (ndays >= getMinimalDaysInFirstWeek()) {
1442                                nextJan1st -= 7;
1443                            }
1444                            value = getWeekNumber(jan1, nextJan1st);
1445                        } else {
1446                            // Get the day of week of January 1 of the year
1447                            CalendarDate d = gcal
1448                                    .newCalendarDate(TimeZone.NO_TIMEZONE);
1449                            d.setDate(date.getNormalizedYear(),
1450                                    BaseCalendar.JANUARY, 1);
1451                            int dayOfWeek = gcal.getDayOfWeek(d);
1452                            // Normalize the day of week with the firstDayOfWeek value
1453                            dayOfWeek -= getFirstDayOfWeek();
1454                            if (dayOfWeek < 0) {
1455                                dayOfWeek += 7;
1456                            }
1457                            value = 52;
1458                            int magic = dayOfWeek + getMinimalDaysInFirstWeek()
1459                                    - 1;
1460                            if ((magic == 6)
1461                                    || (date.isLeapYear() && (magic == 5 || magic == 12))) {
1462                                value++;
1463                            }
1464                        }
1465                        break;
1466                    }
1467
1468                    if (jc == this ) {
1469                        jc = (JapaneseImperialCalendar) jc.clone();
1470                    }
1471                    int max = getActualMaximum(DAY_OF_YEAR);
1472                    jc.set(DAY_OF_YEAR, max);
1473                    value = jc.get(WEEK_OF_YEAR);
1474                    if (value == 1 && max > 7) {
1475                        jc.add(WEEK_OF_YEAR, -1);
1476                        value = jc.get(WEEK_OF_YEAR);
1477                    }
1478                }
1479                    break;
1480
1481                case WEEK_OF_MONTH: {
1482                    LocalGregorianCalendar.Date jd = jcal.getCalendarDate(
1483                            Long.MAX_VALUE, getZone());
1484                    if (!(date.getEra() == jd.getEra() && date.getYear() == jd
1485                            .getYear())) {
1486                        CalendarDate d = gcal
1487                                .newCalendarDate(TimeZone.NO_TIMEZONE);
1488                        d.setDate(date.getNormalizedYear(), date.getMonth(), 1);
1489                        int dayOfWeek = gcal.getDayOfWeek(d);
1490                        int monthLength = gcal.getMonthLength(d);
1491                        dayOfWeek -= getFirstDayOfWeek();
1492                        if (dayOfWeek < 0) {
1493                            dayOfWeek += 7;
1494                        }
1495                        int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1496                        value = 3;
1497                        if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1498                            value++;
1499                        }
1500                        monthLength -= nDaysFirstWeek + 7 * 3;
1501                        if (monthLength > 0) {
1502                            value++;
1503                            if (monthLength > 7) {
1504                                value++;
1505                            }
1506                        }
1507                    } else {
1508                        long fd = jcal.getFixedDate(jd);
1509                        long month1 = fd - jd.getDayOfMonth() + 1;
1510                        value = getWeekNumber(month1, fd);
1511                    }
1512                }
1513                    break;
1514
1515                case DAY_OF_WEEK_IN_MONTH: {
1516                    int ndays, dow1;
1517                    int dow = date.getDayOfWeek();
1518                    BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1519                    ndays = jcal.getMonthLength(d);
1520                    d.setDayOfMonth(1);
1521                    jcal.normalize(d);
1522                    dow1 = d.getDayOfWeek();
1523                    int x = dow - dow1;
1524                    if (x < 0) {
1525                        x += 7;
1526                    }
1527                    ndays -= x;
1528                    value = (ndays + 6) / 7;
1529                }
1530                    break;
1531
1532                case YEAR: {
1533                    CalendarDate jd = jcal.getCalendarDate(
1534                            jc.getTimeInMillis(), getZone());
1535                    CalendarDate d;
1536                    int eraIndex = getEraIndex(date);
1537                    if (eraIndex == eras.length - 1) {
1538                        d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
1539                        value = d.getYear();
1540                        // Use an equivalent year for the
1541                        // getYearOffsetInMillis call to avoid overflow.
1542                        if (value > 400) {
1543                            jd.setYear(value - 400);
1544                        }
1545                    } else {
1546                        d = jcal.getCalendarDate(eras[eraIndex + 1]
1547                                .getSince(getZone()) - 1, getZone());
1548                        value = d.getYear();
1549                        // Use the same year as d.getYear() to be
1550                        // consistent with leap and common years.
1551                        jd.setYear(value);
1552                    }
1553                    jcal.normalize(jd);
1554                    if (getYearOffsetInMillis(jd) > getYearOffsetInMillis(d)) {
1555                        value--;
1556                    }
1557                }
1558                    break;
1559
1560                default:
1561                    throw new ArrayIndexOutOfBoundsException(field);
1562                }
1563                return value;
1564            }
1565
1566            /**
1567             * Returns the millisecond offset from the beginning of the
1568             * year. In the year for Long.MIN_VALUE, it's a pseudo value
1569             * beyond the limit. The given CalendarDate object must have been
1570             * normalized before calling this method.
1571             */
1572            private final long getYearOffsetInMillis(CalendarDate date) {
1573                long t = (jcal.getDayOfYear(date) - 1) * ONE_DAY;
1574                return t + date.getTimeOfDay() - date.getZoneOffset();
1575            }
1576
1577            public Object clone() {
1578                JapaneseImperialCalendar other = (JapaneseImperialCalendar) super 
1579                        .clone();
1580
1581                other.jdate = (LocalGregorianCalendar.Date) jdate.clone();
1582                other.originalFields = null;
1583                other.zoneOffsets = null;
1584                return other;
1585            }
1586
1587            public TimeZone getTimeZone() {
1588                TimeZone zone = super .getTimeZone();
1589                // To share the zone by the CalendarDate
1590                jdate.setZone(zone);
1591                return zone;
1592            }
1593
1594            public void setTimeZone(TimeZone zone) {
1595                super .setTimeZone(zone);
1596                // To share the zone by the CalendarDate
1597                jdate.setZone(zone);
1598            }
1599
1600            /**
1601             * The fixed date corresponding to jdate. If the value is
1602             * Long.MIN_VALUE, the fixed date value is unknown.
1603             */
1604            transient private long cachedFixedDate = Long.MIN_VALUE;
1605
1606            /**
1607             * Converts the time value (millisecond offset from the <a
1608             * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
1609             * The time is <em>not</em>
1610             * recomputed first; to recompute the time, then the fields, call the
1611             * <code>complete</code> method.
1612             *
1613             * @see Calendar#complete
1614             */
1615            protected void computeFields() {
1616                int mask = 0;
1617                if (isPartiallyNormalized()) {
1618                    // Determine which calendar fields need to be computed.
1619                    mask = getSetStateFields();
1620                    int fieldMask = ~mask & ALL_FIELDS;
1621                    if (fieldMask != 0 || cachedFixedDate == Long.MIN_VALUE) {
1622                        mask |= computeFields(fieldMask, mask
1623                                & (ZONE_OFFSET_MASK | DST_OFFSET_MASK));
1624                        assert mask == ALL_FIELDS;
1625                    }
1626                } else {
1627                    // Specify all fields
1628                    mask = ALL_FIELDS;
1629                    computeFields(mask, 0);
1630                }
1631                // After computing all the fields, set the field state to `COMPUTED'.
1632                setFieldsComputed(mask);
1633            }
1634
1635            /**
1636             * This computeFields implements the conversion from UTC
1637             * (millisecond offset from the Epoch) to calendar
1638             * field values. fieldMask specifies which fields to change the
1639             * setting state to COMPUTED, although all fields are set to
1640             * the correct values. This is required to fix 4685354.
1641             *
1642             * @param fieldMask a bit mask to specify which fields to change
1643             * the setting state.
1644             * @param tzMask a bit mask to specify which time zone offset
1645             * fields to be used for time calculations
1646             * @return a new field mask that indicates what field values have
1647             * actually been set.
1648             */
1649            private int computeFields(int fieldMask, int tzMask) {
1650                int zoneOffset = 0;
1651                TimeZone tz = getZone();
1652                if (zoneOffsets == null) {
1653                    zoneOffsets = new int[2];
1654                }
1655                if (tzMask != (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) {
1656                    if (tz instanceof  ZoneInfo) {
1657                        zoneOffset = ((ZoneInfo) tz).getOffsets(time,
1658                                zoneOffsets);
1659                    } else {
1660                        zoneOffset = tz.getOffset(time);
1661                        zoneOffsets[0] = tz.getRawOffset();
1662                        zoneOffsets[1] = zoneOffset - zoneOffsets[0];
1663                    }
1664                }
1665                if (tzMask != 0) {
1666                    if (isFieldSet(tzMask, ZONE_OFFSET)) {
1667                        zoneOffsets[0] = internalGet(ZONE_OFFSET);
1668                    }
1669                    if (isFieldSet(tzMask, DST_OFFSET)) {
1670                        zoneOffsets[1] = internalGet(DST_OFFSET);
1671                    }
1672                    zoneOffset = zoneOffsets[0] + zoneOffsets[1];
1673                }
1674
1675                // By computing time and zoneOffset separately, we can take
1676                // the wider range of time+zoneOffset than the previous
1677                // implementation.
1678                long fixedDate = zoneOffset / ONE_DAY;
1679                int timeOfDay = zoneOffset % (int) ONE_DAY;
1680                fixedDate += time / ONE_DAY;
1681                timeOfDay += (int) (time % ONE_DAY);
1682                if (timeOfDay >= ONE_DAY) {
1683                    timeOfDay -= ONE_DAY;
1684                    ++fixedDate;
1685                } else {
1686                    while (timeOfDay < 0) {
1687                        timeOfDay += ONE_DAY;
1688                        --fixedDate;
1689                    }
1690                }
1691                fixedDate += EPOCH_OFFSET;
1692
1693                // See if we can use jdate to avoid date calculation.
1694                if (fixedDate != cachedFixedDate || fixedDate < 0) {
1695                    jcal.getCalendarDateFromFixedDate(jdate, fixedDate);
1696                    cachedFixedDate = fixedDate;
1697                }
1698                int era = getEraIndex(jdate);
1699                int year = jdate.getYear();
1700
1701                // Always set the ERA and YEAR values.
1702                internalSet(ERA, era);
1703                internalSet(YEAR, year);
1704                int mask = fieldMask | (ERA_MASK | YEAR_MASK);
1705
1706                int month = jdate.getMonth() - 1; // 0-based
1707                int dayOfMonth = jdate.getDayOfMonth();
1708
1709                // Set the basic date fields.
1710                if ((fieldMask & (MONTH_MASK | DAY_OF_MONTH_MASK | DAY_OF_WEEK_MASK)) != 0) {
1711                    internalSet(MONTH, month);
1712                    internalSet(DAY_OF_MONTH, dayOfMonth);
1713                    internalSet(DAY_OF_WEEK, jdate.getDayOfWeek());
1714                    mask |= MONTH_MASK | DAY_OF_MONTH_MASK | DAY_OF_WEEK_MASK;
1715                }
1716
1717                if ((fieldMask & (HOUR_OF_DAY_MASK | AM_PM_MASK | HOUR_MASK
1718                        | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK)) != 0) {
1719                    if (timeOfDay != 0) {
1720                        int hours = timeOfDay / ONE_HOUR;
1721                        internalSet(HOUR_OF_DAY, hours);
1722                        internalSet(AM_PM, hours / 12); // Assume AM == 0
1723                        internalSet(HOUR, hours % 12);
1724                        int r = timeOfDay % ONE_HOUR;
1725                        internalSet(MINUTE, r / ONE_MINUTE);
1726                        r %= ONE_MINUTE;
1727                        internalSet(SECOND, r / ONE_SECOND);
1728                        internalSet(MILLISECOND, r % ONE_SECOND);
1729                    } else {
1730                        internalSet(HOUR_OF_DAY, 0);
1731                        internalSet(AM_PM, AM);
1732                        internalSet(HOUR, 0);
1733                        internalSet(MINUTE, 0);
1734                        internalSet(SECOND, 0);
1735                        internalSet(MILLISECOND, 0);
1736                    }
1737                    mask |= (HOUR_OF_DAY_MASK | AM_PM_MASK | HOUR_MASK
1738                            | MINUTE_MASK | SECOND_MASK | MILLISECOND_MASK);
1739                }
1740
1741                if ((fieldMask & (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) != 0) {
1742                    internalSet(ZONE_OFFSET, zoneOffsets[0]);
1743                    internalSet(DST_OFFSET, zoneOffsets[1]);
1744                    mask |= (ZONE_OFFSET_MASK | DST_OFFSET_MASK);
1745                }
1746
1747                if ((fieldMask & (DAY_OF_YEAR_MASK | WEEK_OF_YEAR_MASK
1748                        | WEEK_OF_MONTH_MASK | DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
1749                    int normalizedYear = jdate.getNormalizedYear();
1750                    // If it's a year of an era transition, we need to handle
1751                    // irregular year boundaries.
1752                    boolean transitionYear = isTransitionYear(jdate
1753                            .getNormalizedYear());
1754                    int dayOfYear;
1755                    long fixedDateJan1;
1756                    if (transitionYear) {
1757                        fixedDateJan1 = getFixedDateJan1(jdate, fixedDate);
1758                        dayOfYear = (int) (fixedDate - fixedDateJan1) + 1;
1759                    } else if (normalizedYear == MIN_VALUES[YEAR]) {
1760                        CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE,
1761                                getZone());
1762                        fixedDateJan1 = jcal.getFixedDate(dx);
1763                        dayOfYear = (int) (fixedDate - fixedDateJan1) + 1;
1764                    } else {
1765                        dayOfYear = (int) jcal.getDayOfYear(jdate);
1766                        fixedDateJan1 = fixedDate - dayOfYear + 1;
1767                    }
1768                    long fixedDateMonth1 = transitionYear ? getFixedDateMonth1(
1769                            jdate, fixedDate) : fixedDate - dayOfMonth + 1;
1770
1771                    internalSet(DAY_OF_YEAR, dayOfYear);
1772                    internalSet(DAY_OF_WEEK_IN_MONTH, (dayOfMonth - 1) / 7 + 1);
1773
1774                    int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
1775
1776                    // The spec is to calculate WEEK_OF_YEAR in the
1777                    // ISO8601-style. This creates problems, though.
1778                    if (weekOfYear == 0) {
1779                        // If the date belongs to the last week of the
1780                        // previous year, use the week number of "12/31" of
1781                        // the "previous" year. Again, if the previous year is
1782                        // a transition year, we need to take care of it.
1783                        // Usually the previous day of the first day of a year
1784                        // is December 31, which is not always true in the
1785                        // Japanese imperial calendar system.
1786                        long fixedDec31 = fixedDateJan1 - 1;
1787                        long prevJan1;
1788                        LocalGregorianCalendar.Date d = getCalendarDate(fixedDec31);
1789                        if (!(transitionYear || isTransitionYear(d
1790                                .getNormalizedYear()))) {
1791                            prevJan1 = fixedDateJan1 - 365;
1792                            if (d.isLeapYear()) {
1793                                --prevJan1;
1794                            }
1795                        } else if (transitionYear) {
1796                            if (jdate.getYear() == 1) {
1797                                // As of Heisei (since Meiji) there's no case
1798                                // that there are multiple transitions in a
1799                                // year.  Historically there was such
1800                                // case. There might be such case again in the
1801                                // future.
1802                                if (era > HEISEI) {
1803                                    CalendarDate pd = eras[era - 1]
1804                                            .getSinceDate();
1805                                    if (normalizedYear == pd.getYear()) {
1806                                        d.setMonth(pd.getMonth())
1807                                                .setDayOfMonth(
1808                                                        pd.getDayOfMonth());
1809                                    }
1810                                } else {
1811                                    d.setMonth(jcal.JANUARY).setDayOfMonth(1);
1812                                }
1813                                jcal.normalize(d);
1814                                prevJan1 = jcal.getFixedDate(d);
1815                            } else {
1816                                prevJan1 = fixedDateJan1 - 365;
1817                                if (d.isLeapYear()) {
1818                                    --prevJan1;
1819                                }
1820                            }
1821                        } else {
1822                            CalendarDate cd = eras[getEraIndex(jdate)]
1823                                    .getSinceDate();
1824                            d.setMonth(cd.getMonth()).setDayOfMonth(
1825                                    cd.getDayOfMonth());
1826                            jcal.normalize(d);
1827                            prevJan1 = jcal.getFixedDate(d);
1828                        }
1829                        weekOfYear = getWeekNumber(prevJan1, fixedDec31);
1830                    } else {
1831                        if (!transitionYear) {
1832                            // Regular years
1833                            if (weekOfYear >= 52) {
1834                                long nextJan1 = fixedDateJan1 + 365;
1835                                if (jdate.isLeapYear()) {
1836                                    nextJan1++;
1837                                }
1838                                long nextJan1st = jcal
1839                                        .getDayOfWeekDateOnOrBefore(
1840                                                nextJan1 + 6,
1841                                                getFirstDayOfWeek());
1842                                int ndays = (int) (nextJan1st - nextJan1);
1843                                if (ndays >= getMinimalDaysInFirstWeek()
1844                                        && fixedDate >= (nextJan1st - 7)) {
1845                                    // The first days forms a week in which the date is included.
1846                                    weekOfYear = 1;
1847                                }
1848                            }
1849                        } else {
1850                            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate
1851                                    .clone();
1852                            long nextJan1;
1853                            if (jdate.getYear() == 1) {
1854                                d.addYear(+1);
1855                                d.setMonth(jcal.JANUARY).setDayOfMonth(1);
1856                                nextJan1 = jcal.getFixedDate(d);
1857                            } else {
1858                                int nextEraIndex = getEraIndex(d) + 1;
1859                                CalendarDate cd = eras[nextEraIndex]
1860                                        .getSinceDate();
1861                                d.setEra(eras[nextEraIndex]);
1862                                d.setDate(1, cd.getMonth(), cd.getDayOfMonth());
1863                                jcal.normalize(d);
1864                                nextJan1 = jcal.getFixedDate(d);
1865                            }
1866                            long nextJan1st = jcal.getDayOfWeekDateOnOrBefore(
1867                                    nextJan1 + 6, getFirstDayOfWeek());
1868                            int ndays = (int) (nextJan1st - nextJan1);
1869                            if (ndays >= getMinimalDaysInFirstWeek()
1870                                    && fixedDate >= (nextJan1st - 7)) {
1871                                // The first days forms a week in which the date is included.
1872                                weekOfYear = 1;
1873                            }
1874                        }
1875                    }
1876                    internalSet(WEEK_OF_YEAR, weekOfYear);
1877                    internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1,
1878                            fixedDate));
1879                    mask |= (DAY_OF_YEAR_MASK | WEEK_OF_YEAR_MASK
1880                            | WEEK_OF_MONTH_MASK | DAY_OF_WEEK_IN_MONTH_MASK);
1881                }
1882                return mask;
1883            }
1884
1885            /**
1886             * Returns the number of weeks in a period between fixedDay1 and
1887             * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
1888             * is applied to calculate the number of weeks.
1889             *
1890             * @param fixedDay1 the fixed date of the first day of the period
1891             * @param fixedDate the fixed date of the last day of the period
1892             * @return the number of weeks of the given period
1893             */
1894            private final int getWeekNumber(long fixedDay1, long fixedDate) {
1895                // We can always use `jcal' since Julian and Gregorian are the
1896                // same thing for this calculation.
1897                long fixedDay1st = jcal.getDayOfWeekDateOnOrBefore(
1898                        fixedDay1 + 6, getFirstDayOfWeek());
1899                int ndays = (int) (fixedDay1st - fixedDay1);
1900                assert ndays <= 7;
1901                if (ndays >= getMinimalDaysInFirstWeek()) {
1902                    fixedDay1st -= 7;
1903                }
1904                int normalizedDayOfPeriod = (int) (fixedDate - fixedDay1st);
1905                if (normalizedDayOfPeriod >= 0) {
1906                    return normalizedDayOfPeriod / 7 + 1;
1907                }
1908                return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
1909            }
1910
1911            /**
1912             * Converts calendar field values to the time value (millisecond
1913             * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
1914             *
1915             * @exception IllegalArgumentException if any calendar fields are invalid.
1916             */
1917            protected void computeTime() {
1918                // In non-lenient mode, perform brief checking of calendar
1919                // fields which have been set externally. Through this
1920                // checking, the field values are stored in originalFields[]
1921                // to see if any of them are normalized later.
1922                if (!isLenient()) {
1923                    if (originalFields == null) {
1924                        originalFields = new int[FIELD_COUNT];
1925                    }
1926                    for (int field = 0; field < FIELD_COUNT; field++) {
1927                        int value = internalGet(field);
1928                        if (isExternallySet(field)) {
1929                            // Quick validation for any out of range values
1930                            if (value < getMinimum(field)
1931                                    || value > getMaximum(field)) {
1932                                throw new IllegalArgumentException(
1933                                        getFieldName(field));
1934                            }
1935                        }
1936                        originalFields[field] = value;
1937                    }
1938                }
1939
1940                // Let the super class determine which calendar fields to be
1941                // used to calculate the time.
1942                int fieldMask = selectFields();
1943
1944                int year;
1945                int era;
1946
1947                if (isSet(ERA)) {
1948                    era = internalGet(ERA);
1949                    year = isSet(YEAR) ? internalGet(YEAR) : 1;
1950                } else {
1951                    if (isSet(YEAR)) {
1952                        era = eras.length - 1;
1953                        year = internalGet(YEAR);
1954                    } else {
1955                        // Equivalent to 1970 (Gregorian)
1956                        era = SHOWA;
1957                        year = 45;
1958                    }
1959                }
1960
1961                // Calculate the time of day. We rely on the convention that
1962                // an UNSET field has 0.
1963                long timeOfDay = 0;
1964                if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
1965                    timeOfDay += (long) internalGet(HOUR_OF_DAY);
1966                } else {
1967                    timeOfDay += internalGet(HOUR);
1968                    // The default value of AM_PM is 0 which designates AM.
1969                    if (isFieldSet(fieldMask, AM_PM)) {
1970                        timeOfDay += 12 * internalGet(AM_PM);
1971                    }
1972                }
1973                timeOfDay *= 60;
1974                timeOfDay += internalGet(MINUTE);
1975                timeOfDay *= 60;
1976                timeOfDay += internalGet(SECOND);
1977                timeOfDay *= 1000;
1978                timeOfDay += internalGet(MILLISECOND);
1979
1980                // Convert the time of day to the number of days and the
1981                // millisecond offset from midnight.
1982                long fixedDate = timeOfDay / ONE_DAY;
1983                timeOfDay %= ONE_DAY;
1984                while (timeOfDay < 0) {
1985                    timeOfDay += ONE_DAY;
1986                    --fixedDate;
1987                }
1988
1989                // Calculate the fixed date since January 1, 1 (Gregorian).
1990                fixedDate += getFixedDate(era, year, fieldMask);
1991
1992                // millis represents local wall-clock time in milliseconds.
1993                long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
1994
1995                // Compute the time zone offset and DST offset.  There are two potential
1996                // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
1997                // for discussion purposes here.
1998                // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
1999                //    can be in standard or in DST depending.  However, 2:00 am is an invalid
2000                //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
2001                //    We assume standard time.
2002                // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
2003                //    can be in standard or DST.  Both are valid representations (the rep
2004                //    jumps from 1:59:59 DST to 1:00:00 Std).
2005                //    Again, we assume standard time.
2006                // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
2007                // or DST_OFFSET fields; then we use those fields.
2008                TimeZone zone = getZone();
2009                if (zoneOffsets == null) {
2010                    zoneOffsets = new int[2];
2011                }
2012                int tzMask = fieldMask & (ZONE_OFFSET_MASK | DST_OFFSET_MASK);
2013                if (tzMask != (ZONE_OFFSET_MASK | DST_OFFSET_MASK)) {
2014                    if (zone instanceof  ZoneInfo) {
2015                        ((ZoneInfo) zone).getOffsetsByWall(millis, zoneOffsets);
2016                    } else {
2017                        zone.getOffsets(millis - zone.getRawOffset(),
2018                                zoneOffsets);
2019                    }
2020                }
2021                if (tzMask != 0) {
2022                    if (isFieldSet(tzMask, ZONE_OFFSET)) {
2023                        zoneOffsets[0] = internalGet(ZONE_OFFSET);
2024                    }
2025                    if (isFieldSet(tzMask, DST_OFFSET)) {
2026                        zoneOffsets[1] = internalGet(DST_OFFSET);
2027                    }
2028                }
2029
2030                // Adjust the time zone offset values to get the UTC time.
2031                millis -= zoneOffsets[0] + zoneOffsets[1];
2032
2033                // Set this calendar's time in milliseconds
2034                time = millis;
2035
2036                int mask = computeFields(fieldMask | getSetStateFields(),
2037                        tzMask);
2038
2039                if (!isLenient()) {
2040                    for (int field = 0; field < FIELD_COUNT; field++) {
2041                        if (!isExternallySet(field)) {
2042                            continue;
2043                        }
2044                        if (originalFields[field] != internalGet(field)) {
2045                            int wrongValue = internalGet(field);
2046                            // Restore the original field values
2047                            System.arraycopy(originalFields, 0, fields, 0,
2048                                    fields.length);
2049                            throw new IllegalArgumentException(
2050                                    getFieldName(field) + "=" + wrongValue
2051                                            + ", expected "
2052                                            + originalFields[field]);
2053                        }
2054                    }
2055                }
2056                setFieldsNormalized(mask);
2057            }
2058
2059            /**
2060             * Computes the fixed date under either the Gregorian or the
2061             * Julian calendar, using the given year and the specified calendar fields.
2062             *
2063             * @param cal the CalendarSystem to be used for the date calculation
2064             * @param year the normalized year number, with 0 indicating the
2065             * year 1 BCE, -1 indicating 2 BCE, etc.
2066             * @param fieldMask the calendar fields to be used for the date calculation
2067             * @return the fixed date
2068             * @see Calendar#selectFields
2069             */
2070            private long getFixedDate(int era, int year, int fieldMask) {
2071                int month = JANUARY;
2072                int firstDayOfMonth = 1;
2073                if (isFieldSet(fieldMask, MONTH)) {
2074                    // No need to check if MONTH has been set (no isSet(MONTH)
2075                    // call) since its unset value happens to be JANUARY (0).
2076                    month = internalGet(MONTH);
2077
2078                    // If the month is out of range, adjust it into range.
2079                    if (month > DECEMBER) {
2080                        year += month / 12;
2081                        month %= 12;
2082                    } else if (month < JANUARY) {
2083                        int[] rem = new int[1];
2084                        year += CalendarUtils.floorDivide(month, 12, rem);
2085                        month = rem[0];
2086                    }
2087                } else {
2088                    if (year == 1 && era != 0) {
2089                        CalendarDate d = eras[era].getSinceDate();
2090                        month = d.getMonth() - 1;
2091                        firstDayOfMonth = d.getDayOfMonth();
2092                    }
2093                }
2094
2095                // Adjust the base date if year is the minimum value.
2096                if (year == MIN_VALUES[YEAR]) {
2097                    CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE,
2098                            getZone());
2099                    int m = dx.getMonth() - 1;
2100                    if (month < m)
2101                        month = m;
2102                    if (month == m)
2103                        firstDayOfMonth = dx.getDayOfMonth();
2104                }
2105
2106                LocalGregorianCalendar.Date date = jcal
2107                        .newCalendarDate(TimeZone.NO_TIMEZONE);
2108                date.setEra(era > 0 ? eras[era] : null);
2109                date.setDate(year, month + 1, firstDayOfMonth);
2110                jcal.normalize(date);
2111
2112                // Get the fixed date since Jan 1, 1 (Gregorian). We are on
2113                // the first day of either `month' or January in 'year'.
2114                long fixedDate = jcal.getFixedDate(date);
2115
2116                if (isFieldSet(fieldMask, MONTH)) {
2117                    // Month-based calculations
2118                    if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
2119                        // We are on the "first day" of the month (which may
2120                        // not be 1). Just add the offset if DAY_OF_MONTH is
2121                        // set. If the isSet call returns false, that means
2122                        // DAY_OF_MONTH has been selected just because of the
2123                        // selected combination. We don't need to add any
2124                        // since the default value is the "first day".
2125                        if (isSet(DAY_OF_MONTH)) {
2126                            // To avoid underflow with DAY_OF_MONTH-firstDayOfMonth, add
2127                            // DAY_OF_MONTH, then subtract firstDayOfMonth.
2128                            fixedDate += internalGet(DAY_OF_MONTH);
2129                            fixedDate -= firstDayOfMonth;
2130                        }
2131                    } else {
2132                        if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2133                            long firstDayOfWeek = jcal
2134                                    .getDayOfWeekDateOnOrBefore(fixedDate + 6,
2135                                            getFirstDayOfWeek());
2136                            // If we have enough days in the first week, then
2137                            // move to the previous week.
2138                            if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2139                                firstDayOfWeek -= 7;
2140                            }
2141                            if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2142                                firstDayOfWeek = jcal
2143                                        .getDayOfWeekDateOnOrBefore(
2144                                                firstDayOfWeek + 6,
2145                                                internalGet(DAY_OF_WEEK));
2146                            }
2147                            // In lenient mode, we treat days of the previous
2148                            // months as a part of the specified
2149                            // WEEK_OF_MONTH. See 4633646.
2150                            fixedDate = firstDayOfWeek + 7
2151                                    * (internalGet(WEEK_OF_MONTH) - 1);
2152                        } else {
2153                            int dayOfWeek;
2154                            if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2155                                dayOfWeek = internalGet(DAY_OF_WEEK);
2156                            } else {
2157                                dayOfWeek = getFirstDayOfWeek();
2158                            }
2159                            // We are basing this on the day-of-week-in-month.  The only
2160                            // trickiness occurs if the day-of-week-in-month is
2161                            // negative.
2162                            int dowim;
2163                            if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2164                                dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2165                            } else {
2166                                dowim = 1;
2167                            }
2168                            if (dowim >= 0) {
2169                                fixedDate = jcal.getDayOfWeekDateOnOrBefore(
2170                                        fixedDate + (7 * dowim) - 1, dayOfWeek);
2171                            } else {
2172                                // Go to the first day of the next week of
2173                                // the specified week boundary.
2174                                int lastDate = monthLength(month, year)
2175                                        + (7 * (dowim + 1));
2176                                // Then, get the day of week date on or before the last date.
2177                                fixedDate = jcal.getDayOfWeekDateOnOrBefore(
2178                                        fixedDate + lastDate - 1, dayOfWeek);
2179                            }
2180                        }
2181                    }
2182                } else {
2183                    // We are on the first day of the year.
2184                    if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
2185                        if (isTransitionYear(date.getNormalizedYear())) {
2186                            fixedDate = getFixedDateJan1(date, fixedDate);
2187                        }
2188                        // Add the offset, then subtract 1. (Make sure to avoid underflow.)
2189                        fixedDate += internalGet(DAY_OF_YEAR);
2190                        fixedDate--;
2191                    } else {
2192                        long firstDayOfWeek = jcal.getDayOfWeekDateOnOrBefore(
2193                                fixedDate + 6, getFirstDayOfWeek());
2194                        // If we have enough days in the first week, then move
2195                        // to the previous week.
2196                        if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2197                            firstDayOfWeek -= 7;
2198                        }
2199                        if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2200                            int dayOfWeek = internalGet(DAY_OF_WEEK);
2201                            if (dayOfWeek != getFirstDayOfWeek()) {
2202                                firstDayOfWeek = jcal
2203                                        .getDayOfWeekDateOnOrBefore(
2204                                                firstDayOfWeek + 6, dayOfWeek);
2205                            }
2206                        }
2207                        fixedDate = firstDayOfWeek + 7
2208                                * ((long) internalGet(WEEK_OF_YEAR) - 1);
2209                    }
2210                }
2211                return fixedDate;
2212            }
2213
2214            /**
2215             * Returns the fixed date of the first day of the year (usually
2216             * January 1) before the specified date.
2217             *
2218             * @param date the date for which the first day of the year is
2219             * calculated. The date has to be in the cut-over year.
2220             * @param fixedDate the fixed date representation of the date
2221             */
2222            private final long getFixedDateJan1(
2223                    LocalGregorianCalendar.Date date, long fixedDate) {
2224                Era era = date.getEra();
2225                if (date.getEra() != null && date.getYear() == 1) {
2226                    for (int eraIndex = getEraIndex(date); eraIndex > 0; eraIndex--) {
2227                        CalendarDate d = eras[eraIndex].getSinceDate();
2228                        long fd = gcal.getFixedDate(d);
2229                        // There might be multiple era transitions in a year.
2230                        if (fd > fixedDate) {
2231                            continue;
2232                        }
2233                        return fd;
2234                    }
2235                }
2236                CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
2237                d.setDate(date.getNormalizedYear(), gcal.JANUARY, 1);
2238                return gcal.getFixedDate(d);
2239            }
2240
2241            /**
2242             * Returns the fixed date of the first date of the month (usually
2243             * the 1st of the month) before the specified date.
2244             *
2245             * @param date the date for which the first day of the month is
2246             * calculated. The date must be in the era transition year.
2247             * @param fixedDate the fixed date representation of the date
2248             */
2249            private final long getFixedDateMonth1(
2250                    LocalGregorianCalendar.Date date, long fixedDate) {
2251                int eraIndex = getTransitionEraIndex(date);
2252                if (eraIndex != -1) {
2253                    long transition = sinceFixedDates[eraIndex];
2254                    // If the given date is on or after the transition date, then
2255                    // return the transition date.
2256                    if (transition <= fixedDate) {
2257                        return transition;
2258                    }
2259                }
2260
2261                // Otherwise, we can use the 1st day of the month.
2262                return fixedDate - date.getDayOfMonth() + 1;
2263            }
2264
2265            /**
2266             * Returns a LocalGregorianCalendar.Date produced from the specified fixed date.
2267             *
2268             * @param fd the fixed date
2269             */
2270            private static final LocalGregorianCalendar.Date getCalendarDate(
2271                    long fd) {
2272                LocalGregorianCalendar.Date d = jcal
2273                        .newCalendarDate(TimeZone.NO_TIMEZONE);
2274                jcal.getCalendarDateFromFixedDate(d, fd);
2275                return d;
2276            }
2277
2278            /**
2279             * Returns the length of the specified month in the specified
2280             * Gregorian year. The year number must be normalized.
2281             *
2282             * @see #isLeapYear(int)
2283             */
2284            private final int monthLength(int month, int gregorianYear) {
2285                return CalendarUtils.isGregorianLeapYear(gregorianYear) ? GregorianCalendar.LEAP_MONTH_LENGTH[month]
2286                        : GregorianCalendar.MONTH_LENGTH[month];
2287            }
2288
2289            /**
2290             * Returns the length of the specified month in the year provided
2291             * by internalGet(YEAR).
2292             *
2293             * @see #isLeapYear(int)
2294             */
2295            private final int monthLength(int month) {
2296                assert jdate.isNormalized();
2297                return jdate.isLeapYear() ? GregorianCalendar.LEAP_MONTH_LENGTH[month]
2298                        : GregorianCalendar.MONTH_LENGTH[month];
2299            }
2300
2301            private final int actualMonthLength() {
2302                int length = jcal.getMonthLength(jdate);
2303                int eraIndex = getTransitionEraIndex(jdate);
2304                if (eraIndex == -1) {
2305                    long transitionFixedDate = sinceFixedDates[eraIndex];
2306                    CalendarDate d = eras[eraIndex].getSinceDate();
2307                    if (transitionFixedDate <= cachedFixedDate) {
2308                        length -= d.getDayOfMonth() - 1;
2309                    } else {
2310                        length = d.getDayOfMonth() - 1;
2311                    }
2312                }
2313                return length;
2314            }
2315
2316            /**
2317             * Returns the index to the new era if the given date is in a
2318             * transition month.  For example, if the give date is Heisei 1
2319             * (1989) January 20, then the era index for Heisei is
2320             * returned. Likewise, if the given date is Showa 64 (1989)
2321             * January 3, then the era index for Heisei is returned. If the
2322             * given date is not in any transition month, then -1 is returned.
2323             */
2324            private static final int getTransitionEraIndex(
2325                    LocalGregorianCalendar.Date date) {
2326                int eraIndex = getEraIndex(date);
2327                CalendarDate transitionDate = eras[eraIndex].getSinceDate();
2328                if (transitionDate.getYear() == date.getNormalizedYear()
2329                        && transitionDate.getMonth() == date.getMonth()) {
2330                    return eraIndex;
2331                }
2332                if (eraIndex < eras.length - 1) {
2333                    transitionDate = eras[++eraIndex].getSinceDate();
2334                    if (transitionDate.getYear() == date.getNormalizedYear()
2335                            && transitionDate.getMonth() == date.getMonth()) {
2336                        return eraIndex;
2337                    }
2338                }
2339                return -1;
2340            }
2341
2342            private final boolean isTransitionYear(int normalizedYear) {
2343                for (int i = eras.length - 1; i > 0; i--) {
2344                    int transitionYear = eras[i].getSinceDate().getYear();
2345                    if (normalizedYear == transitionYear) {
2346                        return true;
2347                    }
2348                    if (normalizedYear > transitionYear) {
2349                        break;
2350                    }
2351                }
2352                return false;
2353            }
2354
2355            private static final int getEraIndex(
2356                    LocalGregorianCalendar.Date date) {
2357                Era era = date.getEra();
2358                for (int i = eras.length - 1; i > 0; i--) {
2359                    if (eras[i] == era) {
2360                        return i;
2361                    }
2362                }
2363                return 0;
2364            }
2365
2366            /**
2367             * Returns this object if it's normalized (all fields and time are
2368             * in sync). Otherwise, a cloned object is returned after calling
2369             * complete() in lenient mode.
2370             */
2371            private final JapaneseImperialCalendar getNormalizedCalendar() {
2372                JapaneseImperialCalendar jc;
2373                if (isFullyNormalized()) {
2374                    jc = this ;
2375                } else {
2376                    // Create a clone and normalize the calendar fields
2377                    jc = (JapaneseImperialCalendar) this .clone();
2378                    jc.setLenient(true);
2379                    jc.complete();
2380                }
2381                return jc;
2382            }
2383
2384            /**
2385             * After adjustments such as add(MONTH), add(YEAR), we don't want the
2386             * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
2387             * 3, we want it to go to Feb 28.  Adjustments which might run into this
2388             * problem call this method to retain the proper month.
2389             */
2390            private final void pinDayOfMonth(LocalGregorianCalendar.Date date) {
2391                int year = date.getYear();
2392                int dom = date.getDayOfMonth();
2393                if (year != getMinimum(YEAR)) {
2394                    date.setDayOfMonth(1);
2395                    jcal.normalize(date);
2396                    int monthLength = jcal.getMonthLength(date);
2397                    if (dom > monthLength) {
2398                        date.setDayOfMonth(monthLength);
2399                    } else {
2400                        date.setDayOfMonth(dom);
2401                    }
2402                    jcal.normalize(date);
2403                } else {
2404                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(
2405                            Long.MIN_VALUE, getZone());
2406                    LocalGregorianCalendar.Date realDate = jcal
2407                            .getCalendarDate(time, getZone());
2408                    long tod = realDate.getTimeOfDay();
2409                    // Use an equivalent year.
2410                    realDate.addYear(+400);
2411                    realDate.setMonth(date.getMonth());
2412                    realDate.setDayOfMonth(1);
2413                    jcal.normalize(realDate);
2414                    int monthLength = jcal.getMonthLength(realDate);
2415                    if (dom > monthLength) {
2416                        realDate.setDayOfMonth(monthLength);
2417                    } else {
2418                        if (dom < d.getDayOfMonth()) {
2419                            realDate.setDayOfMonth(d.getDayOfMonth());
2420                        } else {
2421                            realDate.setDayOfMonth(dom);
2422                        }
2423                    }
2424                    if (realDate.getDayOfMonth() == d.getDayOfMonth()
2425                            && tod < d.getTimeOfDay()) {
2426                        realDate.setDayOfMonth(Math.min(dom + 1, monthLength));
2427                    }
2428                    // restore the year.
2429                    date.setDate(year, realDate.getMonth(), realDate
2430                            .getDayOfMonth());
2431                    // Don't normalize date here so as not to cause underflow.
2432                }
2433            }
2434
2435            /**
2436             * Returns the new value after 'roll'ing the specified value and amount.
2437             */
2438            private static final int getRolledValue(int value, int amount,
2439                    int min, int max) {
2440                assert value >= min && value <= max;
2441                int range = max - min + 1;
2442                amount %= range;
2443                int n = value + amount;
2444                if (n > max) {
2445                    n -= range;
2446                } else if (n < min) {
2447                    n += range;
2448                }
2449                assert n >= min && n <= max;
2450                return n;
2451            }
2452
2453            /**
2454             * Returns the ERA.  We need a special method for this because the
2455             * default ERA is the current era, but a zero (unset) ERA means before Meiji.
2456             */
2457            private final int internalGetEra() {
2458                return isSet(ERA) ? internalGet(ERA) : eras.length - 1;
2459            }
2460
2461            /**
2462             * Updates internal state.
2463             */
2464            private void readObject(ObjectInputStream stream)
2465                    throws IOException, ClassNotFoundException {
2466                stream.defaultReadObject();
2467                if (jdate == null) {
2468                    jdate = jcal.newCalendarDate(getZone());
2469                    cachedFixedDate = Long.MIN_VALUE;
2470                }
2471            }
2472        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.