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