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