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