2383 lines · 98.1 KB · Java
RawDownload
/* * 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.