/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util; import java.io.IOException;import java.io.ObjectInputStream;import sun.util.calendar.BaseCalendar;import sun.util.calendar.CalendarDate;import sun.util.calendar.CalendarSystem;import sun.util.calendar.CalendarUtils;import sun.util.calendar.Era;import sun.util.calendar.Gregorian;import sun.util.calendar.LocalGregorianCalendar;import sun.util.calendar.ZoneInfo;import sun.util.resources.LocaleData; /** * <code>JapaneseImperialCalendar</code> implements a Japanese * calendar system in which the imperial era-based year numbering is * supported from the Meiji era. The following are the eras supported * by this calendar system. * <pre><tt> * ERA value Era name Since (in Gregorian) * ------------------------------------------------------ * 0 N/A N/A * 1 Meiji 1868-01-01 midnight local time * 2 Taisho 1912-07-30 midnight local time * 3 Showa 1926-12-25 midnight local time * 4 Heisei 1989-01-08 midnight local time * ------------------------------------------------------ * </tt></pre> * * <p><code>ERA</code> value 0 specifies the years before Meiji and * the Gregorian year values are used. Unlike {@link * GregorianCalendar}, the Julian to Gregorian transition is not * supported because it doesn't make any sense to the Japanese * calendar systems used before Meiji. To represent the years before * Gregorian year 1, 0 and negative values are used. The Japanese * Imperial rescripts and government decrees don't specify how to deal * with time differences for applying the era transitions. This * calendar implementation assumes local time for all transitions. * * @author Masayoshi Okutsu * @since 1.6 */class JapaneseImperialCalendar extends Calendar { /* * Implementation Notes * * This implementation uses * sun.util.calendar.LocalGregorianCalendar to perform most of the * calendar calculations. LocalGregorianCalendar is configurable * and reads <JRE_HOME>/lib/calendars.properties at the start-up. */ /** * The ERA constant designating the era before Meiji. */ public static final int BEFORE_MEIJI = 0; /** * The ERA constant designating the Meiji era. */ public static final int MEIJI = 1; /** * The ERA constant designating the Taisho era. */ public static final int TAISHO = 2; /** * The ERA constant designating the Showa era. */ public static final int SHOWA = 3; /** * The ERA constant designating the Heisei era. */ public static final int HEISEI = 4; private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian) private static final int EPOCH_YEAR = 1970; // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit // into ints, they must be longs in order to prevent arithmetic overflow // when performing (bug 4173516). private static final int ONE_SECOND = 1000; private static final int ONE_MINUTE = 60*ONE_SECOND; private static final int ONE_HOUR = 60*ONE_MINUTE; private static final long ONE_DAY = 24*ONE_HOUR; private static final long ONE_WEEK = 7*ONE_DAY; // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton). private static final LocalGregorianCalendar jcal = (LocalGregorianCalendar) CalendarSystem.forName("japanese"); // Gregorian calendar instance. This is required because era // transition dates are given in Gregorian dates. private static final Gregorian gcal = CalendarSystem.getGregorianCalendar(); // The Era instance representing "before Meiji". private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false); // Imperial eras. The sun.util.calendar.LocalGregorianCalendar // doesn't have an Era representing before Meiji, which is // inconvenient for a Calendar. So, era[0] is a reference to // BEFORE_MEIJI_ERA. private static final Era[] eras; // Fixed date of the first date of each era. private static final long[] sinceFixedDates; /* * <pre> * Greatest Least * Field name Minimum Minimum Maximum Maximum * ---------- ------- ------- ------- ------- * ERA 0 0 1 1 * YEAR -292275055 1 ? ? * MONTH 0 0 11 11 * WEEK_OF_YEAR 1 1 52* 53 * WEEK_OF_MONTH 0 0 4* 6 * DAY_OF_MONTH 1 1 28* 31 * DAY_OF_YEAR 1 1 365* 366 * DAY_OF_WEEK 1 1 7 7 * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6 * AM_PM 0 0 1 1 * HOUR 0 0 11 11 * HOUR_OF_DAY 0 0 23 23 * MINUTE 0 0 59 59 * SECOND 0 0 59 59 * MILLISECOND 0 0 999 999 * ZONE_OFFSET -13:00 -13:00 14:00 14:00 * DST_OFFSET 0:00 0:00 0:20 2:00 * </pre> * *: depends on eras */ static final int MIN_VALUES[] = { 0, // ERA -292275055, // YEAR JANUARY, // MONTH 1, // WEEK_OF_YEAR 0, // WEEK_OF_MONTH 1, // DAY_OF_MONTH 1, // DAY_OF_YEAR SUNDAY, // DAY_OF_WEEK 1, // DAY_OF_WEEK_IN_MONTH AM, // AM_PM 0, // HOUR 0, // HOUR_OF_DAY 0, // MINUTE 0, // SECOND 0, // MILLISECOND -13*ONE_HOUR, // ZONE_OFFSET (UNIX compatibility) 0 // DST_OFFSET }; static final int LEAST_MAX_VALUES[] = { 0, // ERA (initialized later) 0, // YEAR (initialized later) JANUARY, // MONTH (Showa 64 ended in January.) 0, // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.) 4, // WEEK_OF_MONTH 28, // DAY_OF_MONTH 0, // DAY_OF_YEAR (initialized later) SATURDAY, // DAY_OF_WEEK 4, // DAY_OF_WEEK_IN PM, // AM_PM 11, // HOUR 23, // HOUR_OF_DAY 59, // MINUTE 59, // SECOND 999, // MILLISECOND 14*ONE_HOUR, // ZONE_OFFSET 20*ONE_MINUTE // DST_OFFSET (historical least maximum) }; static final int MAX_VALUES[] = { 0, // ERA 292278994, // YEAR DECEMBER, // MONTH 53, // WEEK_OF_YEAR 6, // WEEK_OF_MONTH 31, // DAY_OF_MONTH 366, // DAY_OF_YEAR SATURDAY, // DAY_OF_WEEK 6, // DAY_OF_WEEK_IN PM, // AM_PM 11, // HOUR 23, // HOUR_OF_DAY 59, // MINUTE 59, // SECOND 999, // MILLISECOND 14*ONE_HOUR, // ZONE_OFFSET 2*ONE_HOUR // DST_OFFSET (double summer time) }; // Proclaim serialization compatibility with JDK 1.6 private static final long serialVersionUID = -3364572813905467929L; static { Era[] es = jcal.getEras(); int length = es.length + 1; eras = new Era[length]; sinceFixedDates = new long[length]; // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the // same as Gregorian. int index = BEFORE_MEIJI; sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate()); eras[index++] = BEFORE_MEIJI_ERA; for (Era e : es) { CalendarDate d = e.getSinceDate(); sinceFixedDates[index] = gcal.getFixedDate(d); eras[index++] = e; } LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1; // Calculate the least maximum year and least day of Year // values. The following code assumes that there's at most one // era transition in a Gregorian year. int year = Integer.MAX_VALUE; int dayOfYear = Integer.MAX_VALUE; CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE); for (int i = 1; i < eras.length; i++) { long fd = sinceFixedDates[i]; CalendarDate transitionDate = eras[i].getSinceDate(); date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1); long fdd = gcal.getFixedDate(date); dayOfYear = Math.min((int)(fdd - fd), dayOfYear); date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31); fdd = gcal.getFixedDate(date) + 1; dayOfYear = Math.min((int)(fd - fdd), dayOfYear); LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1); int y = lgd.getYear(); // Unless the first year starts from January 1, the actual // max value could be one year short. For example, if it's // Showa 63 January 8, 63 is the actual max value since // Showa 64 January 8 doesn't exist. if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd.getDayOfMonth() == 1)) y--; year = Math.min(y, year); } LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value. LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear; } /** * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to * avoid overhead of creating it for each calculation. */ private transient LocalGregorianCalendar.Date jdate; /** * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets * the GMT offset value and zoneOffsets[1] gets the daylight saving * value. */ private transient int[] zoneOffsets; /** * Temporary storage for saving original fields[] values in * non-lenient mode. */ private transient int[] originalFields; /** * Constructs a <code>JapaneseImperialCalendar</code> based on the current time * in the given time zone with the given locale. * * @param zone the given time zone. * @param aLocale the given locale. */ public JapaneseImperialCalendar(TimeZone zone, Locale aLocale) { super(zone, aLocale); jdate = jcal.newCalendarDate(zone); setTimeInMillis(System.currentTimeMillis()); } /** * Compares this <code>JapaneseImperialCalendar</code> to the specified * <code>Object</code>. The result is <code>true</code> if and * only if the argument is a <code>JapaneseImperialCalendar</code> object * that represents the same time value (millisecond offset from * the <a href="Calendar.html#Epoch">Epoch</a>) under the same * <code>Calendar</code> parameters. * * @param obj the object to compare with. * @return <code>true</code> if this object is equal to <code>obj</code>; * <code>false</code> otherwise. * @see Calendar#compareTo(Calendar) */ public boolean equals(Object obj) { return obj instanceof JapaneseImperialCalendar && super.equals(obj); } /** * Generates the hash code for this * <code>JapaneseImperialCalendar</code> object. */ public int hashCode() { return super.hashCode() ^ jdate.hashCode(); } /** * Adds the specified (signed) amount of time to the given calendar field, * based on the calendar's rules. * * <p><em>Add rule 1</em>. The value of <code>field</code> * after the call minus the value of <code>field</code> before the * call is <code>amount</code>, modulo any overflow that has occurred in * <code>field</code>. Overflow occurs when a field value exceeds its * range and, as a result, the next larger field is incremented or * decremented and the field value is adjusted back into its range.</p> * * <p><em>Add rule 2</em>. If a smaller field is expected to be * invariant, but it is impossible for it to be equal to its * prior value because of changes in its minimum or maximum after * <code>field</code> is changed, then its value is adjusted to be as close * as possible to its expected value. A smaller field represents a * smaller unit of time. <code>HOUR</code> is a smaller field than * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields * that are not expected to be invariant. The calendar system * determines what fields are expected to be invariant.</p> * * @param field the calendar field. * @param amount the amount of date or time to be added to the field. * @exception IllegalArgumentException if <code>field</code> is * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown, * or if any calendar fields have out-of-range values in * non-lenient mode. */ public void add(int field, int amount) { // If amount == 0, do nothing even the given field is out of // range. This is tested by JCK. if (amount == 0) { return; // Do nothing! } if (field < 0 || field >= ZONE_OFFSET) { throw new IllegalArgumentException(); } // Sync the time and calendar fields. complete(); if (field == YEAR) { LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone(); d.addYear(amount); pinDayOfMonth(d); set(ERA, getEraIndex(d)); set(YEAR, d.getYear()); set(MONTH, d.getMonth() - 1); set(DAY_OF_MONTH, d.getDayOfMonth()); } else if (field == MONTH) { LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone(); d.addMonth(amount); pinDayOfMonth(d); set(ERA, getEraIndex(d)); set(YEAR, d.getYear()); set(MONTH, d.getMonth() - 1); set(DAY_OF_MONTH, d.getDayOfMonth()); } else if (field == ERA) { int era = internalGet(ERA) + amount; if (era < 0) { era = 0; } else if (era > eras.length - 1) { era = eras.length - 1; } set(ERA, era); } else { long delta = amount; long timeOfDay = 0; switch (field) { // Handle the time fields here. Convert the given // amount to milliseconds and call setTimeInMillis. case HOUR: case HOUR_OF_DAY: delta *= 60 * 60 * 1000; // hours to milliseconds break; case MINUTE: delta *= 60 * 1000; // minutes to milliseconds break; case SECOND: delta *= 1000; // seconds to milliseconds break; case MILLISECOND: break; // Handle week, day and AM_PM fields which involves // time zone offset change adjustment. Convert the // given amount to the number of days. case WEEK_OF_YEAR: case WEEK_OF_MONTH: case DAY_OF_WEEK_IN_MONTH: delta *= 7; break; case DAY_OF_MONTH: // synonym of DATE case DAY_OF_YEAR: case DAY_OF_WEEK: break; case AM_PM: // Convert the amount to the number of days (delta) // and +12 or -12 hours (timeOfDay). delta = amount / 2; timeOfDay = 12 * (amount % 2); break; } // The time fields don't require time zone offset change // adjustment. if (field >= HOUR) { setTimeInMillis(time + delta); return; } // The rest of the fields (week, day or AM_PM fields) // require time zone offset (both GMT and DST) change // adjustment. // Translate the current time to the fixed date and time // of the day. long fd = cachedFixedDate; timeOfDay += internalGet(HOUR_OF_DAY); timeOfDay *= 60; timeOfDay += internalGet(MINUTE); timeOfDay *= 60; timeOfDay += internalGet(SECOND); timeOfDay *= 1000; timeOfDay += internalGet(MILLISECOND); if (timeOfDay >= ONE_DAY) { fd++; timeOfDay -= ONE_DAY; } else if (timeOfDay < 0) { fd--; timeOfDay += ONE_DAY; } fd += delta; // fd is the expected fixed date after the calculation int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET); setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset); zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET); // If the time zone offset has changed, then adjust the difference. if (zoneOffset != 0) { setTimeInMillis(time + zoneOffset); long fd2 = cachedFixedDate; // If the adjustment has changed the date, then take // the previous one. if (fd2 != fd) { setTimeInMillis(time - zoneOffset); } } } } public void roll(int field, boolean up) { roll(field, up ? +1 : -1); } /** * Adds a signed amount to the specified calendar field without changing larger fields. * A negative roll amount means to subtract from field without changing * larger fields. If the specified amount is 0, this method performs nothing. * * <p>This method calls {@link #complete()} before adding the * amount so that all the calendar fields are normalized. If there * is any calendar field having an out-of-range value in non-lenient mode, then an * <code>IllegalArgumentException</code> is thrown. * * @param field the calendar field. * @param amount the signed amount to add to <code>field</code>.Lines 1–500 of 2383. Load more
/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util; import java.io.IOException; import java.io.ObjectInputStream; import sun.util.calendar.BaseCalendar; import sun.util.calendar.CalendarDate; import sun.util.calendar.CalendarSystem; import sun.util.calendar.CalendarUtils; import sun.util.calendar.Era; import sun.util.calendar.Gregorian; import sun.util.calendar.LocalGregorianCalendar; import sun.util.calendar.ZoneInfo; import sun.util.resources.LocaleData; /** * <code>JapaneseImperialCalendar</code> implements a Japanese * calendar system in which the imperial era-based year numbering is * supported from the Meiji era. The following are the eras supported * by this calendar system. * <pre><tt> * ERA value Era name Since (in Gregorian) * ------------------------------------------------------ * 0 N/A N/A * 1 Meiji 1868-01-01 midnight local time * 2 Taisho 1912-07-30 midnight local time * 3 Showa 1926-12-25 midnight local time * 4 Heisei 1989-01-08 midnight local time * ------------------------------------------------------ * </tt></pre> * * <p><code>ERA</code> value 0 specifies the years before Meiji and * the Gregorian year values are used. Unlike {@link * GregorianCalendar}, the Julian to Gregorian transition is not * supported because it doesn't make any sense to the Japanese * calendar systems used before Meiji. To represent the years before * Gregorian year 1, 0 and negative values are used. The Japanese * Imperial rescripts and government decrees don't specify how to deal * with time differences for applying the era transitions. This * calendar implementation assumes local time for all transitions. * * @author Masayoshi Okutsu * @since 1.6 */ class JapaneseImperialCalendar extends Calendar { /* * Implementation Notes * * This implementation uses * sun.util.calendar.LocalGregorianCalendar to perform most of the * calendar calculations. LocalGregorianCalendar is configurable * and reads <JRE_HOME>/lib/calendars.properties at the start-up. */ /** * The ERA constant designating the era before Meiji. */ public static final int BEFORE_MEIJI = 0; /** * The ERA constant designating the Meiji era. */ public static final int MEIJI = 1; /** * The ERA constant designating the Taisho era. */ public static final int TAISHO = 2; /** * The ERA constant designating the Showa era. */ public static final int SHOWA = 3; /** * The ERA constant designating the Heisei era. */ public static final int HEISEI = 4; private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian) private static final int EPOCH_YEAR = 1970; // Useful millisecond constants. Although ONE_DAY and ONE_WEEK can fit // into ints, they must be longs in order to prevent arithmetic overflow // when performing (bug 4173516). private static final int ONE_SECOND = 1000; private static final int ONE_MINUTE = 60*ONE_SECOND; private static final int ONE_HOUR = 60*ONE_MINUTE; private static final long ONE_DAY = 24*ONE_HOUR; private static final long ONE_WEEK = 7*ONE_DAY; // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton). private static final LocalGregorianCalendar jcal = (LocalGregorianCalendar) CalendarSystem.forName("japanese"); // Gregorian calendar instance. This is required because era // transition dates are given in Gregorian dates. private static final Gregorian gcal = CalendarSystem.getGregorianCalendar(); // The Era instance representing "before Meiji". private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false); // Imperial eras. The sun.util.calendar.LocalGregorianCalendar // doesn't have an Era representing before Meiji, which is // inconvenient for a Calendar. So, era[0] is a reference to // BEFORE_MEIJI_ERA. private static final Era[] eras; // Fixed date of the first date of each era. private static final long[] sinceFixedDates; /* * <pre> * Greatest Least * Field name Minimum Minimum Maximum Maximum * ---------- ------- ------- ------- ------- * ERA 0 0 1 1 * YEAR -292275055 1 ? ? * MONTH 0 0 11 11 * WEEK_OF_YEAR 1 1 52* 53 * WEEK_OF_MONTH 0 0 4* 6 * DAY_OF_MONTH 1 1 28* 31 * DAY_OF_YEAR 1 1 365* 366 * DAY_OF_WEEK 1 1 7 7 * DAY_OF_WEEK_IN_MONTH -1 -1 4* 6 * AM_PM 0 0 1 1 * HOUR 0 0 11 11 * HOUR_OF_DAY 0 0 23 23 * MINUTE 0 0 59 59 * SECOND 0 0 59 59 * MILLISECOND 0 0 999 999 * ZONE_OFFSET -13:00 -13:00 14:00 14:00 * DST_OFFSET 0:00 0:00 0:20 2:00 * </pre> * *: depends on eras */ static final int MIN_VALUES[] = { 0, // ERA -292275055, // YEAR JANUARY, // MONTH 1, // WEEK_OF_YEAR 0, // WEEK_OF_MONTH 1, // DAY_OF_MONTH 1, // DAY_OF_YEAR SUNDAY, // DAY_OF_WEEK 1, // DAY_OF_WEEK_IN_MONTH AM, // AM_PM 0, // HOUR 0, // HOUR_OF_DAY 0, // MINUTE 0, // SECOND 0, // MILLISECOND -13*ONE_HOUR, // ZONE_OFFSET (UNIX compatibility) 0 // DST_OFFSET }; static final int LEAST_MAX_VALUES[] = { 0, // ERA (initialized later) 0, // YEAR (initialized later) JANUARY, // MONTH (Showa 64 ended in January.) 0, // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.) 4, // WEEK_OF_MONTH 28, // DAY_OF_MONTH 0, // DAY_OF_YEAR (initialized later) SATURDAY, // DAY_OF_WEEK 4, // DAY_OF_WEEK_IN PM, // AM_PM 11, // HOUR 23, // HOUR_OF_DAY 59, // MINUTE 59, // SECOND 999, // MILLISECOND 14*ONE_HOUR, // ZONE_OFFSET 20*ONE_MINUTE // DST_OFFSET (historical least maximum) }; static final int MAX_VALUES[] = { 0, // ERA 292278994, // YEAR DECEMBER, // MONTH 53, // WEEK_OF_YEAR 6, // WEEK_OF_MONTH 31, // DAY_OF_MONTH 366, // DAY_OF_YEAR SATURDAY, // DAY_OF_WEEK 6, // DAY_OF_WEEK_IN PM, // AM_PM 11, // HOUR 23, // HOUR_OF_DAY 59, // MINUTE 59, // SECOND 999, // MILLISECOND 14*ONE_HOUR, // ZONE_OFFSET 2*ONE_HOUR // DST_OFFSET (double summer time) }; // Proclaim serialization compatibility with JDK 1.6 private static final long serialVersionUID = -3364572813905467929L; static { Era[] es = jcal.getEras(); int length = es.length + 1; eras = new Era[length]; sinceFixedDates = new long[length]; // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the // same as Gregorian. int index = BEFORE_MEIJI; sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate()); eras[index++] = BEFORE_MEIJI_ERA; for (Era e : es) { CalendarDate d = e.getSinceDate(); sinceFixedDates[index] = gcal.getFixedDate(d); eras[index++] = e; } LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1; // Calculate the least maximum year and least day of Year // values. The following code assumes that there's at most one // era transition in a Gregorian year. int year = Integer.MAX_VALUE; int dayOfYear = Integer.MAX_VALUE; CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE); for (int i = 1; i < eras.length; i++) { long fd = sinceFixedDates[i]; CalendarDate transitionDate = eras[i].getSinceDate(); date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1); long fdd = gcal.getFixedDate(date); dayOfYear = Math.min((int)(fdd - fd), dayOfYear); date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31); fdd = gcal.getFixedDate(date) + 1; dayOfYear = Math.min((int)(fd - fdd), dayOfYear); LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1); int y = lgd.getYear(); // Unless the first year starts from January 1, the actual // max value could be one year short. For example, if it's // Showa 63 January 8, 63 is the actual max value since // Showa 64 January 8 doesn't exist. if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd.getDayOfMonth() == 1)) y--; year = Math.min(y, year); } LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value. LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear; } /** * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to * avoid overhead of creating it for each calculation. */ private transient LocalGregorianCalendar.Date jdate; /** * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets * the GMT offset value and zoneOffsets[1] gets the daylight saving * value. */ private transient int[] zoneOffsets; /** * Temporary storage for saving original fields[] values in * non-lenient mode. */ private transient int[] originalFields; /** * Constructs a <code>JapaneseImperialCalendar</code> based on the current time * in the given time zone with the given locale. * * @param zone the given time zone. * @param aLocale the given locale. */ public JapaneseImperialCalendar(TimeZone zone, Locale aLocale) { super(zone, aLocale); jdate = jcal.newCalendarDate(zone); setTimeInMillis(System.currentTimeMillis()); } /** * Compares this <code>JapaneseImperialCalendar</code> to the specified * <code>Object</code>. The result is <code>true</code> if and * only if the argument is a <code>JapaneseImperialCalendar</code> object * that represents the same time value (millisecond offset from * the <a href="Calendar.html#Epoch">Epoch</a>) under the same * <code>Calendar</code> parameters. * * @param obj the object to compare with. * @return <code>true</code> if this object is equal to <code>obj</code>; * <code>false</code> otherwise. * @see Calendar#compareTo(Calendar) */ public boolean equals(Object obj) { return obj instanceof JapaneseImperialCalendar && super.equals(obj); } /** * Generates the hash code for this * <code>JapaneseImperialCalendar</code> object. */ public int hashCode() { return super.hashCode() ^ jdate.hashCode(); } /** * Adds the specified (signed) amount of time to the given calendar field, * based on the calendar's rules. * * <p><em>Add rule 1</em>. The value of <code>field</code> * after the call minus the value of <code>field</code> before the * call is <code>amount</code>, modulo any overflow that has occurred in * <code>field</code>. Overflow occurs when a field value exceeds its * range and, as a result, the next larger field is incremented or * decremented and the field value is adjusted back into its range.</p> * * <p><em>Add rule 2</em>. If a smaller field is expected to be * invariant, but it is impossible for it to be equal to its * prior value because of changes in its minimum or maximum after * <code>field</code> is changed, then its value is adjusted to be as close * as possible to its expected value. A smaller field represents a * smaller unit of time. <code>HOUR</code> is a smaller field than * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields * that are not expected to be invariant. The calendar system * determines what fields are expected to be invariant.</p> * * @param field the calendar field. * @param amount the amount of date or time to be added to the field. * @exception IllegalArgumentException if <code>field</code> is * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown, * or if any calendar fields have out-of-range values in * non-lenient mode. */ public void add(int field, int amount) { // If amount == 0, do nothing even the given field is out of // range. This is tested by JCK. if (amount == 0) { return; // Do nothing! } if (field < 0 || field >= ZONE_OFFSET) { throw new IllegalArgumentException(); } // Sync the time and calendar fields. complete(); if (field == YEAR) { LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone(); d.addYear(amount); pinDayOfMonth(d); set(ERA, getEraIndex(d)); set(YEAR, d.getYear()); set(MONTH, d.getMonth() - 1); set(DAY_OF_MONTH, d.getDayOfMonth()); } else if (field == MONTH) { LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone(); d.addMonth(amount); pinDayOfMonth(d); set(ERA, getEraIndex(d)); set(YEAR, d.getYear()); set(MONTH, d.getMonth() - 1); set(DAY_OF_MONTH, d.getDayOfMonth()); } else if (field == ERA) { int era = internalGet(ERA) + amount; if (era < 0) { era = 0; } else if (era > eras.length - 1) { era = eras.length - 1; } set(ERA, era); } else { long delta = amount; long timeOfDay = 0; switch (field) { // Handle the time fields here. Convert the given // amount to milliseconds and call setTimeInMillis. case HOUR: case HOUR_OF_DAY: delta *= 60 * 60 * 1000; // hours to milliseconds break; case MINUTE: delta *= 60 * 1000; // minutes to milliseconds break; case SECOND: delta *= 1000; // seconds to milliseconds break; case MILLISECOND: break; // Handle week, day and AM_PM fields which involves // time zone offset change adjustment. Convert the // given amount to the number of days. case WEEK_OF_YEAR: case WEEK_OF_MONTH: case DAY_OF_WEEK_IN_MONTH: delta *= 7; break; case DAY_OF_MONTH: // synonym of DATE case DAY_OF_YEAR: case DAY_OF_WEEK: break; case AM_PM: // Convert the amount to the number of days (delta) // and +12 or -12 hours (timeOfDay). delta = amount / 2; timeOfDay = 12 * (amount % 2); break; } // The time fields don't require time zone offset change // adjustment. if (field >= HOUR) { setTimeInMillis(time + delta); return; } // The rest of the fields (week, day or AM_PM fields) // require time zone offset (both GMT and DST) change // adjustment. // Translate the current time to the fixed date and time // of the day. long fd = cachedFixedDate; timeOfDay += internalGet(HOUR_OF_DAY); timeOfDay *= 60; timeOfDay += internalGet(MINUTE); timeOfDay *= 60; timeOfDay += internalGet(SECOND); timeOfDay *= 1000; timeOfDay += internalGet(MILLISECOND); if (timeOfDay >= ONE_DAY) { fd++; timeOfDay -= ONE_DAY; } else if (timeOfDay < 0) { fd--; timeOfDay += ONE_DAY; } fd += delta; // fd is the expected fixed date after the calculation int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET); setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset); zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET); // If the time zone offset has changed, then adjust the difference. if (zoneOffset != 0) { setTimeInMillis(time + zoneOffset); long fd2 = cachedFixedDate; // If the adjustment has changed the date, then take // the previous one. if (fd2 != fd) { setTimeInMillis(time - zoneOffset); } } } } public void roll(int field, boolean up) { roll(field, up ? +1 : -1); } /** * Adds a signed amount to the specified calendar field without changing larger fields. * A negative roll amount means to subtract from field without changing * larger fields. If the specified amount is 0, this method performs nothing. * * <p>This method calls {@link #complete()} before adding the * amount so that all the calendar fields are normalized. If there * is any calendar field having an out-of-range value in non-lenient mode, then an * <code>IllegalArgumentException</code> is thrown. * * @param field the calendar field. * @param amount the signed amount to add to <code>field</code>.