src/share/classes/java/util/JapaneseImperialCalendar.java

Print this page


   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 import sun.util.calendar.ZoneInfo;
  39 
  40 /**
  41  * <code>JapaneseImperialCalendar</code> implements a Japanese
  42  * calendar system in which the imperial era-based year numbering is
  43  * supported from the Meiji era. The following are the eras supported
  44  * by this calendar system.
  45  * <pre><tt>
  46  * ERA value   Era name    Since (in Gregorian)
  47  * ------------------------------------------------------
  48  *     0       N/A         N/A
  49  *     1       Meiji       1868-01-01 midnight local time
  50  *     2       Taisho      1912-07-30 midnight local time
  51  *     3       Showa       1926-12-25 midnight local time
  52  *     4       Heisei      1989-01-08 midnight local time
  53  * ------------------------------------------------------
  54  * </tt></pre>
  55  *
  56  * <p><code>ERA</code> value 0 specifies the years before Meiji and
  57  * the Gregorian year values are used. Unlike {@link
  58  * GregorianCalendar}, the Julian to Gregorian transition is not
  59  * supported because it doesn't make any sense to the Japanese
  60  * calendar systems used before Meiji. To represent the years before
  61  * Gregorian year 1, 0 and negative values are used. The Japanese
  62  * Imperial rescripts and government decrees don't specify how to deal
  63  * with time differences for applying the era transitions. This
  64  * calendar implementation assumes local time for all transitions.
  65  *

























  66  * @author Masayoshi Okutsu
  67  * @since 1.6
  68  */
  69 class JapaneseImperialCalendar extends Calendar {
  70     /*
  71      * Implementation Notes
  72      *
  73      * This implementation uses
  74      * sun.util.calendar.LocalGregorianCalendar to perform most of the
  75      * calendar calculations. LocalGregorianCalendar is configurable
  76      * and reads <JRE_HOME>/lib/calendars.properties at the start-up.
  77      */
  78 
  79     /**
  80      * The ERA constant designating the era before Meiji.
  81      */
  82     public static final int BEFORE_MEIJI = 0;
  83 
  84     /**
  85      * The ERA constant designating the Meiji era.
  86      */
  87     public static final int MEIJI = 1;
  88 
  89     /**
  90      * The ERA constant designating the Taisho era.
  91      */
  92     public static final int TAISHO = 2;
  93 
  94     /**
  95      * The ERA constant designating the Showa era.
  96      */
  97     public static final int SHOWA = 3;
  98 
  99     /**
 100      * The ERA constant designating the Heisei era.
 101      */
 102     public static final int HEISEI = 4;
 103 
 104     private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
 105     private static final int EPOCH_YEAR     = 1970;
 106 
 107     // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
 108     // into ints, they must be longs in order to prevent arithmetic overflow
 109     // when performing (bug 4173516).
 110     private static final int  ONE_SECOND = 1000;
 111     private static final int  ONE_MINUTE = 60*ONE_SECOND;
 112     private static final int  ONE_HOUR   = 60*ONE_MINUTE;
 113     private static final long ONE_DAY    = 24*ONE_HOUR;
 114     private static final long ONE_WEEK   = 7*ONE_DAY;
 115 
 116     // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
 117     private static final LocalGregorianCalendar jcal
 118         = (LocalGregorianCalendar) CalendarSystem.forName("japanese");
 119 
 120     // Gregorian calendar instance. This is required because era
 121     // transition dates are given in Gregorian dates.
 122     private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
 123 
 124     // The Era instance representing "before Meiji".
 125     private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false);
 126 
 127     // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
 128     // doesn't have an Era representing before Meiji, which is
 129     // inconvenient for a Calendar. So, era[0] is a reference to
 130     // BEFORE_MEIJI_ERA.
 131     private static final Era[] eras;
 132 
 133     // Fixed date of the first date of each era.
 134     private static final long[] sinceFixedDates;


 200         0,              // ERA
 201         292278994,      // YEAR
 202         DECEMBER,       // MONTH
 203         53,             // WEEK_OF_YEAR
 204         6,              // WEEK_OF_MONTH
 205         31,             // DAY_OF_MONTH
 206         366,            // DAY_OF_YEAR
 207         SATURDAY,       // DAY_OF_WEEK
 208         6,              // DAY_OF_WEEK_IN
 209         PM,             // AM_PM
 210         11,             // HOUR
 211         23,             // HOUR_OF_DAY
 212         59,             // MINUTE
 213         59,             // SECOND
 214         999,            // MILLISECOND
 215         14*ONE_HOUR,    // ZONE_OFFSET
 216         2*ONE_HOUR      // DST_OFFSET (double summer time)
 217     };
 218 
 219     // Proclaim serialization compatibility with JDK 1.6

 220     private static final long serialVersionUID = -3364572813905467929L;
 221 
 222     static {
 223         Era[] es = jcal.getEras();
 224         int length = es.length + 1;
 225         eras = new Era[length];
 226         sinceFixedDates = new long[length];
 227 
 228         // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
 229         // same as Gregorian.
 230         int index = BEFORE_MEIJI;
 231         sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
 232         eras[index++] = BEFORE_MEIJI_ERA;
 233         for (Era e : es) {
 234             CalendarDate d = e.getSinceDate();
 235             sinceFixedDates[index] = gcal.getFixedDate(d);
 236             eras[index++] = e;
 237         }
 238 
 239         LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;


 323      * @return {@code "japanese"}
 324      */
 325     @Override
 326     public String getCalendarType() {
 327         return "japanese";
 328     }
 329 
 330     /**
 331      * Compares this <code>JapaneseImperialCalendar</code> to the specified
 332      * <code>Object</code>. The result is <code>true</code> if and
 333      * only if the argument is a <code>JapaneseImperialCalendar</code> object
 334      * that represents the same time value (millisecond offset from
 335      * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
 336      * <code>Calendar</code> parameters.
 337      *
 338      * @param obj the object to compare with.
 339      * @return <code>true</code> if this object is equal to <code>obj</code>;
 340      * <code>false</code> otherwise.
 341      * @see Calendar#compareTo(Calendar)
 342      */

 343     public boolean equals(Object obj) {
 344         return obj instanceof JapaneseImperialCalendar &&
 345             super.equals(obj);
 346     }
 347 
 348     /**
 349      * Generates the hash code for this
 350      * <code>JapaneseImperialCalendar</code> object.
 351      */

 352     public int hashCode() {
 353         return super.hashCode() ^ jdate.hashCode();
 354     }
 355 
 356     /**
 357      * Adds the specified (signed) amount of time to the given calendar field,
 358      * based on the calendar's rules.
 359      *
 360      * <p><em>Add rule 1</em>. The value of <code>field</code>
 361      * after the call minus the value of <code>field</code> before the
 362      * call is <code>amount</code>, modulo any overflow that has occurred in
 363      * <code>field</code>. Overflow occurs when a field value exceeds its
 364      * range and, as a result, the next larger field is incremented or
 365      * decremented and the field value is adjusted back into its range.</p>
 366      *
 367      * <p><em>Add rule 2</em>. If a smaller field is expected to be
 368      * invariant, but it is impossible for it to be equal to its
 369      * prior value because of changes in its minimum or maximum after
 370      * <code>field</code> is changed, then its value is adjusted to be as close
 371      * as possible to its expected value. A smaller field represents a
 372      * smaller unit of time. <code>HOUR</code> is a smaller field than
 373      * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
 374      * that are not expected to be invariant. The calendar system
 375      * determines what fields are expected to be invariant.</p>
 376      *
 377      * @param field the calendar field.
 378      * @param amount the amount of date or time to be added to the field.
 379      * @exception IllegalArgumentException if <code>field</code> is
 380      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
 381      * or if any calendar fields have out-of-range values in
 382      * non-lenient mode.
 383      */

 384     public void add(int field, int amount) {
 385         // If amount == 0, do nothing even the given field is out of
 386         // range. This is tested by JCK.
 387         if (amount == 0) {
 388             return;   // Do nothing!
 389         }
 390 
 391         if (field < 0 || field >= ZONE_OFFSET) {
 392             throw new IllegalArgumentException();
 393         }
 394 
 395         // Sync the time and calendar fields.
 396         complete();
 397 
 398         if (field == YEAR) {
 399             LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
 400             d.addYear(amount);
 401             pinDayOfMonth(d);
 402             set(ERA, getEraIndex(d));
 403             set(YEAR, d.getYear());


 492                 timeOfDay += ONE_DAY;
 493             }
 494 
 495             fd += delta; // fd is the expected fixed date after the calculation
 496             int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
 497             setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
 498             zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
 499             // If the time zone offset has changed, then adjust the difference.
 500             if (zoneOffset != 0) {
 501                 setTimeInMillis(time + zoneOffset);
 502                 long fd2 = cachedFixedDate;
 503                 // If the adjustment has changed the date, then take
 504                 // the previous one.
 505                 if (fd2 != fd) {
 506                     setTimeInMillis(time - zoneOffset);
 507                 }
 508             }
 509         }
 510     }
 511 

 512     public void roll(int field, boolean up) {
 513         roll(field, up ? +1 : -1);
 514     }
 515 
 516     /**
 517      * Adds a signed amount to the specified calendar field without changing larger fields.
 518      * A negative roll amount means to subtract from field without changing
 519      * larger fields. If the specified amount is 0, this method performs nothing.
 520      *
 521      * <p>This method calls {@link #complete()} before adding the
 522      * amount so that all the calendar fields are normalized. If there
 523      * is any calendar field having an out-of-range value in non-lenient mode, then an
 524      * <code>IllegalArgumentException</code> is thrown.
 525      *
 526      * @param field the calendar field.
 527      * @param amount the signed amount to add to <code>field</code>.
 528      * @exception IllegalArgumentException if <code>field</code> is
 529      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
 530      * or if any calendar fields have out-of-range values in
 531      * non-lenient mode.
 532      * @see #roll(int,boolean)
 533      * @see #add(int,int)
 534      * @see #set(int,int)
 535      */

 536     public void roll(int field, int amount) {
 537         // If amount == 0, do nothing even the given field is out of
 538         // range. This is tested by JCK.
 539         if (amount == 0) {
 540             return;
 541         }
 542 
 543         if (field < 0 || field >= ZONE_OFFSET) {
 544             throw new IllegalArgumentException();
 545         }
 546 
 547         // Sync the time and calendar fields.
 548         complete();
 549 
 550         int min = getMinimum(field);
 551         int max = getMaximum(field);
 552 
 553         switch (field) {
 554         case ERA:
 555         case AM_PM:


   1 /*
   2  * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.IOException;
  29 import java.io.ObjectInputStream;
  30 import sun.util.locale.provider.CalendarDataUtility;
  31 import sun.util.calendar.BaseCalendar;
  32 import sun.util.calendar.CalendarDate;
  33 import sun.util.calendar.CalendarSystem;
  34 import sun.util.calendar.CalendarUtils;
  35 import sun.util.calendar.Era;
  36 import sun.util.calendar.Gregorian;
  37 import sun.util.calendar.LocalGregorianCalendar;
  38 import sun.util.calendar.ZoneInfo;
  39 
  40 /**
  41  * {@code JapaneseImperialCalendar} implements a Japanese
  42  * calendar system in which the imperial era-based year numbering is
  43  * supported from the Meiji era. The following are the eras supported
  44  * by this calendar system.
  45  * <pre><code>
  46  * ERA value   Era name    Since (in Gregorian)
  47  * ------------------------------------------------------
  48  *     0       N/A         N/A
  49  *     1       Meiji       1868-01-01T00:00:00 local time
  50  *     2       Taisho      1912-07-30T00:00:00 local time
  51  *     3       Showa       1926-12-25T00:00:00 local time
  52  *     4       Heisei      1989-01-08T00:00:00 local time
  53  * ------------------------------------------------------
  54  * </code></pre>
  55  *
  56  * <p><code>ERA</code> value 0 specifies the years before Meiji and
  57  * the Gregorian year values are used. Unlike {@link
  58  * GregorianCalendar}, the Julian to Gregorian transition is not
  59  * supported because it doesn't make any sense to the Japanese
  60  * calendar systems used before Meiji. To represent the years before
  61  * Gregorian year 1, 0 and negative values are used. The Japanese
  62  * Imperial rescripts and government decrees don't specify how to deal
  63  * with time differences for applying the era transitions. This
  64  * calendar implementation assumes local time for all transitions.
  65  *
  66  * <p>A new era can be specified using property
  67  * jdk.calendar.japanese.supplemental.era. The new era is added to the
  68  * predefined eras. The syntax of the property is as follows.
  69  * <p><pre>
  70  *   {@code name=<name>,abbr=<abbr>,since=<time['u']>}
  71  * </pre>
  72  * where
  73  * <dl>
  74  * <dt>{@code <name>:}<dd>the full name of the new era (non-ASCII characters allowed)
  75  * <dt>{@code <abbr>:}<dd>the abbreviation of the new era (non-ASCII characters allowed)
  76  * <dt>{@code <time['u']>:}<dd>the start time of the new era represented by
  77  * milliseconds from 1970-01-01T00:00:00 local time or UTC if {@code 'u'} is
  78  * appended to the milliseconds value. (ASCII digits only)
  79  * </dl>
  80  *
  81  * <p>If the given era is invalid, such as the since value before the
  82  * beginning of the last predefined era, the given era will be
  83  * ignored.
  84  *
  85  * <p>The following is an example of the property usage.
  86  * <p><pre>
  87  *   java -Djdk.calendar.japanese.supplemental.era="name=NewEra,abbr=N,since=253374307200000"
  88  * </pre>
  89  * The property specifies an era change to NewEra at 9999-02-11T00:00:00 local time.
  90  *
  91  * @author Masayoshi Okutsu
  92  * @since 1.6
  93  */
  94 class JapaneseImperialCalendar extends Calendar {
  95     /*
  96      * Implementation Notes
  97      *
  98      * This implementation uses
  99      * sun.util.calendar.LocalGregorianCalendar to perform most of the
 100      * calendar calculations. LocalGregorianCalendar is configurable
 101      * and reads <JRE_HOME>/lib/calendars.properties at the start-up.
 102      */
 103 
 104     /**
 105      * The ERA constant designating the era before Meiji.
 106      */
 107     public static final int BEFORE_MEIJI = 0;
 108 
 109     /**
 110      * The ERA constant designating the Meiji era.
 111      */
 112     public static final int MEIJI = 1;
 113 
 114     /**
 115      * The ERA constant designating the Taisho era.
 116      */
 117     public static final int TAISHO = 2;
 118 
 119     /**
 120      * The ERA constant designating the Showa era.
 121      */
 122     public static final int SHOWA = 3;
 123 
 124     /**
 125      * The ERA constant designating the Heisei era.
 126      */
 127     public static final int HEISEI = 4;
 128 
 129     private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)

 130 
 131     // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
 132     // into ints, they must be longs in order to prevent arithmetic overflow
 133     // when performing (bug 4173516).
 134     private static final int  ONE_SECOND = 1000;
 135     private static final int  ONE_MINUTE = 60*ONE_SECOND;
 136     private static final int  ONE_HOUR   = 60*ONE_MINUTE;
 137     private static final long ONE_DAY    = 24*ONE_HOUR;

 138 
 139     // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
 140     private static final LocalGregorianCalendar jcal
 141         = (LocalGregorianCalendar) CalendarSystem.forName("japanese");
 142 
 143     // Gregorian calendar instance. This is required because era
 144     // transition dates are given in Gregorian dates.
 145     private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
 146 
 147     // The Era instance representing "before Meiji".
 148     private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false);
 149 
 150     // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
 151     // doesn't have an Era representing before Meiji, which is
 152     // inconvenient for a Calendar. So, era[0] is a reference to
 153     // BEFORE_MEIJI_ERA.
 154     private static final Era[] eras;
 155 
 156     // Fixed date of the first date of each era.
 157     private static final long[] sinceFixedDates;


 223         0,              // ERA
 224         292278994,      // YEAR
 225         DECEMBER,       // MONTH
 226         53,             // WEEK_OF_YEAR
 227         6,              // WEEK_OF_MONTH
 228         31,             // DAY_OF_MONTH
 229         366,            // DAY_OF_YEAR
 230         SATURDAY,       // DAY_OF_WEEK
 231         6,              // DAY_OF_WEEK_IN
 232         PM,             // AM_PM
 233         11,             // HOUR
 234         23,             // HOUR_OF_DAY
 235         59,             // MINUTE
 236         59,             // SECOND
 237         999,            // MILLISECOND
 238         14*ONE_HOUR,    // ZONE_OFFSET
 239         2*ONE_HOUR      // DST_OFFSET (double summer time)
 240     };
 241 
 242     // Proclaim serialization compatibility with JDK 1.6
 243     @SuppressWarnings("FieldNameHidesFieldInSuperclass")
 244     private static final long serialVersionUID = -3364572813905467929L;
 245 
 246     static {
 247         Era[] es = jcal.getEras();
 248         int length = es.length + 1;
 249         eras = new Era[length];
 250         sinceFixedDates = new long[length];
 251 
 252         // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
 253         // same as Gregorian.
 254         int index = BEFORE_MEIJI;
 255         sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
 256         eras[index++] = BEFORE_MEIJI_ERA;
 257         for (Era e : es) {
 258             CalendarDate d = e.getSinceDate();
 259             sinceFixedDates[index] = gcal.getFixedDate(d);
 260             eras[index++] = e;
 261         }
 262 
 263         LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;


 347      * @return {@code "japanese"}
 348      */
 349     @Override
 350     public String getCalendarType() {
 351         return "japanese";
 352     }
 353 
 354     /**
 355      * Compares this <code>JapaneseImperialCalendar</code> to the specified
 356      * <code>Object</code>. The result is <code>true</code> if and
 357      * only if the argument is a <code>JapaneseImperialCalendar</code> object
 358      * that represents the same time value (millisecond offset from
 359      * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
 360      * <code>Calendar</code> parameters.
 361      *
 362      * @param obj the object to compare with.
 363      * @return <code>true</code> if this object is equal to <code>obj</code>;
 364      * <code>false</code> otherwise.
 365      * @see Calendar#compareTo(Calendar)
 366      */
 367     @Override
 368     public boolean equals(Object obj) {
 369         return obj instanceof JapaneseImperialCalendar &&
 370             super.equals(obj);
 371     }
 372 
 373     /**
 374      * Generates the hash code for this
 375      * <code>JapaneseImperialCalendar</code> object.
 376      */
 377     @Override
 378     public int hashCode() {
 379         return super.hashCode() ^ jdate.hashCode();
 380     }
 381 
 382     /**
 383      * Adds the specified (signed) amount of time to the given calendar field,
 384      * based on the calendar's rules.
 385      *
 386      * <p><em>Add rule 1</em>. The value of <code>field</code>
 387      * after the call minus the value of <code>field</code> before the
 388      * call is <code>amount</code>, modulo any overflow that has occurred in
 389      * <code>field</code>. Overflow occurs when a field value exceeds its
 390      * range and, as a result, the next larger field is incremented or
 391      * decremented and the field value is adjusted back into its range.</p>
 392      *
 393      * <p><em>Add rule 2</em>. If a smaller field is expected to be
 394      * invariant, but it is impossible for it to be equal to its
 395      * prior value because of changes in its minimum or maximum after
 396      * <code>field</code> is changed, then its value is adjusted to be as close
 397      * as possible to its expected value. A smaller field represents a
 398      * smaller unit of time. <code>HOUR</code> is a smaller field than
 399      * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
 400      * that are not expected to be invariant. The calendar system
 401      * determines what fields are expected to be invariant.</p>
 402      *
 403      * @param field the calendar field.
 404      * @param amount the amount of date or time to be added to the field.
 405      * @exception IllegalArgumentException if <code>field</code> is
 406      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
 407      * or if any calendar fields have out-of-range values in
 408      * non-lenient mode.
 409      */
 410     @Override
 411     public void add(int field, int amount) {
 412         // If amount == 0, do nothing even the given field is out of
 413         // range. This is tested by JCK.
 414         if (amount == 0) {
 415             return;   // Do nothing!
 416         }
 417 
 418         if (field < 0 || field >= ZONE_OFFSET) {
 419             throw new IllegalArgumentException();
 420         }
 421 
 422         // Sync the time and calendar fields.
 423         complete();
 424 
 425         if (field == YEAR) {
 426             LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
 427             d.addYear(amount);
 428             pinDayOfMonth(d);
 429             set(ERA, getEraIndex(d));
 430             set(YEAR, d.getYear());


 519                 timeOfDay += ONE_DAY;
 520             }
 521 
 522             fd += delta; // fd is the expected fixed date after the calculation
 523             int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
 524             setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
 525             zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
 526             // If the time zone offset has changed, then adjust the difference.
 527             if (zoneOffset != 0) {
 528                 setTimeInMillis(time + zoneOffset);
 529                 long fd2 = cachedFixedDate;
 530                 // If the adjustment has changed the date, then take
 531                 // the previous one.
 532                 if (fd2 != fd) {
 533                     setTimeInMillis(time - zoneOffset);
 534                 }
 535             }
 536         }
 537     }
 538 
 539     @Override
 540     public void roll(int field, boolean up) {
 541         roll(field, up ? +1 : -1);
 542     }
 543 
 544     /**
 545      * Adds a signed amount to the specified calendar field without changing larger fields.
 546      * A negative roll amount means to subtract from field without changing
 547      * larger fields. If the specified amount is 0, this method performs nothing.
 548      *
 549      * <p>This method calls {@link #complete()} before adding the
 550      * amount so that all the calendar fields are normalized. If there
 551      * is any calendar field having an out-of-range value in non-lenient mode, then an
 552      * <code>IllegalArgumentException</code> is thrown.
 553      *
 554      * @param field the calendar field.
 555      * @param amount the signed amount to add to <code>field</code>.
 556      * @exception IllegalArgumentException if <code>field</code> is
 557      * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
 558      * or if any calendar fields have out-of-range values in
 559      * non-lenient mode.
 560      * @see #roll(int,boolean)
 561      * @see #add(int,int)
 562      * @see #set(int,int)
 563      */
 564     @Override
 565     public void roll(int field, int amount) {
 566         // If amount == 0, do nothing even the given field is out of
 567         // range. This is tested by JCK.
 568         if (amount == 0) {
 569             return;
 570         }
 571 
 572         if (field < 0 || field >= ZONE_OFFSET) {
 573             throw new IllegalArgumentException();
 574         }
 575 
 576         // Sync the time and calendar fields.
 577         complete();
 578 
 579         int min = getMinimum(field);
 580         int max = getMaximum(field);
 581 
 582         switch (field) {
 583         case ERA:
 584         case AM_PM: