1 /*
   2  * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.IOException;
  29 import java.io.ObjectInputStream;
  30 import sun.util.locale.provider.CalendarDataUtility;
  31 import sun.util.calendar.BaseCalendar;
  32 import sun.util.calendar.CalendarDate;
  33 import sun.util.calendar.CalendarSystem;
  34 import sun.util.calendar.CalendarUtils;
  35 import sun.util.calendar.Era;
  36 import sun.util.calendar.Gregorian;
  37 import sun.util.calendar.LocalGregorianCalendar;
  38 import sun.util.calendar.ZoneInfo;
  39 
  40 /**
  41  * <code>JapaneseImperialCalendar</code> implements a Japanese
  42  * calendar system in which the imperial era-based year numbering is
  43  * supported from the Meiji era. The following are the eras supported
  44  * by this calendar system.
  45  * <pre><tt>
  46  * ERA value   Era name    Since (in Gregorian)
  47  * ------------------------------------------------------
  48  *     0       N/A         N/A
  49  *     1       Meiji       1868-01-01 midnight local time
  50  *     2       Taisho      1912-07-30 midnight local time
  51  *     3       Showa       1926-12-25 midnight local time
  52  *     4       Heisei      1989-01-08 midnight local time
  53  * ------------------------------------------------------
  54  * </tt></pre>
  55  *
  56  * <p><code>ERA</code> value 0 specifies the years before Meiji and
  57  * the Gregorian year values are used. Unlike {@link
  58  * GregorianCalendar}, the Julian to Gregorian transition is not
  59  * supported because it doesn't make any sense to the Japanese
  60  * calendar systems used before Meiji. To represent the years before
  61  * Gregorian year 1, 0 and negative values are used. The Japanese
  62  * Imperial rescripts and government decrees don't specify how to deal
  63  * with time differences for applying the era transitions. This
  64  * calendar implementation assumes local time for all transitions.
  65  *
  66  * @author Masayoshi Okutsu
  67  * @since 1.6
  68  */
  69 class JapaneseImperialCalendar extends Calendar {
  70     /*
  71      * Implementation Notes
  72      *
  73      * This implementation uses
  74      * sun.util.calendar.LocalGregorianCalendar to perform most of the
  75      * calendar calculations. LocalGregorianCalendar is configurable
  76      * and reads <JRE_HOME>/lib/calendars.properties at the start-up.
  77      */
  78 
  79     /**
  80      * The ERA constant designating the era before Meiji.
  81      */
  82     public static final int BEFORE_MEIJI = 0;
  83 
  84     /**
  85      * The ERA constant designating the Meiji era.
  86      */
  87     public static final int MEIJI = 1;
  88 
  89     /**
  90      * The ERA constant designating the Taisho era.
  91      */
  92     public static final int TAISHO = 2;
  93 
  94     /**
  95      * The ERA constant designating the Showa era.
  96      */
  97     public static final int SHOWA = 3;
  98 
  99     /**
 100      * The ERA constant designating the Heisei era.
 101      */
 102     public static final int HEISEI = 4;
 103 
 104     private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
 105     private static final int EPOCH_YEAR     = 1970;
 106 
 107     // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
 108     // into ints, they must be longs in order to prevent arithmetic overflow
 109     // when performing (bug 4173516).
 110     private static final int  ONE_SECOND = 1000;
 111     private static final int  ONE_MINUTE = 60*ONE_SECOND;
 112     private static final int  ONE_HOUR   = 60*ONE_MINUTE;
 113     private static final long ONE_DAY    = 24*ONE_HOUR;
 114     private static final long ONE_WEEK   = 7*ONE_DAY;
 115 
 116     // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
 117     private static final LocalGregorianCalendar jcal
 118         = (LocalGregorianCalendar) CalendarSystem.forName("japanese");
 119 
 120     // Gregorian calendar instance. This is required because era
 121     // transition dates are given in Gregorian dates.
 122     private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
 123 
 124     // The Era instance representing "before Meiji".
 125     private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false);
 126 
 127     // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
 128     // doesn't have an Era representing before Meiji, which is
 129     // inconvenient for a Calendar. So, era[0] is a reference to
 130     // BEFORE_MEIJI_ERA.
 131     private static final Era[] eras;
 132 
 133     // Fixed date of the first date of each era.
 134     private static final long[] sinceFixedDates;
 135 
 136     /*
 137      * <pre>
 138      *                                 Greatest       Least
 139      * Field name             Minimum   Minimum     Maximum     Maximum
 140      * ----------             -------   -------     -------     -------
 141      * ERA                          0         0           1           1
 142      * YEAR                -292275055         1           ?           ?
 143      * MONTH                        0         0          11          11
 144      * WEEK_OF_YEAR                 1         1          52*         53
 145      * WEEK_OF_MONTH                0         0           4*          6
 146      * DAY_OF_MONTH                 1         1          28*         31
 147      * DAY_OF_YEAR                  1         1         365*        366
 148      * DAY_OF_WEEK                  1         1           7           7
 149      * DAY_OF_WEEK_IN_MONTH        -1        -1           4*          6
 150      * AM_PM                        0         0           1           1
 151      * HOUR                         0         0          11          11
 152      * HOUR_OF_DAY                  0         0          23          23
 153      * MINUTE                       0         0          59          59
 154      * SECOND                       0         0          59          59
 155      * MILLISECOND                  0         0         999         999
 156      * ZONE_OFFSET             -13:00    -13:00       14:00       14:00
 157      * DST_OFFSET                0:00      0:00        0:20        2:00
 158      * </pre>
 159      * *: depends on eras
 160      */
 161     static final int MIN_VALUES[] = {
 162         0,              // ERA
 163         -292275055,     // YEAR
 164         JANUARY,        // MONTH
 165         1,              // WEEK_OF_YEAR
 166         0,              // WEEK_OF_MONTH
 167         1,              // DAY_OF_MONTH
 168         1,              // DAY_OF_YEAR
 169         SUNDAY,         // DAY_OF_WEEK
 170         1,              // DAY_OF_WEEK_IN_MONTH
 171         AM,             // AM_PM
 172         0,              // HOUR
 173         0,              // HOUR_OF_DAY
 174         0,              // MINUTE
 175         0,              // SECOND
 176         0,              // MILLISECOND
 177         -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
 178         0               // DST_OFFSET
 179     };
 180     static final int LEAST_MAX_VALUES[] = {
 181         0,              // ERA (initialized later)
 182         0,              // YEAR (initialized later)
 183         JANUARY,        // MONTH (Showa 64 ended in January.)
 184         0,              // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.)
 185         4,              // WEEK_OF_MONTH
 186         28,             // DAY_OF_MONTH
 187         0,              // DAY_OF_YEAR (initialized later)
 188         SATURDAY,       // DAY_OF_WEEK
 189         4,              // DAY_OF_WEEK_IN
 190         PM,             // AM_PM
 191         11,             // HOUR
 192         23,             // HOUR_OF_DAY
 193         59,             // MINUTE
 194         59,             // SECOND
 195         999,            // MILLISECOND
 196         14*ONE_HOUR,    // ZONE_OFFSET
 197         20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
 198     };
 199     static final int MAX_VALUES[] = {
 200         0,              // ERA
 201         292278994,      // YEAR
 202         DECEMBER,       // MONTH
 203         53,             // WEEK_OF_YEAR
 204         6,              // WEEK_OF_MONTH
 205         31,             // DAY_OF_MONTH
 206         366,            // DAY_OF_YEAR
 207         SATURDAY,       // DAY_OF_WEEK
 208         6,              // DAY_OF_WEEK_IN
 209         PM,             // AM_PM
 210         11,             // HOUR
 211         23,             // HOUR_OF_DAY
 212         59,             // MINUTE
 213         59,             // SECOND
 214         999,            // MILLISECOND
 215         14*ONE_HOUR,    // ZONE_OFFSET
 216         2*ONE_HOUR      // DST_OFFSET (double summer time)
 217     };
 218 
 219     // Proclaim serialization compatibility with JDK 1.6
 220     private static final long serialVersionUID = -3364572813905467929L;
 221 
 222     static {
 223         Era[] es = jcal.getEras();
 224         int length = es.length + 1;
 225         eras = new Era[length];
 226         sinceFixedDates = new long[length];
 227 
 228         // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
 229         // same as Gregorian.
 230         int index = BEFORE_MEIJI;
 231         sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
 232         eras[index++] = BEFORE_MEIJI_ERA;
 233         for (Era e : es) {
 234             CalendarDate d = e.getSinceDate();
 235             sinceFixedDates[index] = gcal.getFixedDate(d);
 236             eras[index++] = e;
 237         }
 238 
 239         LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;
 240 
 241         // Calculate the least maximum year and least day of Year
 242         // values. The following code assumes that there's at most one
 243         // era transition in a Gregorian year.
 244         int year = Integer.MAX_VALUE;
 245         int dayOfYear = Integer.MAX_VALUE;
 246         CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
 247         for (int i = 1; i < eras.length; i++) {
 248             long fd = sinceFixedDates[i];
 249             CalendarDate transitionDate = eras[i].getSinceDate();
 250             date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1);
 251             long fdd = gcal.getFixedDate(date);
 252             dayOfYear = Math.min((int)(fdd - fd), dayOfYear);
 253             date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31);
 254             fdd = gcal.getFixedDate(date) + 1;
 255             dayOfYear = Math.min((int)(fd - fdd), dayOfYear);
 256 
 257             LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
 258             int y = lgd.getYear();
 259             // Unless the first year starts from January 1, the actual
 260             // max value could be one year short. For example, if it's
 261             // Showa 63 January 8, 63 is the actual max value since
 262             // Showa 64 January 8 doesn't exist.
 263             if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd.getDayOfMonth() == 1)) {
 264                 y--;
 265             }
 266             year = Math.min(y, year);
 267         }
 268         LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value.
 269         LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear;
 270     }
 271 
 272     /**
 273      * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to
 274      * avoid overhead of creating it for each calculation.
 275      */
 276     private transient LocalGregorianCalendar.Date jdate;
 277 
 278     /**
 279      * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
 280      * the GMT offset value and zoneOffsets[1] gets the daylight saving
 281      * value.
 282      */
 283     private transient int[] zoneOffsets;
 284 
 285     /**
 286      * Temporary storage for saving original fields[] values in
 287      * non-lenient mode.
 288      */
 289     private transient int[] originalFields;
 290 
 291     /**
 292      * Constructs a <code>JapaneseImperialCalendar</code> based on the current time
 293      * in the given time zone with the given locale.
 294      *
 295      * @param zone the given time zone.
 296      * @param aLocale the given locale.
 297      */
 298     JapaneseImperialCalendar(TimeZone zone, Locale aLocale) {
 299         super(zone, aLocale);
 300         jdate = jcal.newCalendarDate(zone);
 301         setTimeInMillis(System.currentTimeMillis());
 302     }
 303 
 304     /**
 305      * Returns {@code "japanese"} as the calendar type of this {@code
 306      * JapaneseImperialCalendar}.
 307      *
 308      * @return {@code "japanese"}
 309      */
 310     @Override
 311     public String getCalendarType() {
 312         return "japanese";
 313     }
 314 
 315     /**
 316      * Compares this <code>JapaneseImperialCalendar</code> to the specified
 317      * <code>Object</code>. The result is <code>true</code> if and
 318      * only if the argument is a <code>JapaneseImperialCalendar</code> object
 319      * that represents the same time value (millisecond offset from
 320      * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
 321      * <code>Calendar</code> parameters.
 322      *
 323      * @param obj the object to compare with.
 324      * @return <code>true</code> if this object is equal to <code>obj</code>;
 325      * <code>false</code> otherwise.
 326      * @see Calendar#compareTo(Calendar)
 327      */
 328     public boolean equals(Object obj) {
 329         return obj instanceof JapaneseImperialCalendar &&
 330             super.equals(obj);
 331     }
 332 
 333     /**
 334      * Generates the hash code for this
 335      * <code>JapaneseImperialCalendar</code> object.
 336      */
 337     public int hashCode() {
 338         return super.hashCode() ^ jdate.hashCode();
 339     }
 340 
 341     /**
 342      * Adds the specified (signed) amount of time to the given calendar field,
 343      * based on the calendar's rules.
 344      *
 345      * <p><em>Add rule 1</em>. The value of <code>field</code>
 346      * after the call minus the value of <code>field</code> before the
 347      * call is <code>amount</code>, modulo any overflow that has occurred in
 348      * <code>field</code>. Overflow occurs when a field value exceeds its
 349      * range and, as a result, the next larger field is incremented or
 350      * decremented and the field value is adjusted back into its range.</p>
 351      *
 352      * <p><em>Add rule 2</em>. If a smaller field is expected to be
 353      * invariant, but it is impossible for it to be equal to its
 354      * prior value because of changes in its minimum or maximum after
 355      * <code>field</code> is changed, then its value is adjusted to be as close
 356      * as possible to its expected value. A smaller field represents a
 357      * smaller unit of time. <code>HOUR</code> is a smaller field than
 358      * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
 359      * that are not expected to be invariant. The calendar system
 360      * determines what fields are expected to be invariant.</p>
 361      *
 362      * @param field the calendar field.
 363      * @param amount the amount of date or time to be added to the field.
 364      * @exception IllegalArgumentException if <code>field</code> is
 365      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
 366      * or if any calendar fields have out-of-range values in
 367      * non-lenient mode.
 368      */
 369     public void add(int field, int amount) {
 370         // If amount == 0, do nothing even the given field is out of
 371         // range. This is tested by JCK.
 372         if (amount == 0) {
 373             return;   // Do nothing!
 374         }
 375 
 376         if (field < 0 || field >= ZONE_OFFSET) {
 377             throw new IllegalArgumentException();
 378         }
 379 
 380         // Sync the time and calendar fields.
 381         complete();
 382 
 383         if (field == YEAR) {
 384             LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
 385             d.addYear(amount);
 386             pinDayOfMonth(d);
 387             set(ERA, getEraIndex(d));
 388             set(YEAR, d.getYear());
 389             set(MONTH, d.getMonth() - 1);
 390             set(DAY_OF_MONTH, d.getDayOfMonth());
 391         } else if (field == MONTH) {
 392             LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
 393             d.addMonth(amount);
 394             pinDayOfMonth(d);
 395             set(ERA, getEraIndex(d));
 396             set(YEAR, d.getYear());
 397             set(MONTH, d.getMonth() - 1);
 398             set(DAY_OF_MONTH, d.getDayOfMonth());
 399         } else if (field == ERA) {
 400             int era = internalGet(ERA) + amount;
 401             if (era < 0) {
 402                 era = 0;
 403             } else if (era > eras.length - 1) {
 404                 era = eras.length - 1;
 405             }
 406             set(ERA, era);
 407         } else {
 408             long delta = amount;
 409             long timeOfDay = 0;
 410             switch (field) {
 411             // Handle the time fields here. Convert the given
 412             // amount to milliseconds and call setTimeInMillis.
 413             case HOUR:
 414             case HOUR_OF_DAY:
 415                 delta *= 60 * 60 * 1000;        // hours to milliseconds
 416                 break;
 417 
 418             case MINUTE:
 419                 delta *= 60 * 1000;             // minutes to milliseconds
 420                 break;
 421 
 422             case SECOND:
 423                 delta *= 1000;                  // seconds to milliseconds
 424                 break;
 425 
 426             case MILLISECOND:
 427                 break;
 428 
 429             // Handle week, day and AM_PM fields which involves
 430             // time zone offset change adjustment. Convert the
 431             // given amount to the number of days.
 432             case WEEK_OF_YEAR:
 433             case WEEK_OF_MONTH:
 434             case DAY_OF_WEEK_IN_MONTH:
 435                 delta *= 7;
 436                 break;
 437 
 438             case DAY_OF_MONTH: // synonym of DATE
 439             case DAY_OF_YEAR:
 440             case DAY_OF_WEEK:
 441                 break;
 442 
 443             case AM_PM:
 444                 // Convert the amount to the number of days (delta)
 445                 // and +12 or -12 hours (timeOfDay).
 446                 delta = amount / 2;
 447                 timeOfDay = 12 * (amount % 2);
 448                 break;
 449             }
 450 
 451             // The time fields don't require time zone offset change
 452             // adjustment.
 453             if (field >= HOUR) {
 454                 setTimeInMillis(time + delta);
 455                 return;
 456             }
 457 
 458             // The rest of the fields (week, day or AM_PM fields)
 459             // require time zone offset (both GMT and DST) change
 460             // adjustment.
 461 
 462             // Translate the current time to the fixed date and time
 463             // of the day.
 464             long fd = cachedFixedDate;
 465             timeOfDay += internalGet(HOUR_OF_DAY);
 466             timeOfDay *= 60;
 467             timeOfDay += internalGet(MINUTE);
 468             timeOfDay *= 60;
 469             timeOfDay += internalGet(SECOND);
 470             timeOfDay *= 1000;
 471             timeOfDay += internalGet(MILLISECOND);
 472             if (timeOfDay >= ONE_DAY) {
 473                 fd++;
 474                 timeOfDay -= ONE_DAY;
 475             } else if (timeOfDay < 0) {
 476                 fd--;
 477                 timeOfDay += ONE_DAY;
 478             }
 479 
 480             fd += delta; // fd is the expected fixed date after the calculation
 481             int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
 482             setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
 483             zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
 484             // If the time zone offset has changed, then adjust the difference.
 485             if (zoneOffset != 0) {
 486                 setTimeInMillis(time + zoneOffset);
 487                 long fd2 = cachedFixedDate;
 488                 // If the adjustment has changed the date, then take
 489                 // the previous one.
 490                 if (fd2 != fd) {
 491                     setTimeInMillis(time - zoneOffset);
 492                 }
 493             }
 494         }
 495     }
 496 
 497     public void roll(int field, boolean up) {
 498         roll(field, up ? +1 : -1);
 499     }
 500 
 501     /**
 502      * Adds a signed amount to the specified calendar field without changing larger fields.
 503      * A negative roll amount means to subtract from field without changing
 504      * larger fields. If the specified amount is 0, this method performs nothing.
 505      *
 506      * <p>This method calls {@link #complete()} before adding the
 507      * amount so that all the calendar fields are normalized. If there
 508      * is any calendar field having an out-of-range value in non-lenient mode, then an
 509      * <code>IllegalArgumentException</code> is thrown.
 510      *
 511      * @param field the calendar field.
 512      * @param amount the signed amount to add to <code>field</code>.
 513      * @exception IllegalArgumentException if <code>field</code> is
 514      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
 515      * or if any calendar fields have out-of-range values in
 516      * non-lenient mode.
 517      * @see #roll(int,boolean)
 518      * @see #add(int,int)
 519      * @see #set(int,int)
 520      */
 521     public void roll(int field, int amount) {
 522         // If amount == 0, do nothing even the given field is out of
 523         // range. This is tested by JCK.
 524         if (amount == 0) {
 525             return;
 526         }
 527 
 528         if (field < 0 || field >= ZONE_OFFSET) {
 529             throw new IllegalArgumentException();
 530         }
 531 
 532         // Sync the time and calendar fields.
 533         complete();
 534 
 535         int min = getMinimum(field);
 536         int max = getMaximum(field);
 537 
 538         switch (field) {
 539         case ERA:
 540         case AM_PM:
 541         case MINUTE:
 542         case SECOND:
 543         case MILLISECOND:
 544             // These fields are handled simply, since they have fixed
 545             // minima and maxima. Other fields are complicated, since
 546             // the range within they must roll varies depending on the
 547             // date, a time zone and the era transitions.
 548             break;
 549 
 550         case HOUR:
 551         case HOUR_OF_DAY:
 552             {
 553                 int unit = max + 1; // 12 or 24 hours
 554                 int h = internalGet(field);
 555                 int nh = (h + amount) % unit;
 556                 if (nh < 0) {
 557                     nh += unit;
 558                 }
 559                 time += ONE_HOUR * (nh - h);
 560 
 561                 // The day might have changed, which could happen if
 562                 // the daylight saving time transition brings it to
 563                 // the next day, although it's very unlikely. But we
 564                 // have to make sure not to change the larger fields.
 565                 CalendarDate d = jcal.getCalendarDate(time, getZone());
 566                 if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
 567                     d.setEra(jdate.getEra());
 568                     d.setDate(internalGet(YEAR),
 569                               internalGet(MONTH) + 1,
 570                               internalGet(DAY_OF_MONTH));
 571                     if (field == HOUR) {
 572                         assert (internalGet(AM_PM) == PM);
 573                         d.addHours(+12); // restore PM
 574                     }
 575                     time = jcal.getTime(d);
 576                 }
 577                 int hourOfDay = d.getHours();
 578                 internalSet(field, hourOfDay % unit);
 579                 if (field == HOUR) {
 580                     internalSet(HOUR_OF_DAY, hourOfDay);
 581                 } else {
 582                     internalSet(AM_PM, hourOfDay / 12);
 583                     internalSet(HOUR, hourOfDay % 12);
 584                 }
 585 
 586                 // Time zone offset and/or daylight saving might have changed.
 587                 int zoneOffset = d.getZoneOffset();
 588                 int saving = d.getDaylightSaving();
 589                 internalSet(ZONE_OFFSET, zoneOffset - saving);
 590                 internalSet(DST_OFFSET, saving);
 591                 return;
 592             }
 593 
 594         case YEAR:
 595             min = getActualMinimum(field);
 596             max = getActualMaximum(field);
 597             break;
 598 
 599         case MONTH:
 600             // Rolling the month involves both pinning the final value to [0, 11]
 601             // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
 602             // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
 603             // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
 604             {
 605                 if (!isTransitionYear(jdate.getNormalizedYear())) {
 606                     int year = jdate.getYear();
 607                     if (year == getMaximum(YEAR)) {
 608                         CalendarDate jd = jcal.getCalendarDate(time, getZone());
 609                         CalendarDate d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
 610                         max = d.getMonth() - 1;
 611                         int n = getRolledValue(internalGet(field), amount, min, max);
 612                         if (n == max) {
 613                             // To avoid overflow, use an equivalent year.
 614                             jd.addYear(-400);
 615                             jd.setMonth(n + 1);
 616                             if (jd.getDayOfMonth() > d.getDayOfMonth()) {
 617                                 jd.setDayOfMonth(d.getDayOfMonth());
 618                                 jcal.normalize(jd);
 619                             }
 620                             if (jd.getDayOfMonth() == d.getDayOfMonth()
 621                                 && jd.getTimeOfDay() > d.getTimeOfDay()) {
 622                                 jd.setMonth(n + 1);
 623                                 jd.setDayOfMonth(d.getDayOfMonth() - 1);
 624                                 jcal.normalize(jd);
 625                                 // Month may have changed by the normalization.
 626                                 n = jd.getMonth() - 1;
 627                             }
 628                             set(DAY_OF_MONTH, jd.getDayOfMonth());
 629                         }
 630                         set(MONTH, n);
 631                     } else if (year == getMinimum(YEAR)) {
 632                         CalendarDate jd = jcal.getCalendarDate(time, getZone());
 633                         CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
 634                         min = d.getMonth() - 1;
 635                         int n = getRolledValue(internalGet(field), amount, min, max);
 636                         if (n == min) {
 637                             // To avoid underflow, use an equivalent year.
 638                             jd.addYear(+400);
 639                             jd.setMonth(n + 1);
 640                             if (jd.getDayOfMonth() < d.getDayOfMonth()) {
 641                                 jd.setDayOfMonth(d.getDayOfMonth());
 642                                 jcal.normalize(jd);
 643                             }
 644                             if (jd.getDayOfMonth() == d.getDayOfMonth()
 645                                 && jd.getTimeOfDay() < d.getTimeOfDay()) {
 646                                 jd.setMonth(n + 1);
 647                                 jd.setDayOfMonth(d.getDayOfMonth() + 1);
 648                                 jcal.normalize(jd);
 649                                 // Month may have changed by the normalization.
 650                                 n = jd.getMonth() - 1;
 651                             }
 652                             set(DAY_OF_MONTH, jd.getDayOfMonth());
 653                         }
 654                         set(MONTH, n);
 655                     } else {
 656                         int mon = (internalGet(MONTH) + amount) % 12;
 657                         if (mon < 0) {
 658                             mon += 12;
 659                         }
 660                         set(MONTH, mon);
 661 
 662                         // Keep the day of month in the range.  We
 663                         // don't want to spill over into the next
 664                         // month; e.g., we don't want jan31 + 1 mo ->
 665                         // feb31 -> mar3.
 666                         int monthLen = monthLength(mon);
 667                         if (internalGet(DAY_OF_MONTH) > monthLen) {
 668                             set(DAY_OF_MONTH, monthLen);
 669                         }
 670                     }
 671                 } else {
 672                     int eraIndex = getEraIndex(jdate);
 673                     CalendarDate transition = null;
 674                     if (jdate.getYear() == 1) {
 675                         transition = eras[eraIndex].getSinceDate();
 676                         min = transition.getMonth() - 1;
 677                     } else {
 678                         if (eraIndex < eras.length - 1) {
 679                             transition = eras[eraIndex + 1].getSinceDate();
 680                             if (transition.getYear() == jdate.getNormalizedYear()) {
 681                                 max = transition.getMonth() - 1;
 682                                 if (transition.getDayOfMonth() == 1) {
 683                                     max--;
 684                                 }
 685                             }
 686                         }
 687                     }
 688 
 689                     if (min == max) {
 690                         // The year has only one month. No need to
 691                         // process further. (Showa Gan-nen (year 1)
 692                         // and the last year have only one month.)
 693                         return;
 694                     }
 695                     int n = getRolledValue(internalGet(field), amount, min, max);
 696                     set(MONTH, n);
 697                     if (n == min) {
 698                         if (!(transition.getMonth() == BaseCalendar.JANUARY
 699                               && transition.getDayOfMonth() == 1)) {
 700                             if (jdate.getDayOfMonth() < transition.getDayOfMonth()) {
 701                                 set(DAY_OF_MONTH, transition.getDayOfMonth());
 702                             }
 703                         }
 704                     } else if (n == max && (transition.getMonth() - 1 == n)) {
 705                         int dom = transition.getDayOfMonth();
 706                         if (jdate.getDayOfMonth() >= dom) {
 707                             set(DAY_OF_MONTH, dom - 1);
 708                         }
 709                     }
 710                 }
 711                 return;
 712             }
 713 
 714         case WEEK_OF_YEAR:
 715             {
 716                 int y = jdate.getNormalizedYear();
 717                 max = getActualMaximum(WEEK_OF_YEAR);
 718                 set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK)); // update stamp[field]
 719                 int woy = internalGet(WEEK_OF_YEAR);
 720                 int value = woy + amount;
 721                 if (!isTransitionYear(jdate.getNormalizedYear())) {
 722                     int year = jdate.getYear();
 723                     if (year == getMaximum(YEAR)) {
 724                         max = getActualMaximum(WEEK_OF_YEAR);
 725                     } else if (year == getMinimum(YEAR)) {
 726                         min = getActualMinimum(WEEK_OF_YEAR);
 727                         max = getActualMaximum(WEEK_OF_YEAR);
 728                         if (value > min && value < max) {
 729                             set(WEEK_OF_YEAR, value);
 730                             return;
 731                         }
 732 
 733                     }
 734                     // If the new value is in between min and max
 735                     // (exclusive), then we can use the value.
 736                     if (value > min && value < max) {
 737                         set(WEEK_OF_YEAR, value);
 738                         return;
 739                     }
 740                     long fd = cachedFixedDate;
 741                     // Make sure that the min week has the current DAY_OF_WEEK
 742                     long day1 = fd - (7 * (woy - min));
 743                     if (year != getMinimum(YEAR)) {
 744                         if (gcal.getYearFromFixedDate(day1) != y) {
 745                             min++;
 746                         }
 747                     } else {
 748                         CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
 749                         if (day1 < jcal.getFixedDate(d)) {
 750                             min++;
 751                         }
 752                     }
 753 
 754                     // Make sure the same thing for the max week
 755                     fd += 7 * (max - internalGet(WEEK_OF_YEAR));
 756                     if (gcal.getYearFromFixedDate(fd) != y) {
 757                         max--;
 758                     }
 759                     break;
 760                 }
 761 
 762                 // Handle transition here.
 763                 long fd = cachedFixedDate;
 764                 long day1 = fd - (7 * (woy - min));
 765                 // Make sure that the min week has the current DAY_OF_WEEK
 766                 LocalGregorianCalendar.Date d = getCalendarDate(day1);
 767                 if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
 768                     min++;
 769                 }
 770 
 771                 // Make sure the same thing for the max week
 772                 fd += 7 * (max - woy);
 773                 jcal.getCalendarDateFromFixedDate(d, fd);
 774                 if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
 775                     max--;
 776                 }
 777                 // value: the new WEEK_OF_YEAR which must be converted
 778                 // to month and day of month.
 779                 value = getRolledValue(woy, amount, min, max) - 1;
 780                 d = getCalendarDate(day1 + value * 7);
 781                 set(MONTH, d.getMonth() - 1);
 782                 set(DAY_OF_MONTH, d.getDayOfMonth());
 783                 return;
 784             }
 785 
 786         case WEEK_OF_MONTH:
 787             {
 788                 boolean isTransitionYear = isTransitionYear(jdate.getNormalizedYear());
 789                 // dow: relative day of week from the first day of week
 790                 int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
 791                 if (dow < 0) {
 792                     dow += 7;
 793                 }
 794 
 795                 long fd = cachedFixedDate;
 796                 long month1;     // fixed date of the first day (usually 1) of the month
 797                 int monthLength; // actual month length
 798                 if (isTransitionYear) {
 799                     month1 = getFixedDateMonth1(jdate, fd);
 800                     monthLength = actualMonthLength();
 801                 } else {
 802                     month1 = fd - internalGet(DAY_OF_MONTH) + 1;
 803                     monthLength = jcal.getMonthLength(jdate);
 804                 }
 805 
 806                 // the first day of week of the month.
 807                 long monthDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
 808                                                                                      getFirstDayOfWeek());
 809                 // if the week has enough days to form a week, the
 810                 // week starts from the previous month.
 811                 if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
 812                     monthDay1st -= 7;
 813                 }
 814                 max = getActualMaximum(field);
 815 
 816                 // value: the new WEEK_OF_MONTH value
 817                 int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
 818 
 819                 // nfd: fixed date of the rolled date
 820                 long nfd = monthDay1st + value * 7 + dow;
 821 
 822                 // Unlike WEEK_OF_YEAR, we need to change day of week if the
 823                 // nfd is out of the month.
 824                 if (nfd < month1) {
 825                     nfd = month1;
 826                 } else if (nfd >= (month1 + monthLength)) {
 827                     nfd = month1 + monthLength - 1;
 828                 }
 829                 set(DAY_OF_MONTH, (int)(nfd - month1) + 1);
 830                 return;
 831             }
 832 
 833         case DAY_OF_MONTH:
 834             {
 835                 if (!isTransitionYear(jdate.getNormalizedYear())) {
 836                     max = jcal.getMonthLength(jdate);
 837                     break;
 838                 }
 839 
 840                 // TODO: Need to change the spec to be usable DAY_OF_MONTH rolling...
 841 
 842                 // Transition handling. We can't change year and era
 843                 // values here due to the Calendar roll spec!
 844                 long month1 = getFixedDateMonth1(jdate, cachedFixedDate);
 845 
 846                 // It may not be a regular month. Convert the date and range to
 847                 // the relative values, perform the roll, and
 848                 // convert the result back to the rolled date.
 849                 int value = getRolledValue((int)(cachedFixedDate - month1), amount,
 850                                            0, actualMonthLength() - 1);
 851                 LocalGregorianCalendar.Date d = getCalendarDate(month1 + value);
 852                 assert getEraIndex(d) == internalGetEra()
 853                     && d.getYear() == internalGet(YEAR) && d.getMonth()-1 == internalGet(MONTH);
 854                 set(DAY_OF_MONTH, d.getDayOfMonth());
 855                 return;
 856             }
 857 
 858         case DAY_OF_YEAR:
 859             {
 860                 max = getActualMaximum(field);
 861                 if (!isTransitionYear(jdate.getNormalizedYear())) {
 862                     break;
 863                 }
 864 
 865                 // Handle transition. We can't change year and era values
 866                 // here due to the Calendar roll spec.
 867                 int value = getRolledValue(internalGet(DAY_OF_YEAR), amount, min, max);
 868                 long jan0 = cachedFixedDate - internalGet(DAY_OF_YEAR);
 869                 LocalGregorianCalendar.Date d = getCalendarDate(jan0 + value);
 870                 assert getEraIndex(d) == internalGetEra() && d.getYear() == internalGet(YEAR);
 871                 set(MONTH, d.getMonth() - 1);
 872                 set(DAY_OF_MONTH, d.getDayOfMonth());
 873                 return;
 874             }
 875 
 876         case DAY_OF_WEEK:
 877             {
 878                 int normalizedYear = jdate.getNormalizedYear();
 879                 if (!isTransitionYear(normalizedYear) && !isTransitionYear(normalizedYear - 1)) {
 880                     // If the week of year is in the same year, we can
 881                     // just change DAY_OF_WEEK.
 882                     int weekOfYear = internalGet(WEEK_OF_YEAR);
 883                     if (weekOfYear > 1 && weekOfYear < 52) {
 884                         set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
 885                         max = SATURDAY;
 886                         break;
 887                     }
 888                 }
 889 
 890                 // We need to handle it in a different way around year
 891                 // boundaries and in the transition year. Note that
 892                 // changing era and year values violates the roll
 893                 // rule: not changing larger calendar fields...
 894                 amount %= 7;
 895                 if (amount == 0) {
 896                     return;
 897                 }
 898                 long fd = cachedFixedDate;
 899                 long dowFirst = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
 900                 fd += amount;
 901                 if (fd < dowFirst) {
 902                     fd += 7;
 903                 } else if (fd >= dowFirst + 7) {
 904                     fd -= 7;
 905                 }
 906                 LocalGregorianCalendar.Date d = getCalendarDate(fd);
 907                 set(ERA, getEraIndex(d));
 908                 set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
 909                 return;
 910             }
 911 
 912         case DAY_OF_WEEK_IN_MONTH:
 913             {
 914                 min = 1; // after having normalized, min should be 1.
 915                 if (!isTransitionYear(jdate.getNormalizedYear())) {
 916                     int dom = internalGet(DAY_OF_MONTH);
 917                     int monthLength = jcal.getMonthLength(jdate);
 918                     int lastDays = monthLength % 7;
 919                     max = monthLength / 7;
 920                     int x = (dom - 1) % 7;
 921                     if (x < lastDays) {
 922                         max++;
 923                     }
 924                     set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
 925                     break;
 926                 }
 927 
 928                 // Transition year handling.
 929                 long fd = cachedFixedDate;
 930                 long month1 = getFixedDateMonth1(jdate, fd);
 931                 int monthLength = actualMonthLength();
 932                 int lastDays = monthLength % 7;
 933                 max = monthLength / 7;
 934                 int x = (int)(fd - month1) % 7;
 935                 if (x < lastDays) {
 936                     max++;
 937                 }
 938                 int value = getRolledValue(internalGet(field), amount, min, max) - 1;
 939                 fd = month1 + value * 7 + x;
 940                 LocalGregorianCalendar.Date d = getCalendarDate(fd);
 941                 set(DAY_OF_MONTH, d.getDayOfMonth());
 942                 return;
 943             }
 944         }
 945 
 946         set(field, getRolledValue(internalGet(field), amount, min, max));
 947     }
 948 
 949     public String getDisplayName(int field, int style, Locale locale) {
 950         if (!checkDisplayNameParams(field, style, SHORT, LONG, locale,
 951                                     ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
 952             return null;
 953         }
 954 
 955         int fieldValue = get(field);
 956 
 957         // "GanNen" is supported only in the LONG style.
 958         if (field == YEAR
 959             && (getBaseStyle(style) == SHORT || fieldValue != 1 || get(ERA) == 0)) {
 960             return null;
 961         }
 962 
 963         String name = CalendarDataUtility.retrieveFieldValueName("japanese", field, fieldValue, style, locale);
 964         // If the ERA value is null, then
 965         // try to get its name or abbreviation from the Era instance.
 966         if (name == null && field == ERA && fieldValue < eras.length) {
 967             Era era = eras[fieldValue];
 968             name = (style == SHORT) ? era.getAbbreviation() : era.getName();
 969         }
 970         return name;
 971     }
 972 
 973     public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
 974         if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
 975                                     ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
 976             return null;
 977         }
 978         Map<String, Integer> names = CalendarDataUtility.retrieveFieldValueNames("japanese", field, style, locale);
 979         // If strings[] has fewer than eras[], get more names from eras[].
 980         if (field == ERA) {
 981             int size = names.size();
 982             if (style == ALL_STYLES) {
 983                 size /= 2; // SHORT and LONG
 984             }
 985             if (size < eras.length) {
 986                 int baseStyle = getBaseStyle(style);
 987                 for (int i = size; i < eras.length; i++) {
 988                     Era era = eras[i];
 989                     if (baseStyle == ALL_STYLES || baseStyle == SHORT) {
 990                         names.put(era.getAbbreviation(), i);
 991                     }
 992                     if (baseStyle == ALL_STYLES || baseStyle == LONG) {
 993                         names.put(era.getName(), i);
 994                     }
 995                 }
 996             }
 997         }
 998         return names;
 999     }
1000 
1001     /**
1002      * Returns the minimum value for the given calendar field of this
1003      * <code>Calendar</code> instance. The minimum value is
1004      * defined as the smallest value returned by the {@link
1005      * Calendar#get(int) get} method for any possible time value,
1006      * taking into consideration the current values of the
1007      * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1008      * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1009      * and {@link Calendar#getTimeZone() getTimeZone} methods.
1010      *
1011      * @param field the calendar field.
1012      * @return the minimum value for the given calendar field.
1013      * @see #getMaximum(int)
1014      * @see #getGreatestMinimum(int)
1015      * @see #getLeastMaximum(int)
1016      * @see #getActualMinimum(int)
1017      * @see #getActualMaximum(int)
1018      */
1019     public int getMinimum(int field) {
1020         return MIN_VALUES[field];
1021     }
1022 
1023     /**
1024      * Returns the maximum value for the given calendar field of this
1025      * <code>GregorianCalendar</code> instance. The maximum value is
1026      * defined as the largest value returned by the {@link
1027      * Calendar#get(int) get} method for any possible time value,
1028      * taking into consideration the current values of the
1029      * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1030      * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1031      * and {@link Calendar#getTimeZone() getTimeZone} methods.
1032      *
1033      * @param field the calendar field.
1034      * @return the maximum value for the given calendar field.
1035      * @see #getMinimum(int)
1036      * @see #getGreatestMinimum(int)
1037      * @see #getLeastMaximum(int)
1038      * @see #getActualMinimum(int)
1039      * @see #getActualMaximum(int)
1040      */
1041     public int getMaximum(int field) {
1042         switch (field) {
1043         case YEAR:
1044             {
1045                 // The value should depend on the time zone of this calendar.
1046                 LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
1047                                                                      getZone());
1048                 return Math.max(LEAST_MAX_VALUES[YEAR], d.getYear());
1049             }
1050         }
1051         return MAX_VALUES[field];
1052     }
1053 
1054     /**
1055      * Returns the highest minimum value for the given calendar field
1056      * of this <code>GregorianCalendar</code> instance. The highest
1057      * minimum value is defined as the largest value returned by
1058      * {@link #getActualMinimum(int)} for any possible time value,
1059      * taking into consideration the current values of the
1060      * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1061      * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1062      * and {@link Calendar#getTimeZone() getTimeZone} methods.
1063      *
1064      * @param field the calendar field.
1065      * @return the highest minimum value for the given calendar field.
1066      * @see #getMinimum(int)
1067      * @see #getMaximum(int)
1068      * @see #getLeastMaximum(int)
1069      * @see #getActualMinimum(int)
1070      * @see #getActualMaximum(int)
1071      */
1072     public int getGreatestMinimum(int field) {
1073         return field == YEAR ? 1 : MIN_VALUES[field];
1074     }
1075 
1076     /**
1077      * Returns the lowest maximum value for the given calendar field
1078      * of this <code>GregorianCalendar</code> instance. The lowest
1079      * maximum value is defined as the smallest value returned by
1080      * {@link #getActualMaximum(int)} for any possible time value,
1081      * taking into consideration the current values of the
1082      * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1083      * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1084      * and {@link Calendar#getTimeZone() getTimeZone} methods.
1085      *
1086      * @param field the calendar field
1087      * @return the lowest maximum value for the given calendar field.
1088      * @see #getMinimum(int)
1089      * @see #getMaximum(int)
1090      * @see #getGreatestMinimum(int)
1091      * @see #getActualMinimum(int)
1092      * @see #getActualMaximum(int)
1093      */
1094     public int getLeastMaximum(int field) {
1095         switch (field) {
1096         case YEAR:
1097             {
1098                 return Math.min(LEAST_MAX_VALUES[YEAR], getMaximum(YEAR));
1099             }
1100         }
1101         return LEAST_MAX_VALUES[field];
1102     }
1103 
1104     /**
1105      * Returns the minimum value that this calendar field could have,
1106      * taking into consideration the given time value and the current
1107      * values of the
1108      * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1109      * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1110      * and {@link Calendar#getTimeZone() getTimeZone} methods.
1111      *
1112      * @param field the calendar field
1113      * @return the minimum of the given field for the time value of
1114      * this <code>JapaneseImperialCalendar</code>
1115      * @see #getMinimum(int)
1116      * @see #getMaximum(int)
1117      * @see #getGreatestMinimum(int)
1118      * @see #getLeastMaximum(int)
1119      * @see #getActualMaximum(int)
1120      */
1121     public int getActualMinimum(int field) {
1122         if (!isFieldSet(YEAR_MASK|MONTH_MASK|WEEK_OF_YEAR_MASK, field)) {
1123             return getMinimum(field);
1124         }
1125 
1126         int value = 0;
1127         JapaneseImperialCalendar jc = getNormalizedCalendar();
1128         // Get a local date which includes time of day and time zone,
1129         // which are missing in jc.jdate.
1130         LocalGregorianCalendar.Date jd = jcal.getCalendarDate(jc.getTimeInMillis(),
1131                                                               getZone());
1132         int eraIndex = getEraIndex(jd);
1133         switch (field) {
1134         case YEAR:
1135             {
1136                 if (eraIndex > BEFORE_MEIJI) {
1137                     value = 1;
1138                     long since = eras[eraIndex].getSince(getZone());
1139                     CalendarDate d = jcal.getCalendarDate(since, getZone());
1140                     // Use the same year in jd to take care of leap
1141                     // years. i.e., both jd and d must agree on leap
1142                     // or common years.
1143                     jd.setYear(d.getYear());
1144                     jcal.normalize(jd);
1145                     assert jd.isLeapYear() == d.isLeapYear();
1146                     if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
1147                         value++;
1148                     }
1149                 } else {
1150                     value = getMinimum(field);
1151                     CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
1152                     // Use an equvalent year of d.getYear() if
1153                     // possible. Otherwise, ignore the leap year and
1154                     // common year difference.
1155                     int y = d.getYear();
1156                     if (y > 400) {
1157                         y -= 400;
1158                     }
1159                     jd.setYear(y);
1160                     jcal.normalize(jd);
1161                     if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
1162                         value++;
1163                     }
1164                 }
1165             }
1166             break;
1167 
1168         case MONTH:
1169             {
1170                 // In Before Meiji and Meiji, January is the first month.
1171                 if (eraIndex > MEIJI && jd.getYear() == 1) {
1172                     long since = eras[eraIndex].getSince(getZone());
1173                     CalendarDate d = jcal.getCalendarDate(since, getZone());
1174                     value = d.getMonth() - 1;
1175                     if (jd.getDayOfMonth() < d.getDayOfMonth()) {
1176                         value++;
1177                     }
1178                 }
1179             }
1180             break;
1181 
1182         case WEEK_OF_YEAR:
1183             {
1184                 value = 1;
1185                 CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
1186                 // shift 400 years to avoid underflow
1187                 d.addYear(+400);
1188                 jcal.normalize(d);
1189                 jd.setEra(d.getEra());
1190                 jd.setYear(d.getYear());
1191                 jcal.normalize(jd);
1192 
1193                 long jan1 = jcal.getFixedDate(d);
1194                 long fd = jcal.getFixedDate(jd);
1195                 int woy = getWeekNumber(jan1, fd);
1196                 long day1 = fd - (7 * (woy - 1));
1197                 if ((day1 < jan1) ||
1198                     (day1 == jan1 &&
1199                      jd.getTimeOfDay() < d.getTimeOfDay())) {
1200                     value++;
1201                 }
1202             }
1203             break;
1204         }
1205         return value;
1206     }
1207 
1208     /**
1209      * Returns the maximum value that this calendar field could have,
1210      * taking into consideration the given time value and the current
1211      * values of the
1212      * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
1213      * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
1214      * and
1215      * {@link Calendar#getTimeZone() getTimeZone} methods.
1216      * For example, if the date of this instance is Heisei 16February 1,
1217      * the actual maximum value of the <code>DAY_OF_MONTH</code> field
1218      * is 29 because Heisei 16 is a leap year, and if the date of this
1219      * instance is Heisei 17 February 1, it's 28.
1220      *
1221      * @param field the calendar field
1222      * @return the maximum of the given field for the time value of
1223      * this <code>JapaneseImperialCalendar</code>
1224      * @see #getMinimum(int)
1225      * @see #getMaximum(int)
1226      * @see #getGreatestMinimum(int)
1227      * @see #getLeastMaximum(int)
1228      * @see #getActualMinimum(int)
1229      */
1230     public int getActualMaximum(int field) {
1231         final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
1232             HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
1233             ZONE_OFFSET_MASK|DST_OFFSET_MASK;
1234         if ((fieldsForFixedMax & (1<<field)) != 0) {
1235             return getMaximum(field);
1236         }
1237 
1238         JapaneseImperialCalendar jc = getNormalizedCalendar();
1239         LocalGregorianCalendar.Date date = jc.jdate;
1240         int normalizedYear = date.getNormalizedYear();
1241 
1242         int value = -1;
1243         switch (field) {
1244         case MONTH:
1245             {
1246                 value = DECEMBER;
1247                 if (isTransitionYear(date.getNormalizedYear())) {
1248                     // TODO: there may be multiple transitions in a year.
1249                     int eraIndex = getEraIndex(date);
1250                     if (date.getYear() != 1) {
1251                         eraIndex++;
1252                         assert eraIndex < eras.length;
1253                     }
1254                     long transition = sinceFixedDates[eraIndex];
1255                     long fd = jc.cachedFixedDate;
1256                     if (fd < transition) {
1257                         LocalGregorianCalendar.Date ldate
1258                             = (LocalGregorianCalendar.Date) date.clone();
1259                         jcal.getCalendarDateFromFixedDate(ldate, transition - 1);
1260                         value = ldate.getMonth() - 1;
1261                     }
1262                 } else {
1263                     LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
1264                                                                          getZone());
1265                     if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
1266                         value = d.getMonth() - 1;
1267                     }
1268                 }
1269             }
1270             break;
1271 
1272         case DAY_OF_MONTH:
1273             value = jcal.getMonthLength(date);
1274             break;
1275 
1276         case DAY_OF_YEAR:
1277             {
1278                 if (isTransitionYear(date.getNormalizedYear())) {
1279                     // Handle transition year.
1280                     // TODO: there may be multiple transitions in a year.
1281                     int eraIndex = getEraIndex(date);
1282                     if (date.getYear() != 1) {
1283                         eraIndex++;
1284                         assert eraIndex < eras.length;
1285                     }
1286                     long transition = sinceFixedDates[eraIndex];
1287                     long fd = jc.cachedFixedDate;
1288                     CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
1289                     d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
1290                     if (fd < transition) {
1291                         value = (int)(transition - gcal.getFixedDate(d));
1292                     } else {
1293                         d.addYear(+1);
1294                         value = (int)(gcal.getFixedDate(d) - transition);
1295                     }
1296                 } else {
1297                     LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
1298                                                                          getZone());
1299                     if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
1300                         long fd = jcal.getFixedDate(d);
1301                         long jan1 = getFixedDateJan1(d, fd);
1302                         value = (int)(fd - jan1) + 1;
1303                     } else if (date.getYear() == getMinimum(YEAR)) {
1304                         CalendarDate d1 = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
1305                         long fd1 = jcal.getFixedDate(d1);
1306                         d1.addYear(1);
1307                         d1.setMonth(BaseCalendar.JANUARY).setDayOfMonth(1);
1308                         jcal.normalize(d1);
1309                         long fd2 = jcal.getFixedDate(d1);
1310                         value = (int)(fd2 - fd1);
1311                     } else {
1312                         value = jcal.getYearLength(date);
1313                     }
1314                 }
1315             }
1316             break;
1317 
1318         case WEEK_OF_YEAR:
1319             {
1320                 if (!isTransitionYear(date.getNormalizedYear())) {
1321                     LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
1322                                                                           getZone());
1323                     if (date.getEra() == jd.getEra() && date.getYear() == jd.getYear()) {
1324                         long fd = jcal.getFixedDate(jd);
1325                         long jan1 = getFixedDateJan1(jd, fd);
1326                         value = getWeekNumber(jan1, fd);
1327                     } else if (date.getEra() == null && date.getYear() == getMinimum(YEAR)) {
1328                         CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
1329                         // shift 400 years to avoid underflow
1330                         d.addYear(+400);
1331                         jcal.normalize(d);
1332                         jd.setEra(d.getEra());
1333                         jd.setDate(d.getYear() + 1, BaseCalendar.JANUARY, 1);
1334                         jcal.normalize(jd);
1335                         long jan1 = jcal.getFixedDate(d);
1336                         long nextJan1 = jcal.getFixedDate(jd);
1337                         long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
1338                                                                                             getFirstDayOfWeek());
1339                         int ndays = (int)(nextJan1st - nextJan1);
1340                         if (ndays >= getMinimalDaysInFirstWeek()) {
1341                             nextJan1st -= 7;
1342                         }
1343                         value = getWeekNumber(jan1, nextJan1st);
1344                     } else {
1345                         // Get the day of week of January 1 of the year
1346                         CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
1347                         d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
1348                         int dayOfWeek = gcal.getDayOfWeek(d);
1349                         // Normalize the day of week with the firstDayOfWeek value
1350                         dayOfWeek -= getFirstDayOfWeek();
1351                         if (dayOfWeek < 0) {
1352                             dayOfWeek += 7;
1353                         }
1354                         value = 52;
1355                         int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
1356                         if ((magic == 6) ||
1357                             (date.isLeapYear() && (magic == 5 || magic == 12))) {
1358                             value++;
1359                         }
1360                     }
1361                     break;
1362                 }
1363 
1364                 if (jc == this) {
1365                     jc = (JapaneseImperialCalendar) jc.clone();
1366                 }
1367                 int max = getActualMaximum(DAY_OF_YEAR);
1368                 jc.set(DAY_OF_YEAR, max);
1369                 value = jc.get(WEEK_OF_YEAR);
1370                 if (value == 1 && max > 7) {
1371                     jc.add(WEEK_OF_YEAR, -1);
1372                     value = jc.get(WEEK_OF_YEAR);
1373                 }
1374             }
1375             break;
1376 
1377         case WEEK_OF_MONTH:
1378             {
1379                 LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
1380                                                                       getZone());
1381                 if (!(date.getEra() == jd.getEra() && date.getYear() == jd.getYear())) {
1382                     CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
1383                     d.setDate(date.getNormalizedYear(), date.getMonth(), 1);
1384                     int dayOfWeek = gcal.getDayOfWeek(d);
1385                     int monthLength = gcal.getMonthLength(d);
1386                     dayOfWeek -= getFirstDayOfWeek();
1387                     if (dayOfWeek < 0) {
1388                         dayOfWeek += 7;
1389                     }
1390                     int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
1391                     value = 3;
1392                     if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
1393                         value++;
1394                     }
1395                     monthLength -= nDaysFirstWeek + 7 * 3;
1396                     if (monthLength > 0) {
1397                         value++;
1398                         if (monthLength > 7) {
1399                             value++;
1400                         }
1401                     }
1402                 } else {
1403                     long fd = jcal.getFixedDate(jd);
1404                     long month1 = fd - jd.getDayOfMonth() + 1;
1405                     value = getWeekNumber(month1, fd);
1406                 }
1407             }
1408             break;
1409 
1410         case DAY_OF_WEEK_IN_MONTH:
1411             {
1412                 int ndays, dow1;
1413                 int dow = date.getDayOfWeek();
1414                 BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
1415                 ndays = jcal.getMonthLength(d);
1416                 d.setDayOfMonth(1);
1417                 jcal.normalize(d);
1418                 dow1 = d.getDayOfWeek();
1419                 int x = dow - dow1;
1420                 if (x < 0) {
1421                     x += 7;
1422                 }
1423                 ndays -= x;
1424                 value = (ndays + 6) / 7;
1425             }
1426             break;
1427 
1428         case YEAR:
1429             {
1430                 CalendarDate jd = jcal.getCalendarDate(jc.getTimeInMillis(), getZone());
1431                 CalendarDate d;
1432                 int eraIndex = getEraIndex(date);
1433                 if (eraIndex == eras.length - 1) {
1434                     d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
1435                     value = d.getYear();
1436                     // Use an equivalent year for the
1437                     // getYearOffsetInMillis call to avoid overflow.
1438                     if (value > 400) {
1439                         jd.setYear(value - 400);
1440                     }
1441                 } else {
1442                     d = jcal.getCalendarDate(eras[eraIndex + 1].getSince(getZone()) - 1,
1443                                              getZone());
1444                     value = d.getYear();
1445                     // Use the same year as d.getYear() to be
1446                     // consistent with leap and common years.
1447                     jd.setYear(value);
1448                 }
1449                 jcal.normalize(jd);
1450                 if (getYearOffsetInMillis(jd) > getYearOffsetInMillis(d)) {
1451                     value--;
1452                 }
1453             }
1454             break;
1455 
1456         default:
1457             throw new ArrayIndexOutOfBoundsException(field);
1458         }
1459         return value;
1460     }
1461 
1462     /**
1463      * Returns the millisecond offset from the beginning of the
1464      * year. In the year for Long.MIN_VALUE, it's a pseudo value
1465      * beyond the limit. The given CalendarDate object must have been
1466      * normalized before calling this method.
1467      */
1468     private long getYearOffsetInMillis(CalendarDate date) {
1469         long t = (jcal.getDayOfYear(date) - 1) * ONE_DAY;
1470         return t + date.getTimeOfDay() - date.getZoneOffset();
1471     }
1472 
1473     public Object clone() {
1474         JapaneseImperialCalendar other = (JapaneseImperialCalendar) super.clone();
1475 
1476         other.jdate = (LocalGregorianCalendar.Date) jdate.clone();
1477         other.originalFields = null;
1478         other.zoneOffsets = null;
1479         return other;
1480     }
1481 
1482     public TimeZone getTimeZone() {
1483         TimeZone zone = super.getTimeZone();
1484         // To share the zone by the CalendarDate
1485         jdate.setZone(zone);
1486         return zone;
1487     }
1488 
1489     public void setTimeZone(TimeZone zone) {
1490         super.setTimeZone(zone);
1491         // To share the zone by the CalendarDate
1492         jdate.setZone(zone);
1493     }
1494 
1495     /**
1496      * The fixed date corresponding to jdate. If the value is
1497      * Long.MIN_VALUE, the fixed date value is unknown.
1498      */
1499     transient private long cachedFixedDate = Long.MIN_VALUE;
1500 
1501     /**
1502      * Converts the time value (millisecond offset from the <a
1503      * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
1504      * The time is <em>not</em>
1505      * recomputed first; to recompute the time, then the fields, call the
1506      * <code>complete</code> method.
1507      *
1508      * @see Calendar#complete
1509      */
1510     protected void computeFields() {
1511         int mask = 0;
1512         if (isPartiallyNormalized()) {
1513             // Determine which calendar fields need to be computed.
1514             mask = getSetStateFields();
1515             int fieldMask = ~mask & ALL_FIELDS;
1516             if (fieldMask != 0 || cachedFixedDate == Long.MIN_VALUE) {
1517                 mask |= computeFields(fieldMask,
1518                                       mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
1519                 assert mask == ALL_FIELDS;
1520             }
1521         } else {
1522             // Specify all fields
1523             mask = ALL_FIELDS;
1524             computeFields(mask, 0);
1525         }
1526         // After computing all the fields, set the field state to `COMPUTED'.
1527         setFieldsComputed(mask);
1528     }
1529 
1530     /**
1531      * This computeFields implements the conversion from UTC
1532      * (millisecond offset from the Epoch) to calendar
1533      * field values. fieldMask specifies which fields to change the
1534      * setting state to COMPUTED, although all fields are set to
1535      * the correct values. This is required to fix 4685354.
1536      *
1537      * @param fieldMask a bit mask to specify which fields to change
1538      * the setting state.
1539      * @param tzMask a bit mask to specify which time zone offset
1540      * fields to be used for time calculations
1541      * @return a new field mask that indicates what field values have
1542      * actually been set.
1543      */
1544     private int computeFields(int fieldMask, int tzMask) {
1545         int zoneOffset = 0;
1546         TimeZone tz = getZone();
1547         if (zoneOffsets == null) {
1548             zoneOffsets = new int[2];
1549         }
1550         if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
1551             if (tz instanceof ZoneInfo) {
1552                 zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
1553             } else {
1554                 zoneOffset = tz.getOffset(time);
1555                 zoneOffsets[0] = tz.getRawOffset();
1556                 zoneOffsets[1] = zoneOffset - zoneOffsets[0];
1557             }
1558         }
1559         if (tzMask != 0) {
1560             if (isFieldSet(tzMask, ZONE_OFFSET)) {
1561                 zoneOffsets[0] = internalGet(ZONE_OFFSET);
1562             }
1563             if (isFieldSet(tzMask, DST_OFFSET)) {
1564                 zoneOffsets[1] = internalGet(DST_OFFSET);
1565             }
1566             zoneOffset = zoneOffsets[0] + zoneOffsets[1];
1567         }
1568 
1569         // By computing time and zoneOffset separately, we can take
1570         // the wider range of time+zoneOffset than the previous
1571         // implementation.
1572         long fixedDate = zoneOffset / ONE_DAY;
1573         int timeOfDay = zoneOffset % (int)ONE_DAY;
1574         fixedDate += time / ONE_DAY;
1575         timeOfDay += (int) (time % ONE_DAY);
1576         if (timeOfDay >= ONE_DAY) {
1577             timeOfDay -= ONE_DAY;
1578             ++fixedDate;
1579         } else {
1580             while (timeOfDay < 0) {
1581                 timeOfDay += ONE_DAY;
1582                 --fixedDate;
1583             }
1584         }
1585         fixedDate += EPOCH_OFFSET;
1586 
1587         // See if we can use jdate to avoid date calculation.
1588         if (fixedDate != cachedFixedDate || fixedDate < 0) {
1589             jcal.getCalendarDateFromFixedDate(jdate, fixedDate);
1590             cachedFixedDate = fixedDate;
1591         }
1592         int era = getEraIndex(jdate);
1593         int year = jdate.getYear();
1594 
1595         // Always set the ERA and YEAR values.
1596         internalSet(ERA, era);
1597         internalSet(YEAR, year);
1598         int mask = fieldMask | (ERA_MASK|YEAR_MASK);
1599 
1600         int month =  jdate.getMonth() - 1; // 0-based
1601         int dayOfMonth = jdate.getDayOfMonth();
1602 
1603         // Set the basic date fields.
1604         if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
1605             != 0) {
1606             internalSet(MONTH, month);
1607             internalSet(DAY_OF_MONTH, dayOfMonth);
1608             internalSet(DAY_OF_WEEK, jdate.getDayOfWeek());
1609             mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
1610         }
1611 
1612         if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
1613                           |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
1614             if (timeOfDay != 0) {
1615                 int hours = timeOfDay / ONE_HOUR;
1616                 internalSet(HOUR_OF_DAY, hours);
1617                 internalSet(AM_PM, hours / 12); // Assume AM == 0
1618                 internalSet(HOUR, hours % 12);
1619                 int r = timeOfDay % ONE_HOUR;
1620                 internalSet(MINUTE, r / ONE_MINUTE);
1621                 r %= ONE_MINUTE;
1622                 internalSet(SECOND, r / ONE_SECOND);
1623                 internalSet(MILLISECOND, r % ONE_SECOND);
1624             } else {
1625                 internalSet(HOUR_OF_DAY, 0);
1626                 internalSet(AM_PM, AM);
1627                 internalSet(HOUR, 0);
1628                 internalSet(MINUTE, 0);
1629                 internalSet(SECOND, 0);
1630                 internalSet(MILLISECOND, 0);
1631             }
1632             mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
1633                      |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
1634         }
1635 
1636         if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
1637             internalSet(ZONE_OFFSET, zoneOffsets[0]);
1638             internalSet(DST_OFFSET, zoneOffsets[1]);
1639             mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
1640         }
1641 
1642         if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK
1643                           |WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
1644             int normalizedYear = jdate.getNormalizedYear();
1645             // If it's a year of an era transition, we need to handle
1646             // irregular year boundaries.
1647             boolean transitionYear = isTransitionYear(jdate.getNormalizedYear());
1648             int dayOfYear;
1649             long fixedDateJan1;
1650             if (transitionYear) {
1651                 fixedDateJan1 = getFixedDateJan1(jdate, fixedDate);
1652                 dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
1653             } else if (normalizedYear == MIN_VALUES[YEAR]) {
1654                 CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
1655                 fixedDateJan1 = jcal.getFixedDate(dx);
1656                 dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
1657             } else {
1658                 dayOfYear = (int) jcal.getDayOfYear(jdate);
1659                 fixedDateJan1 = fixedDate - dayOfYear + 1;
1660             }
1661             long fixedDateMonth1 = transitionYear ?
1662                 getFixedDateMonth1(jdate, fixedDate) : fixedDate - dayOfMonth + 1;
1663 
1664             internalSet(DAY_OF_YEAR, dayOfYear);
1665             internalSet(DAY_OF_WEEK_IN_MONTH, (dayOfMonth - 1) / 7 + 1);
1666 
1667             int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
1668 
1669             // The spec is to calculate WEEK_OF_YEAR in the
1670             // ISO8601-style. This creates problems, though.
1671             if (weekOfYear == 0) {
1672                 // If the date belongs to the last week of the
1673                 // previous year, use the week number of "12/31" of
1674                 // the "previous" year. Again, if the previous year is
1675                 // a transition year, we need to take care of it.
1676                 // Usually the previous day of the first day of a year
1677                 // is December 31, which is not always true in the
1678                 // Japanese imperial calendar system.
1679                 long fixedDec31 = fixedDateJan1 - 1;
1680                 long prevJan1;
1681                 LocalGregorianCalendar.Date d = getCalendarDate(fixedDec31);
1682                 if (!(transitionYear || isTransitionYear(d.getNormalizedYear()))) {
1683                     prevJan1 = fixedDateJan1 - 365;
1684                     if (d.isLeapYear()) {
1685                         --prevJan1;
1686                     }
1687                 } else if (transitionYear) {
1688                     if (jdate.getYear() == 1) {
1689                         // As of Heisei (since Meiji) there's no case
1690                         // that there are multiple transitions in a
1691                         // year.  Historically there was such
1692                         // case. There might be such case again in the
1693                         // future.
1694                         if (era > HEISEI) {
1695                             CalendarDate pd = eras[era - 1].getSinceDate();
1696                             if (normalizedYear == pd.getYear()) {
1697                                 d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
1698                             }
1699                         } else {
1700                             d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
1701                         }
1702                         jcal.normalize(d);
1703                         prevJan1 = jcal.getFixedDate(d);
1704                     } else {
1705                         prevJan1 = fixedDateJan1 - 365;
1706                         if (d.isLeapYear()) {
1707                             --prevJan1;
1708                         }
1709                     }
1710                 } else {
1711                     CalendarDate cd = eras[getEraIndex(jdate)].getSinceDate();
1712                     d.setMonth(cd.getMonth()).setDayOfMonth(cd.getDayOfMonth());
1713                     jcal.normalize(d);
1714                     prevJan1 = jcal.getFixedDate(d);
1715                 }
1716                 weekOfYear = getWeekNumber(prevJan1, fixedDec31);
1717             } else {
1718                 if (!transitionYear) {
1719                     // Regular years
1720                     if (weekOfYear >= 52) {
1721                         long nextJan1 = fixedDateJan1 + 365;
1722                         if (jdate.isLeapYear()) {
1723                             nextJan1++;
1724                         }
1725                         long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
1726                                                                                             getFirstDayOfWeek());
1727                         int ndays = (int)(nextJan1st - nextJan1);
1728                         if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
1729                             // The first days forms a week in which the date is included.
1730                             weekOfYear = 1;
1731                         }
1732                     }
1733                 } else {
1734                     LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
1735                     long nextJan1;
1736                     if (jdate.getYear() == 1) {
1737                         d.addYear(+1);
1738                         d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
1739                         nextJan1 = jcal.getFixedDate(d);
1740                     } else {
1741                         int nextEraIndex = getEraIndex(d) + 1;
1742                         CalendarDate cd = eras[nextEraIndex].getSinceDate();
1743                         d.setEra(eras[nextEraIndex]);
1744                         d.setDate(1, cd.getMonth(), cd.getDayOfMonth());
1745                         jcal.normalize(d);
1746                         nextJan1 = jcal.getFixedDate(d);
1747                     }
1748                     long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
1749                                                                                         getFirstDayOfWeek());
1750                     int ndays = (int)(nextJan1st - nextJan1);
1751                     if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
1752                         // The first days forms a week in which the date is included.
1753                         weekOfYear = 1;
1754                     }
1755                 }
1756             }
1757             internalSet(WEEK_OF_YEAR, weekOfYear);
1758             internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
1759             mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
1760         }
1761         return mask;
1762     }
1763 
1764     /**
1765      * Returns the number of weeks in a period between fixedDay1 and
1766      * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
1767      * is applied to calculate the number of weeks.
1768      *
1769      * @param fixedDay1 the fixed date of the first day of the period
1770      * @param fixedDate the fixed date of the last day of the period
1771      * @return the number of weeks of the given period
1772      */
1773     private int getWeekNumber(long fixedDay1, long fixedDate) {
1774         // We can always use `jcal' since Julian and Gregorian are the
1775         // same thing for this calculation.
1776         long fixedDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
1777                                                                              getFirstDayOfWeek());
1778         int ndays = (int)(fixedDay1st - fixedDay1);
1779         assert ndays <= 7;
1780         if (ndays >= getMinimalDaysInFirstWeek()) {
1781             fixedDay1st -= 7;
1782         }
1783         int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
1784         if (normalizedDayOfPeriod >= 0) {
1785             return normalizedDayOfPeriod / 7 + 1;
1786         }
1787         return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
1788     }
1789 
1790     /**
1791      * Converts calendar field values to the time value (millisecond
1792      * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
1793      *
1794      * @exception IllegalArgumentException if any calendar fields are invalid.
1795      */
1796     protected void computeTime() {
1797         // In non-lenient mode, perform brief checking of calendar
1798         // fields which have been set externally. Through this
1799         // checking, the field values are stored in originalFields[]
1800         // to see if any of them are normalized later.
1801         if (!isLenient()) {
1802             if (originalFields == null) {
1803                 originalFields = new int[FIELD_COUNT];
1804             }
1805             for (int field = 0; field < FIELD_COUNT; field++) {
1806                 int value = internalGet(field);
1807                 if (isExternallySet(field)) {
1808                     // Quick validation for any out of range values
1809                     if (value < getMinimum(field) || value > getMaximum(field)) {
1810                         throw new IllegalArgumentException(getFieldName(field));
1811                     }
1812                 }
1813                 originalFields[field] = value;
1814             }
1815         }
1816 
1817         // Let the super class determine which calendar fields to be
1818         // used to calculate the time.
1819         int fieldMask = selectFields();
1820 
1821         int year;
1822         int era;
1823 
1824         if (isSet(ERA)) {
1825             era = internalGet(ERA);
1826             year = isSet(YEAR) ? internalGet(YEAR) : 1;
1827         } else {
1828             if (isSet(YEAR)) {
1829                 era = eras.length - 1;
1830                 year = internalGet(YEAR);
1831             } else {
1832                 // Equivalent to 1970 (Gregorian)
1833                 era = SHOWA;
1834                 year = 45;
1835             }
1836         }
1837 
1838         // Calculate the time of day. We rely on the convention that
1839         // an UNSET field has 0.
1840         long timeOfDay = 0;
1841         if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
1842             timeOfDay += (long) internalGet(HOUR_OF_DAY);
1843         } else {
1844             timeOfDay += internalGet(HOUR);
1845             // The default value of AM_PM is 0 which designates AM.
1846             if (isFieldSet(fieldMask, AM_PM)) {
1847                 timeOfDay += 12 * internalGet(AM_PM);
1848             }
1849         }
1850         timeOfDay *= 60;
1851         timeOfDay += internalGet(MINUTE);
1852         timeOfDay *= 60;
1853         timeOfDay += internalGet(SECOND);
1854         timeOfDay *= 1000;
1855         timeOfDay += internalGet(MILLISECOND);
1856 
1857         // Convert the time of day to the number of days and the
1858         // millisecond offset from midnight.
1859         long fixedDate = timeOfDay / ONE_DAY;
1860         timeOfDay %= ONE_DAY;
1861         while (timeOfDay < 0) {
1862             timeOfDay += ONE_DAY;
1863             --fixedDate;
1864         }
1865 
1866         // Calculate the fixed date since January 1, 1 (Gregorian).
1867         fixedDate += getFixedDate(era, year, fieldMask);
1868 
1869         // millis represents local wall-clock time in milliseconds.
1870         long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
1871 
1872         // Compute the time zone offset and DST offset.  There are two potential
1873         // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
1874         // for discussion purposes here.
1875         // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
1876         //    can be in standard or in DST depending.  However, 2:00 am is an invalid
1877         //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
1878         //    We assume standard time.
1879         // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
1880         //    can be in standard or DST.  Both are valid representations (the rep
1881         //    jumps from 1:59:59 DST to 1:00:00 Std).
1882         //    Again, we assume standard time.
1883         // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
1884         // or DST_OFFSET fields; then we use those fields.
1885         TimeZone zone = getZone();
1886         if (zoneOffsets == null) {
1887             zoneOffsets = new int[2];
1888         }
1889         int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
1890         if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
1891             if (zone instanceof ZoneInfo) {
1892                 ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
1893             } else {
1894                 zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
1895             }
1896         }
1897         if (tzMask != 0) {
1898             if (isFieldSet(tzMask, ZONE_OFFSET)) {
1899                 zoneOffsets[0] = internalGet(ZONE_OFFSET);
1900             }
1901             if (isFieldSet(tzMask, DST_OFFSET)) {
1902                 zoneOffsets[1] = internalGet(DST_OFFSET);
1903             }
1904         }
1905 
1906         // Adjust the time zone offset values to get the UTC time.
1907         millis -= zoneOffsets[0] + zoneOffsets[1];
1908 
1909         // Set this calendar's time in milliseconds
1910         time = millis;
1911 
1912         int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
1913 
1914         if (!isLenient()) {
1915             for (int field = 0; field < FIELD_COUNT; field++) {
1916                 if (!isExternallySet(field)) {
1917                     continue;
1918                 }
1919                 if (originalFields[field] != internalGet(field)) {
1920                     int wrongValue = internalGet(field);
1921                     // Restore the original field values
1922                     System.arraycopy(originalFields, 0, fields, 0, fields.length);
1923                     throw new IllegalArgumentException(getFieldName(field) + "=" + wrongValue
1924                                                        + ", expected " + originalFields[field]);
1925                 }
1926             }
1927         }
1928         setFieldsNormalized(mask);
1929     }
1930 
1931     /**
1932      * Computes the fixed date under either the Gregorian or the
1933      * Julian calendar, using the given year and the specified calendar fields.
1934      *
1935      * @param era era index
1936      * @param year the normalized year number, with 0 indicating the
1937      * year 1 BCE, -1 indicating 2 BCE, etc.
1938      * @param fieldMask the calendar fields to be used for the date calculation
1939      * @return the fixed date
1940      * @see Calendar#selectFields
1941      */
1942     private long getFixedDate(int era, int year, int fieldMask) {
1943         int month = JANUARY;
1944         int firstDayOfMonth = 1;
1945         if (isFieldSet(fieldMask, MONTH)) {
1946             // No need to check if MONTH has been set (no isSet(MONTH)
1947             // call) since its unset value happens to be JANUARY (0).
1948             month = internalGet(MONTH);
1949 
1950             // If the month is out of range, adjust it into range.
1951             if (month > DECEMBER) {
1952                 year += month / 12;
1953                 month %= 12;
1954             } else if (month < JANUARY) {
1955                 int[] rem = new int[1];
1956                 year += CalendarUtils.floorDivide(month, 12, rem);
1957                 month = rem[0];
1958             }
1959         } else {
1960             if (year == 1 && era != 0) {
1961                 CalendarDate d = eras[era].getSinceDate();
1962                 month = d.getMonth() - 1;
1963                 firstDayOfMonth = d.getDayOfMonth();
1964             }
1965         }
1966 
1967         // Adjust the base date if year is the minimum value.
1968         if (year == MIN_VALUES[YEAR]) {
1969             CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
1970             int m = dx.getMonth() - 1;
1971             if (month < m) {
1972                 month = m;
1973             }
1974             if (month == m) {
1975                 firstDayOfMonth = dx.getDayOfMonth();
1976             }
1977         }
1978 
1979         LocalGregorianCalendar.Date date = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
1980         date.setEra(era > 0 ? eras[era] : null);
1981         date.setDate(year, month + 1, firstDayOfMonth);
1982         jcal.normalize(date);
1983 
1984         // Get the fixed date since Jan 1, 1 (Gregorian). We are on
1985         // the first day of either `month' or January in 'year'.
1986         long fixedDate = jcal.getFixedDate(date);
1987 
1988         if (isFieldSet(fieldMask, MONTH)) {
1989             // Month-based calculations
1990             if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
1991                 // We are on the "first day" of the month (which may
1992                 // not be 1). Just add the offset if DAY_OF_MONTH is
1993                 // set. If the isSet call returns false, that means
1994                 // DAY_OF_MONTH has been selected just because of the
1995                 // selected combination. We don't need to add any
1996                 // since the default value is the "first day".
1997                 if (isSet(DAY_OF_MONTH)) {
1998                     // To avoid underflow with DAY_OF_MONTH-firstDayOfMonth, add
1999                     // DAY_OF_MONTH, then subtract firstDayOfMonth.
2000                     fixedDate += internalGet(DAY_OF_MONTH);
2001                     fixedDate -= firstDayOfMonth;
2002                 }
2003             } else {
2004                 if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
2005                     long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2006                                                                                             getFirstDayOfWeek());
2007                     // If we have enough days in the first week, then
2008                     // move to the previous week.
2009                     if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2010                         firstDayOfWeek -= 7;
2011                     }
2012                     if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2013                         firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2014                                                                                            internalGet(DAY_OF_WEEK));
2015                     }
2016                     // In lenient mode, we treat days of the previous
2017                     // months as a part of the specified
2018                     // WEEK_OF_MONTH. See 4633646.
2019                     fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
2020                 } else {
2021                     int dayOfWeek;
2022                     if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2023                         dayOfWeek = internalGet(DAY_OF_WEEK);
2024                     } else {
2025                         dayOfWeek = getFirstDayOfWeek();
2026                     }
2027                     // We are basing this on the day-of-week-in-month.  The only
2028                     // trickiness occurs if the day-of-week-in-month is
2029                     // negative.
2030                     int dowim;
2031                     if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
2032                         dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
2033                     } else {
2034                         dowim = 1;
2035                     }
2036                     if (dowim >= 0) {
2037                         fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
2038                                                                                       dayOfWeek);
2039                     } else {
2040                         // Go to the first day of the next week of
2041                         // the specified week boundary.
2042                         int lastDate = monthLength(month, year) + (7 * (dowim + 1));
2043                         // Then, get the day of week date on or before the last date.
2044                         fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
2045                                                                                       dayOfWeek);
2046                     }
2047                 }
2048             }
2049         } else {
2050             // We are on the first day of the year.
2051             if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
2052                 if (isTransitionYear(date.getNormalizedYear())) {
2053                     fixedDate = getFixedDateJan1(date, fixedDate);
2054                 }
2055                 // Add the offset, then subtract 1. (Make sure to avoid underflow.)
2056                 fixedDate += internalGet(DAY_OF_YEAR);
2057                 fixedDate--;
2058             } else {
2059                 long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
2060                                                                                         getFirstDayOfWeek());
2061                 // If we have enough days in the first week, then move
2062                 // to the previous week.
2063                 if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
2064                     firstDayOfWeek -= 7;
2065                 }
2066                 if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
2067                     int dayOfWeek = internalGet(DAY_OF_WEEK);
2068                     if (dayOfWeek != getFirstDayOfWeek()) {
2069                         firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
2070                                                                                            dayOfWeek);
2071                     }
2072                 }
2073                 fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
2074             }
2075         }
2076         return fixedDate;
2077     }
2078 
2079     /**
2080      * Returns the fixed date of the first day of the year (usually
2081      * January 1) before the specified date.
2082      *
2083      * @param date the date for which the first day of the year is
2084      * calculated. The date has to be in the cut-over year.
2085      * @param fixedDate the fixed date representation of the date
2086      */
2087     private long getFixedDateJan1(LocalGregorianCalendar.Date date, long fixedDate) {
2088         Era era = date.getEra();
2089         if (date.getEra() != null && date.getYear() == 1) {
2090             for (int eraIndex = getEraIndex(date); eraIndex > 0; eraIndex--) {
2091                 CalendarDate d = eras[eraIndex].getSinceDate();
2092                 long fd = gcal.getFixedDate(d);
2093                 // There might be multiple era transitions in a year.
2094                 if (fd > fixedDate) {
2095                     continue;
2096                 }
2097                 return fd;
2098             }
2099         }
2100         CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
2101         d.setDate(date.getNormalizedYear(), Gregorian.JANUARY, 1);
2102         return gcal.getFixedDate(d);
2103     }
2104 
2105     /**
2106      * Returns the fixed date of the first date of the month (usually
2107      * the 1st of the month) before the specified date.
2108      *
2109      * @param date the date for which the first day of the month is
2110      * calculated. The date must be in the era transition year.
2111      * @param fixedDate the fixed date representation of the date
2112      */
2113     private long getFixedDateMonth1(LocalGregorianCalendar.Date date,
2114                                           long fixedDate) {
2115         int eraIndex = getTransitionEraIndex(date);
2116         if (eraIndex != -1) {
2117             long transition = sinceFixedDates[eraIndex];
2118             // If the given date is on or after the transition date, then
2119             // return the transition date.
2120             if (transition <= fixedDate) {
2121                 return transition;
2122             }
2123         }
2124 
2125         // Otherwise, we can use the 1st day of the month.
2126         return fixedDate - date.getDayOfMonth() + 1;
2127     }
2128 
2129     /**
2130      * Returns a LocalGregorianCalendar.Date produced from the specified fixed date.
2131      *
2132      * @param fd the fixed date
2133      */
2134     private static LocalGregorianCalendar.Date getCalendarDate(long fd) {
2135         LocalGregorianCalendar.Date d = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
2136         jcal.getCalendarDateFromFixedDate(d, fd);
2137         return d;
2138     }
2139 
2140     /**
2141      * Returns the length of the specified month in the specified
2142      * Gregorian year. The year number must be normalized.
2143      *
2144      * @see GregorianCalendar#isLeapYear(int)
2145      */
2146     private int monthLength(int month, int gregorianYear) {
2147         return CalendarUtils.isGregorianLeapYear(gregorianYear) ?
2148             GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
2149     }
2150 
2151     /**
2152      * Returns the length of the specified month in the year provided
2153      * by internalGet(YEAR).
2154      *
2155      * @see GregorianCalendar#isLeapYear(int)
2156      */
2157     private int monthLength(int month) {
2158         assert jdate.isNormalized();
2159         return jdate.isLeapYear() ?
2160             GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
2161     }
2162 
2163     private int actualMonthLength() {
2164         int length = jcal.getMonthLength(jdate);
2165         int eraIndex = getTransitionEraIndex(jdate);
2166         if (eraIndex == -1) {
2167             long transitionFixedDate = sinceFixedDates[eraIndex];
2168             CalendarDate d = eras[eraIndex].getSinceDate();
2169             if (transitionFixedDate <= cachedFixedDate) {
2170                 length -= d.getDayOfMonth() - 1;
2171             } else {
2172                 length = d.getDayOfMonth() - 1;
2173             }
2174         }
2175         return length;
2176     }
2177 
2178     /**
2179      * Returns the index to the new era if the given date is in a
2180      * transition month.  For example, if the give date is Heisei 1
2181      * (1989) January 20, then the era index for Heisei is
2182      * returned. Likewise, if the given date is Showa 64 (1989)
2183      * January 3, then the era index for Heisei is returned. If the
2184      * given date is not in any transition month, then -1 is returned.
2185      */
2186     private static int getTransitionEraIndex(LocalGregorianCalendar.Date date) {
2187         int eraIndex = getEraIndex(date);
2188         CalendarDate transitionDate = eras[eraIndex].getSinceDate();
2189         if (transitionDate.getYear() == date.getNormalizedYear() &&
2190             transitionDate.getMonth() == date.getMonth()) {
2191             return eraIndex;
2192         }
2193         if (eraIndex < eras.length - 1) {
2194             transitionDate = eras[++eraIndex].getSinceDate();
2195             if (transitionDate.getYear() == date.getNormalizedYear() &&
2196                 transitionDate.getMonth() == date.getMonth()) {
2197                 return eraIndex;
2198             }
2199         }
2200         return -1;
2201     }
2202 
2203     private boolean isTransitionYear(int normalizedYear) {
2204         for (int i = eras.length - 1; i > 0; i--) {
2205             int transitionYear = eras[i].getSinceDate().getYear();
2206             if (normalizedYear == transitionYear) {
2207                 return true;
2208             }
2209             if (normalizedYear > transitionYear) {
2210                 break;
2211             }
2212         }
2213         return false;
2214     }
2215 
2216     private static int getEraIndex(LocalGregorianCalendar.Date date) {
2217         Era era = date.getEra();
2218         for (int i = eras.length - 1; i > 0; i--) {
2219             if (eras[i] == era) {
2220                 return i;
2221             }
2222         }
2223         return 0;
2224     }
2225 
2226     /**
2227      * Returns this object if it's normalized (all fields and time are
2228      * in sync). Otherwise, a cloned object is returned after calling
2229      * complete() in lenient mode.
2230      */
2231     private JapaneseImperialCalendar getNormalizedCalendar() {
2232         JapaneseImperialCalendar jc;
2233         if (isFullyNormalized()) {
2234             jc = this;
2235         } else {
2236             // Create a clone and normalize the calendar fields
2237             jc = (JapaneseImperialCalendar) this.clone();
2238             jc.setLenient(true);
2239             jc.complete();
2240         }
2241         return jc;
2242     }
2243 
2244     /**
2245      * After adjustments such as add(MONTH), add(YEAR), we don't want the
2246      * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
2247      * 3, we want it to go to Feb 28.  Adjustments which might run into this
2248      * problem call this method to retain the proper month.
2249      */
2250     private void pinDayOfMonth(LocalGregorianCalendar.Date date) {
2251         int year = date.getYear();
2252         int dom = date.getDayOfMonth();
2253         if (year != getMinimum(YEAR)) {
2254             date.setDayOfMonth(1);
2255             jcal.normalize(date);
2256             int monthLength = jcal.getMonthLength(date);
2257             if (dom > monthLength) {
2258                 date.setDayOfMonth(monthLength);
2259             } else {
2260                 date.setDayOfMonth(dom);
2261             }
2262             jcal.normalize(date);
2263         } else {
2264             LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
2265             LocalGregorianCalendar.Date realDate = jcal.getCalendarDate(time, getZone());
2266             long tod = realDate.getTimeOfDay();
2267             // Use an equivalent year.
2268             realDate.addYear(+400);
2269             realDate.setMonth(date.getMonth());
2270             realDate.setDayOfMonth(1);
2271             jcal.normalize(realDate);
2272             int monthLength = jcal.getMonthLength(realDate);
2273             if (dom > monthLength) {
2274                 realDate.setDayOfMonth(monthLength);
2275             } else {
2276                 if (dom < d.getDayOfMonth()) {
2277                     realDate.setDayOfMonth(d.getDayOfMonth());
2278                 } else {
2279                     realDate.setDayOfMonth(dom);
2280                 }
2281             }
2282             if (realDate.getDayOfMonth() == d.getDayOfMonth() && tod < d.getTimeOfDay()) {
2283                 realDate.setDayOfMonth(Math.min(dom + 1, monthLength));
2284             }
2285             // restore the year.
2286             date.setDate(year, realDate.getMonth(), realDate.getDayOfMonth());
2287             // Don't normalize date here so as not to cause underflow.
2288         }
2289     }
2290 
2291     /**
2292      * Returns the new value after 'roll'ing the specified value and amount.
2293      */
2294     private static int getRolledValue(int value, int amount, int min, int max) {
2295         assert value >= min && value <= max;
2296         int range = max - min + 1;
2297         amount %= range;
2298         int n = value + amount;
2299         if (n > max) {
2300             n -= range;
2301         } else if (n < min) {
2302             n += range;
2303         }
2304         assert n >= min && n <= max;
2305         return n;
2306     }
2307 
2308     /**
2309      * Returns the ERA.  We need a special method for this because the
2310      * default ERA is the current era, but a zero (unset) ERA means before Meiji.
2311      */
2312     private int internalGetEra() {
2313         return isSet(ERA) ? internalGet(ERA) : eras.length - 1;
2314     }
2315 
2316     /**
2317      * Updates internal state.
2318      */
2319     private void readObject(ObjectInputStream stream)
2320             throws IOException, ClassNotFoundException {
2321         stream.defaultReadObject();
2322         if (jdate == null) {
2323             jdate = jcal.newCalendarDate(getZone());
2324             cachedFixedDate = Long.MIN_VALUE;
2325         }
2326     }
2327 }