FileDocCategorySizeDatePackage
JapaneseImperialCalendar.javaAPI DocJava SE 6 API79320Tue Jun 10 00:25:54 BST 2008java.util

JapaneseImperialCalendar

public class JapaneseImperialCalendar extends Calendar
JapaneseImperialCalendar 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.

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
------------------------------------------------------

ERA 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

Fields Summary
public static final int
BEFORE_MEIJI
The ERA constant designating the era before Meiji.
public static final int
MEIJI
The ERA constant designating the Meiji era.
public static final int
TAISHO
The ERA constant designating the Taisho era.
public static final int
SHOWA
The ERA constant designating the Showa era.
public static final int
HEISEI
The ERA constant designating the Heisei era.
private static final int
EPOCH_OFFSET
private static final int
EPOCH_YEAR
private static final int
ONE_SECOND
private static final int
ONE_MINUTE
private static final int
ONE_HOUR
private static final long
ONE_DAY
private static final long
ONE_WEEK
private static final LocalGregorianCalendar
jcal
private static final Gregorian
gcal
private static final Era
BEFORE_MEIJI_ERA
private static final Era[]
eras
private static final long[]
sinceFixedDates
static final int[]
MIN_VALUES
static final int[]
LEAST_MAX_VALUES
static final int[]
MAX_VALUES
private static final long
serialVersionUID
private transient LocalGregorianCalendar$Date
jdate
jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to avoid overhead of creating it for each calculation.
private transient int[]
zoneOffsets
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[]
originalFields
Temporary storage for saving original fields[] values in non-lenient mode.
private transient long
cachedFixedDate
The fixed date corresponding to jdate. If the value is Long.MIN_VALUE, the fixed date value is unknown.
Constructors Summary
public JapaneseImperialCalendar(TimeZone zone, Locale aLocale)
Constructs a JapaneseImperialCalendar 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.

        super(zone, aLocale);
	jdate = jcal.newCalendarDate(zone);
        setTimeInMillis(System.currentTimeMillis());
    
Methods Summary
private final intactualMonthLength()

	int length = jcal.getMonthLength(jdate);
	int eraIndex = getTransitionEraIndex(jdate);
	if (eraIndex == -1) {
	    long transitionFixedDate = sinceFixedDates[eraIndex];
	    CalendarDate d = eras[eraIndex].getSinceDate();
	    if (transitionFixedDate <= cachedFixedDate) {
		length -= d.getDayOfMonth() - 1;
	    } else {
		length = d.getDayOfMonth() - 1;
	    }
	}
	return length;
    
public voidadd(int field, int amount)
Adds the specified (signed) amount of time to the given calendar field, based on the calendar's rules.

Add rule 1. The value of field after the call minus the value of field before the call is amount, modulo any overflow that has occurred in field. 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.

Add rule 2. 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 field 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. HOUR is a smaller field than DAY_OF_MONTH. 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.

param
field the calendar field.
param
amount the amount of date or time to be added to the field.
exception
IllegalArgumentException if field is ZONE_OFFSET, DST_OFFSET, or unknown, or if any calendar fields have out-of-range values in non-lenient mode.

	// 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 java.lang.Objectclone()

	JapaneseImperialCalendar other = (JapaneseImperialCalendar) super.clone();

	other.jdate = (LocalGregorianCalendar.Date) jdate.clone();
	other.originalFields = null;
	other.zoneOffsets = null;
	return other;
    
protected voidcomputeFields()
Converts the time value (millisecond offset from the Epoch) to calendar field values. The time is not recomputed first; to recompute the time, then the fields, call the complete method.

see
Calendar#complete


                                          
       
	int mask = 0;
	if (isPartiallyNormalized()) {
	    // Determine which calendar fields need to be computed.
	    mask = getSetStateFields();
	    int fieldMask = ~mask & ALL_FIELDS;
	    if (fieldMask != 0 || cachedFixedDate == Long.MIN_VALUE) {
		mask |= computeFields(fieldMask,
				      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
		assert mask == ALL_FIELDS;
	    }
	} else {
	    // Specify all fields
	    mask = ALL_FIELDS;
	    computeFields(mask, 0);
	}
	// After computing all the fields, set the field state to `COMPUTED'.
	setFieldsComputed(mask);
    
private intcomputeFields(int fieldMask, int tzMask)
This computeFields implements the conversion from UTC (millisecond offset from the Epoch) to calendar field values. fieldMask specifies which fields to change the setting state to COMPUTED, although all fields are set to the correct values. This is required to fix 4685354.

param
fieldMask a bit mask to specify which fields to change the setting state.
param
tzMask a bit mask to specify which time zone offset fields to be used for time calculations
return
a new field mask that indicates what field values have actually been set.

	int zoneOffset = 0;
	TimeZone tz = getZone();
	if (zoneOffsets == null) {
	    zoneOffsets = new int[2];
	}
	if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
	    if (tz instanceof ZoneInfo) {
		zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
	    } else {
		zoneOffset = tz.getOffset(time);
		zoneOffsets[0] = tz.getRawOffset();
		zoneOffsets[1] = zoneOffset - zoneOffsets[0];
	    }
	}
	if (tzMask != 0) {
	    if (isFieldSet(tzMask, ZONE_OFFSET)) {
		zoneOffsets[0] = internalGet(ZONE_OFFSET);
	    }
	    if (isFieldSet(tzMask, DST_OFFSET)) {
		zoneOffsets[1] = internalGet(DST_OFFSET);
	    }
	    zoneOffset = zoneOffsets[0] + zoneOffsets[1];
	}

	// By computing time and zoneOffset separately, we can take
	// the wider range of time+zoneOffset than the previous
	// implementation.
	long fixedDate = zoneOffset / ONE_DAY;
	int timeOfDay = zoneOffset % (int)ONE_DAY;
	fixedDate += time / ONE_DAY;
	timeOfDay += (int) (time % ONE_DAY);
	if (timeOfDay >= ONE_DAY) {
	    timeOfDay -= ONE_DAY;
	    ++fixedDate;
	} else {
	    while (timeOfDay < 0) {
		timeOfDay += ONE_DAY;
		--fixedDate;
	    }
	}
	fixedDate += EPOCH_OFFSET;

	// See if we can use jdate to avoid date calculation.
	if (fixedDate != cachedFixedDate || fixedDate < 0) {
	    jcal.getCalendarDateFromFixedDate(jdate, fixedDate);
	    cachedFixedDate = fixedDate;
	}
	int era = getEraIndex(jdate);
	int year = jdate.getYear();

	// Always set the ERA and YEAR values.
        internalSet(ERA, era);
	internalSet(YEAR, year);
	int mask = fieldMask | (ERA_MASK|YEAR_MASK);

	int month =  jdate.getMonth() - 1; // 0-based
	int dayOfMonth = jdate.getDayOfMonth();

	// Set the basic date fields.
	if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
	    != 0) {
	    internalSet(MONTH, month);
	    internalSet(DAY_OF_MONTH, dayOfMonth);
	    internalSet(DAY_OF_WEEK, jdate.getDayOfWeek());
	    mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
	}

	if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
			  |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
	    if (timeOfDay != 0) {
		int hours = timeOfDay / ONE_HOUR;
		internalSet(HOUR_OF_DAY, hours);
		internalSet(AM_PM, hours / 12); // Assume AM == 0
		internalSet(HOUR, hours % 12);
		int r = timeOfDay % ONE_HOUR;
		internalSet(MINUTE, r / ONE_MINUTE);
		r %= ONE_MINUTE;
		internalSet(SECOND, r / ONE_SECOND);
		internalSet(MILLISECOND, r % ONE_SECOND);
	    } else {
		internalSet(HOUR_OF_DAY, 0);
		internalSet(AM_PM, AM);
		internalSet(HOUR, 0);
		internalSet(MINUTE, 0);
		internalSet(SECOND, 0);
		internalSet(MILLISECOND, 0);
	    }
	    mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
		     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
	}

	if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
	    internalSet(ZONE_OFFSET, zoneOffsets[0]);
	    internalSet(DST_OFFSET, zoneOffsets[1]);
	    mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
	}

	if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK
			  |WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
	    int normalizedYear = jdate.getNormalizedYear();
	    // If it's a year of an era transition, we need to handle
	    // irregular year boundaries.
	    boolean transitionYear = isTransitionYear(jdate.getNormalizedYear());
	    int dayOfYear;
	    long fixedDateJan1;
	    if (transitionYear) {
		fixedDateJan1 = getFixedDateJan1(jdate, fixedDate);
		dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
	    } else if (normalizedYear == MIN_VALUES[YEAR]) {
		CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
		fixedDateJan1 = jcal.getFixedDate(dx);
		dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
	    } else {
		dayOfYear = (int) jcal.getDayOfYear(jdate);
		fixedDateJan1 = fixedDate - dayOfYear + 1;
	    }
	    long fixedDateMonth1 = transitionYear ?
		getFixedDateMonth1(jdate, fixedDate) : fixedDate - dayOfMonth + 1;

	    internalSet(DAY_OF_YEAR, dayOfYear);
	    internalSet(DAY_OF_WEEK_IN_MONTH, (dayOfMonth - 1) / 7 + 1);

	    int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);

	    // The spec is to calculate WEEK_OF_YEAR in the
	    // ISO8601-style. This creates problems, though.
	    if (weekOfYear == 0) {
		// If the date belongs to the last week of the
		// previous year, use the week number of "12/31" of
		// the "previous" year. Again, if the previous year is
		// a transition year, we need to take care of it.
		// Usually the previous day of the first day of a year
		// is December 31, which is not always true in the
		// Japanese imperial calendar system.
		long fixedDec31 = fixedDateJan1 - 1;
		long prevJan1;
		LocalGregorianCalendar.Date d = getCalendarDate(fixedDec31);
		if (!(transitionYear || isTransitionYear(d.getNormalizedYear()))) {
		    prevJan1 = fixedDateJan1 - 365;
		    if (d.isLeapYear()) {
			--prevJan1;
		    }
		} else if (transitionYear) {
		    if (jdate.getYear() == 1) {
			// As of Heisei (since Meiji) there's no case
			// that there are multiple transitions in a
			// year.  Historically there was such
			// case. There might be such case again in the
			// future.
			if (era > HEISEI) {
			    CalendarDate pd = eras[era - 1].getSinceDate();
			    if (normalizedYear == pd.getYear()) {
				d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
			    }
			} else {
			    d.setMonth(jcal.JANUARY).setDayOfMonth(1);
			}
			jcal.normalize(d);
			prevJan1 = jcal.getFixedDate(d);
		    } else {
			prevJan1 = fixedDateJan1 - 365;
			if (d.isLeapYear()) {
			    --prevJan1;
			}
		    }
		} else {
		    CalendarDate cd = eras[getEraIndex(jdate)].getSinceDate();
		    d.setMonth(cd.getMonth()).setDayOfMonth(cd.getDayOfMonth());
		    jcal.normalize(d);
		    prevJan1 = jcal.getFixedDate(d);
		}
		weekOfYear = getWeekNumber(prevJan1, fixedDec31);
	    } else {
		if (!transitionYear) {
		    // Regular years
		    if (weekOfYear >= 52) {
			long nextJan1 = fixedDateJan1 + 365;
			if (jdate.isLeapYear()) {
			    nextJan1++;
			}
			long nextJan1st = jcal.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
									  getFirstDayOfWeek());
			int ndays = (int)(nextJan1st - nextJan1);
			if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
			    // The first days forms a week in which the date is included.
			    weekOfYear = 1;
			}
		    }
		} else {
		    LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
		    long nextJan1;
		    if (jdate.getYear() == 1) {
			d.addYear(+1);
			d.setMonth(jcal.JANUARY).setDayOfMonth(1);
			nextJan1 = jcal.getFixedDate(d);
		    } else {
			int nextEraIndex = getEraIndex(d) + 1;
			CalendarDate cd = eras[nextEraIndex].getSinceDate();
			d.setEra(eras[nextEraIndex]);
			d.setDate(1, cd.getMonth(), cd.getDayOfMonth());
			jcal.normalize(d);
			nextJan1 = jcal.getFixedDate(d);
		    }
		    long nextJan1st = jcal.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
								      getFirstDayOfWeek());
		    int ndays = (int)(nextJan1st - nextJan1);
		    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
			// The first days forms a week in which the date is included.
			weekOfYear = 1;
		    }
		}
	    }
	    internalSet(WEEK_OF_YEAR, weekOfYear);
	    internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
	    mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
	}
	return mask;
    
protected voidcomputeTime()
Converts calendar field values to the time value (millisecond offset from the Epoch).

exception
IllegalArgumentException if any calendar fields are invalid.

	// In non-lenient mode, perform brief checking of calendar
	// fields which have been set externally. Through this
	// checking, the field values are stored in originalFields[]
	// to see if any of them are normalized later.
        if (!isLenient()) {
	    if (originalFields == null) {
		originalFields = new int[FIELD_COUNT];
	    }
	    for (int field = 0; field < FIELD_COUNT; field++) {
		int value = internalGet(field);
		if (isExternallySet(field)) {
		    // Quick validation for any out of range values
		    if (value < getMinimum(field) || value > getMaximum(field)) {
			throw new IllegalArgumentException(getFieldName(field));
		    }
		}
		originalFields[field] = value;
	    }
	}

	// Let the super class determine which calendar fields to be
	// used to calculate the time.
	int fieldMask = selectFields();

        int year;
        int era;

	if (isSet(ERA)) {
	    era = internalGet(ERA);
	    year = isSet(YEAR) ? internalGet(YEAR) : 1;
	} else {
	    if (isSet(YEAR)) {
		era = eras.length - 1;
		year = internalGet(YEAR);
	    } else {
		// Equivalent to 1970 (Gregorian)
		era = SHOWA;
		year = 45;
	    }
	}

        // Calculate the time of day. We rely on the convention that
        // an UNSET field has 0.
        long timeOfDay = 0;
	if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
	    timeOfDay += (long) internalGet(HOUR_OF_DAY);
	} else {
	    timeOfDay += internalGet(HOUR);
	    // The default value of AM_PM is 0 which designates AM.
	    if (isFieldSet(fieldMask, AM_PM)) {
		timeOfDay += 12 * internalGet(AM_PM);
	    }
        }
        timeOfDay *= 60;
	timeOfDay += internalGet(MINUTE);
        timeOfDay *= 60;
	timeOfDay += internalGet(SECOND);
        timeOfDay *= 1000;
	timeOfDay += internalGet(MILLISECOND);

	// Convert the time of day to the number of days and the
	// millisecond offset from midnight.
	long fixedDate = timeOfDay / ONE_DAY;
	timeOfDay %= ONE_DAY;
	while (timeOfDay < 0) {
	    timeOfDay += ONE_DAY;
	    --fixedDate;
	}
	
	// Calculate the fixed date since January 1, 1 (Gregorian).
	fixedDate += getFixedDate(era, year, fieldMask);

        // millis represents local wall-clock time in milliseconds.
        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;

        // Compute the time zone offset and DST offset.  There are two potential
        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
        // for discussion purposes here.
        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
        //    We assume standard time.
        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
        //    can be in standard or DST.  Both are valid representations (the rep
        //    jumps from 1:59:59 DST to 1:00:00 Std).
        //    Again, we assume standard time.
        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
        // or DST_OFFSET fields; then we use those fields.
        TimeZone zone = getZone();
	if (zoneOffsets == null) {
	    zoneOffsets = new int[2];
	}
	int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
	if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
	    if (zone instanceof ZoneInfo) {
		((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
	    } else {
		zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
	    }
	}
	if (tzMask != 0) {
	    if (isFieldSet(tzMask, ZONE_OFFSET)) {
		zoneOffsets[0] = internalGet(ZONE_OFFSET);
	    }
	    if (isFieldSet(tzMask, DST_OFFSET)) {
		zoneOffsets[1] = internalGet(DST_OFFSET);
	    }
	}

	// Adjust the time zone offset values to get the UTC time.
	millis -= zoneOffsets[0] + zoneOffsets[1];

	// Set this calendar's time in milliseconds
	time = millis;

	int mask = computeFields(fieldMask | getSetStateFields(), tzMask);

	if (!isLenient()) {
	    for (int field = 0; field < FIELD_COUNT; field++) {
		if (!isExternallySet(field)) {
		    continue;
		}
		if (originalFields[field] != internalGet(field)) {
		    int wrongValue = internalGet(field);
		    // Restore the original field values
		    System.arraycopy(originalFields, 0, fields, 0, fields.length);
		    throw new IllegalArgumentException(getFieldName(field) + "=" + wrongValue
						       + ", expected " + originalFields[field]);
		}
	    }
	}
	setFieldsNormalized(mask);
    
public booleanequals(java.lang.Object obj)
Compares this JapaneseImperialCalendar to the specified Object. The result is true if and only if the argument is a JapaneseImperialCalendar object that represents the same time value (millisecond offset from the Epoch) under the same Calendar parameters.

param
obj the object to compare with.
return
true if this object is equal to obj; false otherwise.
see
Calendar#compareTo(Calendar)

        return obj instanceof JapaneseImperialCalendar &&
	    super.equals(obj);
    
public intgetActualMaximum(int field)
Returns the maximum value that this calendar field could have, taking into consideration the given time value and the current values of the {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, and {@link Calendar#getTimeZone() getTimeZone} methods. For example, if the date of this instance is Heisei 16February 1, the actual maximum value of the DAY_OF_MONTH field is 29 because Heisei 16 is a leap year, and if the date of this instance is Heisei 17 February 1, it's 28.

param
field the calendar field
return
the maximum of the given field for the time value of this JapaneseImperialCalendar
see
#getMinimum(int)
see
#getMaximum(int)
see
#getGreatestMinimum(int)
see
#getLeastMaximum(int)
see
#getActualMinimum(int)

	final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
	    HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
	    ZONE_OFFSET_MASK|DST_OFFSET_MASK;
	if ((fieldsForFixedMax & (1<<field)) != 0) {
	    return getMaximum(field);
	}

	JapaneseImperialCalendar jc = getNormalizedCalendar();
	LocalGregorianCalendar.Date date = jc.jdate;
	int normalizedYear = date.getNormalizedYear();

	int value = -1;
        switch (field) {
	case MONTH:
	    {
		value = DECEMBER;
		if (isTransitionYear(date.getNormalizedYear())) {
		    // TODO: there may be multiple transitions in a year.
		    int eraIndex = getEraIndex(date);
		    if (date.getYear() != 1) {
			eraIndex++;
			assert eraIndex < eras.length;
		    }
		    long transition = sinceFixedDates[eraIndex];
		    long fd = jc.cachedFixedDate;
		    if (fd < transition) {
			LocalGregorianCalendar.Date ldate
			    = (LocalGregorianCalendar.Date) date.clone();
			jcal.getCalendarDateFromFixedDate(ldate, transition - 1);
			value = ldate.getMonth() - 1;
		    }
		} else {
		    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
									 getZone());
		    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
			value = d.getMonth() - 1;
		    }
		}
	    }
	    break;

        case DAY_OF_MONTH:
	    value = jcal.getMonthLength(date);
	    break;

        case DAY_OF_YEAR:
	    {
		if (isTransitionYear(date.getNormalizedYear())) {
		    // Handle transition year.
		    // TODO: there may be multiple transitions in a year.
		    int eraIndex = getEraIndex(date);
		    if (date.getYear() != 1) {
			eraIndex++;
			assert eraIndex < eras.length;
		    }
		    long transition = sinceFixedDates[eraIndex];
		    long fd = jc.cachedFixedDate;
		    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
		    d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
		    if (fd < transition) {
			value = (int)(transition - gcal.getFixedDate(d));
		    } else {
			d.addYear(+1);
			value = (int)(gcal.getFixedDate(d) - transition);
		    }
		} else {
		    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
									 getZone());
		    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
			long fd = jcal.getFixedDate(d);
			long jan1 = getFixedDateJan1(d, fd);
			value = (int)(fd - jan1) + 1;
		    } else if (date.getYear() == getMinimum(YEAR)) {
			CalendarDate d1 = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
			long fd1 = jcal.getFixedDate(d1);
			d1.addYear(1);
			d1.setMonth(BaseCalendar.JANUARY).setDayOfMonth(1);
			jcal.normalize(d1);
			long fd2 = jcal.getFixedDate(d1);
			value = (int)(fd2 - fd1);
		    } else {
			value = jcal.getYearLength(date);
		    }
		}
	    }
	    break;

        case WEEK_OF_YEAR:
	    {
		if (!isTransitionYear(date.getNormalizedYear())) {
		    LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
									  getZone());
		    if (date.getEra() == jd.getEra() && date.getYear() == jd.getYear()) {
			long fd = jcal.getFixedDate(jd);
			long jan1 = getFixedDateJan1(jd, fd);
			value = getWeekNumber(jan1, fd);
		    } else if (date.getEra() == null && date.getYear() == getMinimum(YEAR)) {
			CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
			// shift 400 years to avoid underflow
			d.addYear(+400);
			jcal.normalize(d);
			jd.setEra(d.getEra());
			jd.setDate(d.getYear() + 1, BaseCalendar.JANUARY, 1);
			jcal.normalize(jd);
			long jan1 = jcal.getFixedDate(d);
			long nextJan1 = jcal.getFixedDate(jd);
			long nextJan1st = jcal.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
									  getFirstDayOfWeek());
			int ndays = (int)(nextJan1st - nextJan1);
			if (ndays >= getMinimalDaysInFirstWeek()) {
			    nextJan1st -= 7;
			}
			value = getWeekNumber(jan1, nextJan1st);
		    } else {
			// Get the day of week of January 1 of the year
			CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
			d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
			int dayOfWeek = gcal.getDayOfWeek(d);
			// Normalize the day of week with the firstDayOfWeek value
			dayOfWeek -= getFirstDayOfWeek();
			if (dayOfWeek < 0) {
			    dayOfWeek += 7;
			}
			value = 52;
			int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
			if ((magic == 6) ||
			    (date.isLeapYear() && (magic == 5 || magic == 12))) {
			    value++;
			}
		    }
		    break;
		}

		if (jc == this) {
		    jc = (JapaneseImperialCalendar) jc.clone();
		}
		int max = getActualMaximum(DAY_OF_YEAR);
		jc.set(DAY_OF_YEAR, max);
		value = jc.get(WEEK_OF_YEAR);
		if (value == 1 && max > 7) {
		    jc.add(WEEK_OF_YEAR, -1);
		    value = jc.get(WEEK_OF_YEAR);
		}
	    }
	    break;

        case WEEK_OF_MONTH:
	    {
		LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
								      getZone());
		if (!(date.getEra() == jd.getEra() && date.getYear() == jd.getYear())) {
		    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
		    d.setDate(date.getNormalizedYear(), date.getMonth(), 1);
		    int dayOfWeek = gcal.getDayOfWeek(d);
		    int monthLength = gcal.getMonthLength(d);
		    dayOfWeek -= getFirstDayOfWeek();
		    if (dayOfWeek < 0) {
			dayOfWeek += 7;
		    }
		    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
		    value = 3;
		    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
			value++;
		    }
		    monthLength -= nDaysFirstWeek + 7 * 3;
		    if (monthLength > 0) {
			value++;
			if (monthLength > 7) {
			    value++;
			}
		    }
		} else {
		    long fd = jcal.getFixedDate(jd);
		    long month1 = fd - jd.getDayOfMonth() + 1;
		    value = getWeekNumber(month1, fd);
		}
	    }
	    break;

        case DAY_OF_WEEK_IN_MONTH:
	    {
		int ndays, dow1;
		int dow = date.getDayOfWeek();
		BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
		ndays = jcal.getMonthLength(d);
		d.setDayOfMonth(1);
		jcal.normalize(d);
		dow1 = d.getDayOfWeek();
		int x = dow - dow1;
		if (x < 0) {
		    x += 7;
		}
		ndays -= x;
		value = (ndays + 6) / 7;
	    }
	    break;

	case YEAR:
	    {
		CalendarDate jd = jcal.getCalendarDate(jc.getTimeInMillis(), getZone());
		CalendarDate d;
		int eraIndex = getEraIndex(date);
		if (eraIndex == eras.length - 1) {
		    d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
		    value = d.getYear();
		    // Use an equivalent year for the
		    // getYearOffsetInMillis call to avoid overflow.
		    if (value > 400) {
			jd.setYear(value - 400);
		    }
		} else {
		    d = jcal.getCalendarDate(eras[eraIndex + 1].getSince(getZone()) - 1,
					     getZone());
		    value = d.getYear();
		    // Use the same year as d.getYear() to be
		    // consistent with leap and common years.
		    jd.setYear(value);
		}
		jcal.normalize(jd);
		if (getYearOffsetInMillis(jd) > getYearOffsetInMillis(d)) {
		    value--;
		}
	    }
	    break;

	default:
	    throw new ArrayIndexOutOfBoundsException(field);
	}
	return value;
    
public intgetActualMinimum(int field)
Returns the minimum value that this calendar field could have, taking into consideration the given time value and the current values of the {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, and {@link Calendar#getTimeZone() getTimeZone} methods.

param
field the calendar field
return
the minimum of the given field for the time value of this JapaneseImperialCalendar
see
#getMinimum(int)
see
#getMaximum(int)
see
#getGreatestMinimum(int)
see
#getLeastMaximum(int)
see
#getActualMaximum(int)

	if (!isFieldSet(YEAR_MASK|MONTH_MASK|WEEK_OF_YEAR_MASK, field)) {
	    return getMinimum(field);
	}

	int value = 0;
	JapaneseImperialCalendar jc = getNormalizedCalendar();
	// Get a local date which includes time of day and time zone,
	// which are missing in jc.jdate.
	LocalGregorianCalendar.Date jd = jcal.getCalendarDate(jc.getTimeInMillis(),
							      getZone());
	int eraIndex = getEraIndex(jd);
	switch (field) {
	case YEAR:
	    {
		if (eraIndex > BEFORE_MEIJI) {
		    value = 1;
		    long since = eras[eraIndex].getSince(getZone());
		    CalendarDate d = jcal.getCalendarDate(since, getZone());
		    // Use the same year in jd to take care of leap
		    // years. i.e., both jd and d must agree on leap
		    // or common years.
		    jd.setYear(d.getYear());
		    jcal.normalize(jd);
		    assert jd.isLeapYear() == d.isLeapYear();
		    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
			value++;
		    }
		} else {
		    value = getMinimum(field);
		    CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
		    // Use an equvalent year of d.getYear() if
		    // possible. Otherwise, ignore the leap year and
		    // common year difference.
		    int y = d.getYear();
		    if (y > 400) {
			y -= 400;
		    }
		    jd.setYear(y);
		    jcal.normalize(jd);
		    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
			value++;
		    }
		}
	    }
	    break;

	case MONTH:
	    {
		// In Before Meiji and Meiji, January is the first month.
		if (eraIndex > MEIJI && jd.getYear() == 1) {
		    long since = eras[eraIndex].getSince(getZone());
		    CalendarDate d = jcal.getCalendarDate(since, getZone());
		    value = d.getMonth() - 1;
		    if (jd.getDayOfMonth() < d.getDayOfMonth()) {
			value++;
		    }
		}
	    }
	    break;

	case WEEK_OF_YEAR:
	    {
		value = 1;
		CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
		// shift 400 years to avoid underflow
		d.addYear(+400);
		jcal.normalize(d);
		jd.setEra(d.getEra());
		jd.setYear(d.getYear());
		jcal.normalize(jd);

		long jan1 = jcal.getFixedDate(d);
		long fd = jcal.getFixedDate(jd);
		int woy = getWeekNumber(jan1, fd);
		long day1 = fd - (7 * (woy - 1));
		if ((day1 < jan1) ||
		    (day1 == jan1 &&
		     jd.getTimeOfDay() < d.getTimeOfDay())) {
		    value++;
		}
	    }
	    break;
	}
	return value;
    
private static final sun.util.calendar.LocalGregorianCalendar$DategetCalendarDate(long fd)
Returns a LocalGregorianCalendar.Date produced from the specified fixed date.

param
fd the fixed date

	LocalGregorianCalendar.Date d = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
	jcal.getCalendarDateFromFixedDate(d, fd);
	return d;
    
public java.lang.StringgetDisplayName(int field, int style, java.util.Locale locale)

	if (!checkDisplayNameParams(field, style, SHORT, LONG, locale,
				    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
	    return null;
	}

	// "GanNen" is supported only in the LONG style.
	if (field == YEAR
	    && (style == SHORT || get(YEAR) != 1 || get(ERA) == 0)) {
	    return null;
	}

	ResourceBundle rb = LocaleData.getDateFormatData(locale);
	String name = null;
	String key = getKey(field, style);
	if (key != null) {
	    String[] strings = rb.getStringArray(key);
	    if (field == YEAR) {
		if (strings.length > 0) {
		    name = strings[0];
		}
	    } else {
		int index = get(field);
		// If the ERA value is out of range for strings, then
		// try to get its name or abbreviation from the Era instance.
		if (field == ERA && index >= strings.length && index < eras.length) {
		    Era era = eras[index];
		    name = (style == SHORT) ? era.getAbbreviation() : era.getName();
		} else {
		    if (field == DAY_OF_WEEK)
			--index;
		    name = strings[index];
		}
	    }
	}
	return name;
    
public java.util.MapgetDisplayNames(int field, int style, java.util.Locale locale)

	if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
				    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
	    return null;
	}

	if (style == ALL_STYLES) {
	    Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
	    if (field == AM_PM) {
		return shortNames;
	    }
	    Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
	    if (shortNames == null) {
		return longNames;
	    }
	    if (longNames != null) {
		shortNames.putAll(longNames);
	    }
	    return shortNames;
	}

	// SHORT or LONG
	return getDisplayNamesImpl(field, style, locale);
    
private java.util.MapgetDisplayNamesImpl(int field, int style, java.util.Locale locale)

	ResourceBundle rb = LocaleData.getDateFormatData(locale);
	String key = getKey(field, style);
	Map<String,Integer> map = new HashMap<String,Integer>();
	if (key != null) {
	    String[] strings = rb.getStringArray(key);
	    if (field == YEAR) {
		if (strings.length > 0) {
		    map.put(strings[0], 1);
		}
	    } else {
		int base = (field == DAY_OF_WEEK) ? 1 : 0;
		for (int i = 0; i < strings.length; i++) {
		    map.put(strings[i], base + i);
		}
		// If strings[] has fewer than eras[], get more names from eras[].
		if (field == ERA && strings.length < eras.length) {
		    for (int i = strings.length; i < eras.length; i++) {
			Era era = eras[i];
			String name = (style == SHORT) ? era.getAbbreviation() : era.getName();
			map.put(name, i);
		    }
		}
	    }
	}
	return map.size() > 0 ? map : null;
    
private static final intgetEraIndex(sun.util.calendar.LocalGregorianCalendar$Date date)

	Era era = date.getEra();
	for (int i = eras.length - 1; i > 0; i--) {
	    if (eras[i] == era) {
		return i;
	    }
	}
	return 0;
    
private longgetFixedDate(int era, int year, int fieldMask)
Computes the fixed date under either the Gregorian or the Julian calendar, using the given year and the specified calendar fields.

param
cal the CalendarSystem to be used for the date calculation
param
year the normalized year number, with 0 indicating the year 1 BCE, -1 indicating 2 BCE, etc.
param
fieldMask the calendar fields to be used for the date calculation
return
the fixed date
see
Calendar#selectFields

	int month = JANUARY;
	int firstDayOfMonth = 1;
	if (isFieldSet(fieldMask, MONTH)) {
            // No need to check if MONTH has been set (no isSet(MONTH)
            // call) since its unset value happens to be JANUARY (0).
	    month = internalGet(MONTH);

            // If the month is out of range, adjust it into range.
	    if (month > DECEMBER) {
		year += month / 12;
		month %= 12;
	    } else if (month < JANUARY) {
                int[] rem = new int[1];
                year += CalendarUtils.floorDivide(month, 12, rem);
                month = rem[0];
            }
	} else {
	    if (year == 1 && era != 0) {
		CalendarDate d = eras[era].getSinceDate();
		month = d.getMonth() - 1;
		firstDayOfMonth = d.getDayOfMonth();
	    }
	}

	// Adjust the base date if year is the minimum value.
	if (year == MIN_VALUES[YEAR]) {
	    CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
	    int m = dx.getMonth() - 1;
	    if (month < m)
		month = m;
	    if (month == m)
		firstDayOfMonth = dx.getDayOfMonth();
	}

	LocalGregorianCalendar.Date date = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
	date.setEra(era > 0 ? eras[era] : null);
	date.setDate(year, month + 1, firstDayOfMonth);
	jcal.normalize(date);

	// Get the fixed date since Jan 1, 1 (Gregorian). We are on
	// the first day of either `month' or January in 'year'.
	long fixedDate = jcal.getFixedDate(date);

	if (isFieldSet(fieldMask, MONTH)) {
	    // Month-based calculations
            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
		// We are on the "first day" of the month (which may
		// not be 1). Just add the offset if DAY_OF_MONTH is
		// set. If the isSet call returns false, that means
		// DAY_OF_MONTH has been selected just because of the
		// selected combination. We don't need to add any
		// since the default value is the "first day".
		if (isSet(DAY_OF_MONTH)) {
		    // To avoid underflow with DAY_OF_MONTH-firstDayOfMonth, add
		    // DAY_OF_MONTH, then subtract firstDayOfMonth.
		    fixedDate += internalGet(DAY_OF_MONTH);
		    fixedDate -= firstDayOfMonth;
		}
            } else {
                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
		    long firstDayOfWeek = jcal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
									  getFirstDayOfWeek());
                    // If we have enough days in the first week, then
                    // move to the previous week.
                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
			firstDayOfWeek -= 7;
		    }
		    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
			firstDayOfWeek = jcal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
									 internalGet(DAY_OF_WEEK));
		    }
		    // In lenient mode, we treat days of the previous
		    // months as a part of the specified
		    // WEEK_OF_MONTH. See 4633646.
		    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
                } else {
		    int dayOfWeek;
		    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
			dayOfWeek = internalGet(DAY_OF_WEEK);
		    } else {
			dayOfWeek = getFirstDayOfWeek();
		    }
                    // We are basing this on the day-of-week-in-month.  The only
                    // trickiness occurs if the day-of-week-in-month is
                    // negative.
		    int dowim;
		    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
			dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
		    } else {
			dowim = 1;
		    }
		    if (dowim >= 0) {
			fixedDate = jcal.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
								    dayOfWeek);
		    } else {
			// Go to the first day of the next week of
			// the specified week boundary.
			int lastDate = monthLength(month, year) + (7 * (dowim + 1));
			// Then, get the day of week date on or before the last date.
			fixedDate = jcal.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
								    dayOfWeek);
                    }
                }
            }
        } else {
	    // We are on the first day of the year.
            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
		if (isTransitionYear(date.getNormalizedYear())) {
		    fixedDate = getFixedDateJan1(date, fixedDate);
		}
		// Add the offset, then subtract 1. (Make sure to avoid underflow.)
                fixedDate += internalGet(DAY_OF_YEAR);
		fixedDate--;
            } else {
		long firstDayOfWeek = jcal.getDayOfWeekDateOnOrBefore(fixedDate + 6,
								      getFirstDayOfWeek());
		// If we have enough days in the first week, then move
		// to the previous week.
		if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
		    firstDayOfWeek -= 7;
		}
		if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
		    int dayOfWeek = internalGet(DAY_OF_WEEK);
		    if (dayOfWeek != getFirstDayOfWeek()) {
			firstDayOfWeek = jcal.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
									 dayOfWeek);
		    }
		}
		fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
            }
        }
        return fixedDate;
    
private final longgetFixedDateJan1(sun.util.calendar.LocalGregorianCalendar$Date date, long fixedDate)
Returns the fixed date of the first day of the year (usually January 1) before the specified date.

param
date the date for which the first day of the year is calculated. The date has to be in the cut-over year.
param
fixedDate the fixed date representation of the date

	Era era = date.getEra();
	if (date.getEra() != null && date.getYear() == 1) {
	    for (int eraIndex = getEraIndex(date); eraIndex > 0; eraIndex--) {
		CalendarDate d = eras[eraIndex].getSinceDate();
		long fd = gcal.getFixedDate(d);
		// There might be multiple era transitions in a year.
		if (fd > fixedDate) {
		    continue;
		}
		return fd;
	    }
	}
	CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
	d.setDate(date.getNormalizedYear(), gcal.JANUARY, 1);
	return gcal.getFixedDate(d);
    
private final longgetFixedDateMonth1(sun.util.calendar.LocalGregorianCalendar$Date date, long fixedDate)
Returns the fixed date of the first date of the month (usually the 1st of the month) before the specified date.

param
date the date for which the first day of the month is calculated. The date must be in the era transition year.
param
fixedDate the fixed date representation of the date

	int eraIndex = getTransitionEraIndex(date);
	if (eraIndex != -1) {
	    long transition = sinceFixedDates[eraIndex];
	    // If the given date is on or after the transition date, then
	    // return the transition date.
	    if (transition <= fixedDate) {
		return transition;
	    }
	}

	// Otherwise, we can use the 1st day of the month.
	return fixedDate - date.getDayOfMonth() + 1;
    
public intgetGreatestMinimum(int field)
Returns the highest minimum value for the given calendar field of this GregorianCalendar instance. The highest minimum value is defined as the largest value returned by {@link #getActualMinimum(int)} for any possible time value, taking into consideration the current values of the {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, and {@link Calendar#getTimeZone() getTimeZone} methods.

param
field the calendar field.
return
the highest minimum value for the given calendar field.
see
#getMinimum(int)
see
#getMaximum(int)
see
#getLeastMaximum(int)
see
#getActualMinimum(int)
see
#getActualMaximum(int)

        return field == YEAR ? 1 : MIN_VALUES[field];
    
private java.lang.StringgetKey(int field, int style)

	String className = JapaneseImperialCalendar.class.getName();
	StringBuilder key = new StringBuilder();
	switch (field) {
	case ERA:
	    key.append(className);
	    if (style == SHORT) {
		key.append(".short");
	    }
	    key.append(".Eras");
	    break;

	case YEAR:
	    key.append(className).append(".FirstYear");
	    break;

	case MONTH:
	    key.append(style == SHORT ? "MonthAbbreviations" : "MonthNames");
	    break;

	case DAY_OF_WEEK:
	    key.append(style == SHORT ? "DayAbbreviations" : "DayNames");
	    break;

	case AM_PM:
	    key.append("AmPmMarkers");
	    break;
	}
	return key.length() > 0 ? key.toString() : null;
    
public intgetLeastMaximum(int field)
Returns the lowest maximum value for the given calendar field of this GregorianCalendar instance. The lowest maximum value is defined as the smallest value returned by {@link #getActualMaximum(int)} for any possible time value, taking into consideration the current values of the {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, and {@link Calendar#getTimeZone() getTimeZone} methods.

param
field the calendar field
return
the lowest maximum value for the given calendar field.
see
#getMinimum(int)
see
#getMaximum(int)
see
#getGreatestMinimum(int)
see
#getActualMinimum(int)
see
#getActualMaximum(int)

	switch (field) {
	case YEAR:
	    {
		return Math.min(LEAST_MAX_VALUES[YEAR], getMaximum(YEAR));
	    }
	}
        return LEAST_MAX_VALUES[field];
    
public intgetMaximum(int field)
Returns the maximum value for the given calendar field of this GregorianCalendar instance. The maximum value is defined as the largest value returned by the {@link Calendar#get(int) get} method for any possible time value, taking into consideration the current values of the {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, and {@link Calendar#getTimeZone() getTimeZone} methods.

param
field the calendar field.
return
the maximum value for the given calendar field.
see
#getMinimum(int)
see
#getGreatestMinimum(int)
see
#getLeastMaximum(int)
see
#getActualMinimum(int)
see
#getActualMaximum(int)

	switch (field) {
	case YEAR:
	    {
		// The value should depend on the time zone of this calendar.
		LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
								     getZone());
		return Math.max(LEAST_MAX_VALUES[YEAR], d.getYear());
	    }
	}
        return MAX_VALUES[field];
    
public intgetMinimum(int field)
Returns the minimum value for the given calendar field of this Calendar instance. The minimum value is defined as the smallest value returned by the {@link Calendar#get(int) get} method for any possible time value, taking into consideration the current values of the {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek}, {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek}, and {@link Calendar#getTimeZone() getTimeZone} methods.

param
field the calendar field.
return
the minimum value for the given calendar field.
see
#getMaximum(int)
see
#getGreatestMinimum(int)
see
#getLeastMaximum(int)
see
#getActualMinimum(int)
see
#getActualMaximum(int)

        return MIN_VALUES[field];
    
private final java.util.JapaneseImperialCalendargetNormalizedCalendar()
Returns this object if it's normalized (all fields and time are in sync). Otherwise, a cloned object is returned after calling complete() in lenient mode.

	JapaneseImperialCalendar jc;
	if (isFullyNormalized()) {
	    jc = this;
	} else {
	    // Create a clone and normalize the calendar fields
	    jc = (JapaneseImperialCalendar) this.clone();
	    jc.setLenient(true);
	    jc.complete();
	}
	return jc;
    
private static final intgetRolledValue(int value, int amount, int min, int max)
Returns the new value after 'roll'ing the specified value and amount.

	assert value >= min && value <= max;
	int range = max - min + 1;
	amount %= range;
	int n = value + amount;
	if (n > max) {
	    n -= range;
	} else if (n < min) {
	    n += range;
	}
	assert n >= min && n <= max;
	return n;
    
public java.util.TimeZonegetTimeZone()

	TimeZone zone = super.getTimeZone();
	// To share the zone by the CalendarDate
	jdate.setZone(zone);
	return zone;
    
private static final intgetTransitionEraIndex(sun.util.calendar.LocalGregorianCalendar$Date date)
Returns the index to the new era if the given date is in a transition month. For example, if the give date is Heisei 1 (1989) January 20, then the era index for Heisei is returned. Likewise, if the given date is Showa 64 (1989) January 3, then the era index for Heisei is returned. If the given date is not in any transition month, then -1 is returned.

	int eraIndex = getEraIndex(date);
	CalendarDate transitionDate = eras[eraIndex].getSinceDate();
	if (transitionDate.getYear() == date.getNormalizedYear() &&
	    transitionDate.getMonth() == date.getMonth()) {
	    return eraIndex;
	}
	if (eraIndex < eras.length - 1) {
	    transitionDate = eras[++eraIndex].getSinceDate();
	    if (transitionDate.getYear() == date.getNormalizedYear() &&
		transitionDate.getMonth() == date.getMonth()) {
		return eraIndex;
	    }
	}
	return -1;
    
private final intgetWeekNumber(long fixedDay1, long fixedDate)
Returns the number of weeks in a period between fixedDay1 and fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule is applied to calculate the number of weeks.

param
fixedDay1 the fixed date of the first day of the period
param
fixedDate the fixed date of the last day of the period
return
the number of weeks of the given period

	// We can always use `jcal' since Julian and Gregorian are the
	// same thing for this calculation.
	long fixedDay1st = jcal.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
							   getFirstDayOfWeek());
	int ndays = (int)(fixedDay1st - fixedDay1);
	assert ndays <= 7;
	if (ndays >= getMinimalDaysInFirstWeek()) {
	    fixedDay1st -= 7;
	}
	int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
	if (normalizedDayOfPeriod >= 0) {
	    return normalizedDayOfPeriod / 7 + 1;
	}
	return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
    
private final longgetYearOffsetInMillis(sun.util.calendar.CalendarDate date)
Returns the millisecond offset from the beginning of the year. In the year for Long.MIN_VALUE, it's a pseudo value beyond the limit. The given CalendarDate object must have been normalized before calling this method.

	long t = (jcal.getDayOfYear(date) - 1) * ONE_DAY;
	return t + date.getTimeOfDay() - date.getZoneOffset();
    
public inthashCode()
Generates the hash code for this JapaneseImperialCalendar object.

        return super.hashCode() ^ jdate.hashCode();
    
private final intinternalGetEra()
Returns the ERA. We need a special method for this because the default ERA is the current era, but a zero (unset) ERA means before Meiji.

        return isSet(ERA) ? internalGet(ERA) : eras.length - 1;
    
private final booleanisTransitionYear(int normalizedYear)

	for (int i = eras.length - 1; i > 0; i--) {
	    int transitionYear = eras[i].getSinceDate().getYear();
	    if (normalizedYear == transitionYear) {
		return true;
	    }
	    if (normalizedYear > transitionYear) {
		break;
	    }
	}
	return false;
    
private final intmonthLength(int month, int gregorianYear)
Returns the length of the specified month in the specified Gregorian year. The year number must be normalized.

see
#isLeapYear(int)

        return CalendarUtils.isGregorianLeapYear(gregorianYear) ?
	    GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
    
private final intmonthLength(int month)
Returns the length of the specified month in the year provided by internalGet(YEAR).

see
#isLeapYear(int)

	assert jdate.isNormalized();
        return jdate.isLeapYear() ?
	    GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
    
private final voidpinDayOfMonth(sun.util.calendar.LocalGregorianCalendar$Date date)
After adjustments such as add(MONTH), add(YEAR), we don't want the month to jump around. E.g., we don't want Jan 31 + 1 month to go to Mar 3, we want it to go to Feb 28. Adjustments which might run into this problem call this method to retain the proper month.

	int year = date.getYear();
	int dom = date.getDayOfMonth();
	if (year != getMinimum(YEAR)) {
	    date.setDayOfMonth(1);
	    jcal.normalize(date);
	    int monthLength = jcal.getMonthLength(date);
	    if (dom > monthLength) {
		date.setDayOfMonth(monthLength);
	    } else {
		date.setDayOfMonth(dom);
	    }
	    jcal.normalize(date);
	} else {
	    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
	    LocalGregorianCalendar.Date realDate = jcal.getCalendarDate(time, getZone());
	    long tod = realDate.getTimeOfDay();
	    // Use an equivalent year.
	    realDate.addYear(+400);
	    realDate.setMonth(date.getMonth());
	    realDate.setDayOfMonth(1);
	    jcal.normalize(realDate);
	    int monthLength = jcal.getMonthLength(realDate);
	    if (dom > monthLength) {
		realDate.setDayOfMonth(monthLength);
	    } else {
		if (dom < d.getDayOfMonth()) {
		    realDate.setDayOfMonth(d.getDayOfMonth());
		} else {
		    realDate.setDayOfMonth(dom);
		}
	    }
	    if (realDate.getDayOfMonth() == d.getDayOfMonth() && tod < d.getTimeOfDay()) {
		realDate.setDayOfMonth(Math.min(dom + 1, monthLength));
	    }
	    // restore the year.
	    date.setDate(year, realDate.getMonth(), realDate.getDayOfMonth());
	    // Don't normalize date here so as not to cause underflow.
	}
    
private voidreadObject(java.io.ObjectInputStream stream)
Updates internal state.

	stream.defaultReadObject();
	if (jdate == null) {
	    jdate = jcal.newCalendarDate(getZone());
	    cachedFixedDate = Long.MIN_VALUE;
	}
    
public voidroll(int field, boolean up)

        roll(field, up ? +1 : -1);
    
public voidroll(int field, int amount)
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.

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 IllegalArgumentException is thrown.

param
field the calendar field.
param
amount the signed amount to add to field.
exception
IllegalArgumentException if field is ZONE_OFFSET, DST_OFFSET, or unknown, or if any calendar fields have out-of-range values in non-lenient mode.
see
#roll(int,boolean)
see
#add(int,int)
see
#set(int,int)

	// If amount == 0, do nothing even the given field is out of
	// range. This is tested by JCK.
        if (amount == 0) {
	    return;
	}

	if (field < 0 || field >= ZONE_OFFSET) {
	    throw new IllegalArgumentException();
	}

	// Sync the time and calendar fields.
	complete();

	int min = getMinimum(field);
	int max = getMaximum(field);

        switch (field) {
	case ERA:
        case AM_PM:
        case MINUTE:
        case SECOND:
        case MILLISECOND:
            // These fields are handled simply, since they have fixed
            // minima and maxima. Other fields are complicated, since
            // the range within they must roll varies depending on the
            // date, a time zone and the era transitions.
            break;

        case HOUR:
        case HOUR_OF_DAY:
	    {
		int unit = max + 1; // 12 or 24 hours
		int h = internalGet(field);
		int nh = (h + amount) % unit;
		if (nh < 0) {
		    nh += unit;
		}
		time += ONE_HOUR * (nh - h);

		// The day might have changed, which could happen if
		// the daylight saving time transition brings it to
		// the next day, although it's very unlikely. But we
		// have to make sure not to change the larger fields.
		CalendarDate d = jcal.getCalendarDate(time, getZone());
		if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
		    d.setEra(jdate.getEra());
		    d.setDate(internalGet(YEAR),
			      internalGet(MONTH) + 1,
			      internalGet(DAY_OF_MONTH));
		    if (field == HOUR) {
			assert (internalGet(AM_PM) == PM);
			d.addHours(+12); // restore PM
		    }
		    time = jcal.getTime(d);
		}
		int hourOfDay = d.getHours();
		internalSet(field, hourOfDay % unit);
		if (field == HOUR) {
		    internalSet(HOUR_OF_DAY, hourOfDay);
		} else {
		    internalSet(AM_PM, hourOfDay / 12);
		    internalSet(HOUR, hourOfDay % 12);
		}

		// Time zone offset and/or daylight saving might have changed.
		int zoneOffset = d.getZoneOffset();
		int saving = d.getDaylightSaving();
		internalSet(ZONE_OFFSET, zoneOffset - saving);
		internalSet(DST_OFFSET, saving);
		return;
	    }

        case YEAR:
	    min = getActualMinimum(field);
	    max = getActualMaximum(field);
	    break;

        case MONTH:
            // Rolling the month involves both pinning the final value to [0, 11]
            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
            {
		if (!isTransitionYear(jdate.getNormalizedYear())) {
		    int year = jdate.getYear();
		    if (year == getMaximum(YEAR)) {
			CalendarDate jd = jcal.getCalendarDate(time, getZone());
			CalendarDate d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
			max = d.getMonth() - 1;
			int n = getRolledValue(internalGet(field), amount, min, max);
			if (n == max) {
			    // To avoid overflow, use an equivalent year.
			    jd.addYear(-400);
			    jd.setMonth(n + 1);
			    if (jd.getDayOfMonth() > d.getDayOfMonth()) {
				jd.setDayOfMonth(d.getDayOfMonth());
				jcal.normalize(jd);
			    }
			    if (jd.getDayOfMonth() == d.getDayOfMonth()
				&& jd.getTimeOfDay() > d.getTimeOfDay()) {
				jd.setMonth(n + 1);
				jd.setDayOfMonth(d.getDayOfMonth() - 1);
				jcal.normalize(jd);
				// Month may have changed by the normalization.
				n = jd.getMonth() - 1;
			    }
			    set(DAY_OF_MONTH, jd.getDayOfMonth());
			}
			set(MONTH, n);
		    } else if (year == getMinimum(YEAR)) {
			CalendarDate jd = jcal.getCalendarDate(time, getZone());
			CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
			min = d.getMonth() - 1;
			int n = getRolledValue(internalGet(field), amount, min, max);
			if (n == min) {
			    // To avoid underflow, use an equivalent year.
			    jd.addYear(+400);
			    jd.setMonth(n + 1);
			    if (jd.getDayOfMonth() < d.getDayOfMonth()) {
				jd.setDayOfMonth(d.getDayOfMonth());
				jcal.normalize(jd);
			    }
			    if (jd.getDayOfMonth() == d.getDayOfMonth()
				&& jd.getTimeOfDay() < d.getTimeOfDay()) {
				jd.setMonth(n + 1);
				jd.setDayOfMonth(d.getDayOfMonth() + 1);
				jcal.normalize(jd);
				// Month may have changed by the normalization.
				n = jd.getMonth() - 1;
			    }
			    set(DAY_OF_MONTH, jd.getDayOfMonth());
			}
			set(MONTH, n);
		    } else {
			int mon = (internalGet(MONTH) + amount) % 12;
			if (mon < 0) {
			    mon += 12;
			}
			set(MONTH, mon);
                
			// Keep the day of month in the range.  We
			// don't want to spill over into the next
			// month; e.g., we don't want jan31 + 1 mo ->
			// feb31 -> mar3.
			int monthLen = monthLength(mon);
			if (internalGet(DAY_OF_MONTH) > monthLen) {
			    set(DAY_OF_MONTH, monthLen);
			}
		    }
		} else {
		    int eraIndex = getEraIndex(jdate);
		    CalendarDate transition = null;
		    if (jdate.getYear() == 1) {
			transition = eras[eraIndex].getSinceDate();
			min = transition.getMonth() - 1;
		    } else {
			if (eraIndex < eras.length - 1) {
			    transition = eras[eraIndex + 1].getSinceDate();
			    if (transition.getYear() == jdate.getNormalizedYear()) {
				max = transition.getMonth() - 1;
				if (transition.getDayOfMonth() == 1) {
				    max--;
				}
			    }
			}
		    }

		    if (min == max) {
			// The year has only one month. No need to
			// process further. (Showa Gan-nen (year 1)
			// and the last year have only one month.)
			return;
		    }
		    int n = getRolledValue(internalGet(field), amount, min, max);
		    set(MONTH, n);
		    if (n == min) {
			if (!(transition.getMonth() == BaseCalendar.JANUARY
			      && transition.getDayOfMonth() == 1)) {
			    if (jdate.getDayOfMonth() < transition.getDayOfMonth()) {
				set(DAY_OF_MONTH, transition.getDayOfMonth());
			    }
			}
		    } else if (n == max && (transition.getMonth() - 1 == n)) {
			int dom = transition.getDayOfMonth();
			if (jdate.getDayOfMonth() >= dom) {
			    set(DAY_OF_MONTH, dom - 1);
			}
		    }
		}
		return;
            }

        case WEEK_OF_YEAR:
	    {
		int y = jdate.getNormalizedYear();
		max = getActualMaximum(WEEK_OF_YEAR);
		set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK)); // update stamp[field]
		int woy = internalGet(WEEK_OF_YEAR);
		int value = woy + amount;
		if (!isTransitionYear(jdate.getNormalizedYear())) {
		    int year = jdate.getYear();
		    if (year == getMaximum(YEAR)) {
			max = getActualMaximum(WEEK_OF_YEAR);
		    } else if (year == getMinimum(YEAR)) {
			min = getActualMinimum(WEEK_OF_YEAR);
			max = getActualMaximum(WEEK_OF_YEAR);
			if (value > min && value < max) {
			    set(WEEK_OF_YEAR, value);
			    return;
			}
			
		    }
		    // If the new value is in between min and max
		    // (exclusive), then we can use the value.
		    if (value > min && value < max) {
			set(WEEK_OF_YEAR, value);
			return;
		    }
		    long fd = cachedFixedDate;
		    // Make sure that the min week has the current DAY_OF_WEEK
		    long day1 = fd - (7 * (woy - min));
		    if (year != getMinimum(YEAR)) {
			if (gcal.getYearFromFixedDate(day1) != y) {
			    min++;
			}
		    } else {
			CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
			if (day1 < jcal.getFixedDate(d)) {
			    min++;
			}
		    }

		    // Make sure the same thing for the max week
		    fd += 7 * (max - internalGet(WEEK_OF_YEAR));
		    if (gcal.getYearFromFixedDate(fd) != y) {
			max--;
		    }
		    break;
		}

		// Handle transition here.
		long fd = cachedFixedDate;
		long day1 = fd - (7 * (woy - min));
		// Make sure that the min week has the current DAY_OF_WEEK
		LocalGregorianCalendar.Date d = getCalendarDate(day1);
		if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
		    min++;
		}

		// Make sure the same thing for the max week
		fd += 7 * (max - woy);
		jcal.getCalendarDateFromFixedDate(d, fd);
		if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
		    max--;
		}
		// value: the new WEEK_OF_YEAR which must be converted
		// to month and day of month.
		value = getRolledValue(woy, amount, min, max) - 1;
		d = getCalendarDate(day1 + value * 7);
		set(MONTH, d.getMonth() - 1);
		set(DAY_OF_MONTH, d.getDayOfMonth());
		return;
	    }

        case WEEK_OF_MONTH:
	    {
		boolean isTransitionYear = isTransitionYear(jdate.getNormalizedYear());
		// dow: relative day of week from the first day of week
		int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
		if (dow < 0) {
		    dow += 7;
		}

		long fd = cachedFixedDate;
		long month1;	 // fixed date of the first day (usually 1) of the month
		int monthLength; // actual month length
		if (isTransitionYear) {
		    month1 = getFixedDateMonth1(jdate, fd);
		    monthLength = actualMonthLength();
		} else {
		    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
		    monthLength = jcal.getMonthLength(jdate);
		}

		// the first day of week of the month.
		long monthDay1st = jcal.getDayOfWeekDateOnOrBefore(month1 + 6,
								   getFirstDayOfWeek());
		// if the week has enough days to form a week, the
		// week starts from the previous month.
		if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
		    monthDay1st -= 7;
		}
		max = getActualMaximum(field);

		// value: the new WEEK_OF_MONTH value
		int value = getRolledValue(internalGet(field), amount, 1, max) - 1;

		// nfd: fixed date of the rolled date
		long nfd = monthDay1st + value * 7 + dow;

		// Unlike WEEK_OF_YEAR, we need to change day of week if the
		// nfd is out of the month.
		if (nfd < month1) {
		    nfd = month1;
		} else if (nfd >= (month1 + monthLength)) {
		    nfd = month1 + monthLength - 1;
		}
		set(DAY_OF_MONTH, (int)(nfd - month1) + 1);
		return;
	    }

        case DAY_OF_MONTH:
	    {
		if (!isTransitionYear(jdate.getNormalizedYear())) {
		    max = jcal.getMonthLength(jdate);
		    break;
		}

		// TODO: Need to change the spec to be usable DAY_OF_MONTH rolling...

		// Transition handling. We can't change year and era
		// values here due to the Calendar roll spec!
		long month1 = getFixedDateMonth1(jdate, cachedFixedDate);

		// It may not be a regular month. Convert the date and range to
		// the relative values, perform the roll, and
		// convert the result back to the rolled date.
		int value = getRolledValue((int)(cachedFixedDate - month1), amount,
					   0, actualMonthLength() - 1);
		LocalGregorianCalendar.Date d = getCalendarDate(month1 + value);
		assert getEraIndex(d) == internalGetEra()
		    && d.getYear() == internalGet(YEAR) && d.getMonth()-1 == internalGet(MONTH);
		set(DAY_OF_MONTH, d.getDayOfMonth());
		return;
	    }

        case DAY_OF_YEAR:
	    {
		max = getActualMaximum(field);
		if (!isTransitionYear(jdate.getNormalizedYear())) {
		    break;
		}

		// Handle transition. We can't change year and era values
		// here due to the Calendar roll spec.
		int value = getRolledValue(internalGet(DAY_OF_YEAR), amount, min, max);
		long jan0 = cachedFixedDate - internalGet(DAY_OF_YEAR);
		LocalGregorianCalendar.Date d = getCalendarDate(jan0 + value);
		assert getEraIndex(d) == internalGetEra() && d.getYear() == internalGet(YEAR);
		set(MONTH, d.getMonth() - 1);
		set(DAY_OF_MONTH, d.getDayOfMonth());
		return;
	    }

        case DAY_OF_WEEK:
	    {
		int normalizedYear = jdate.getNormalizedYear();
		if (!isTransitionYear(normalizedYear) && !isTransitionYear(normalizedYear - 1)) {
		    // If the week of year is in the same year, we can
		    // just change DAY_OF_WEEK.
		    int weekOfYear = internalGet(WEEK_OF_YEAR);
		    if (weekOfYear > 1 && weekOfYear < 52) {
			set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
			max = SATURDAY;
			break;
		    }
		}

		// We need to handle it in a different way around year
		// boundaries and in the transition year. Note that
		// changing era and year values violates the roll
		// rule: not changing larger calendar fields...
		amount %= 7;
		if (amount == 0) {
		    return;
		}
		long fd = cachedFixedDate;
		long dowFirst = jcal.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
		fd += amount;
		if (fd < dowFirst) {
		    fd += 7;
		} else if (fd >= dowFirst + 7) {
		    fd -= 7;
		}
		LocalGregorianCalendar.Date d = getCalendarDate(fd);
		set(ERA, getEraIndex(d));
		set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
		return;
	    }

        case DAY_OF_WEEK_IN_MONTH:
            {
		min = 1; // after having normalized, min should be 1.
		if (!isTransitionYear(jdate.getNormalizedYear())) {
		    int dom = internalGet(DAY_OF_MONTH);
		    int monthLength = jcal.getMonthLength(jdate);
		    int lastDays = monthLength % 7;
		    max = monthLength / 7;
		    int x = (dom - 1) % 7;
		    if (x < lastDays) {
			max++;
		    }
		    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
		    break;
		}

		// Transition year handling.
		long fd = cachedFixedDate;
		long month1 = getFixedDateMonth1(jdate, fd);
		int monthLength = actualMonthLength();
		int lastDays = monthLength % 7;
		max = monthLength / 7;
		int x = (int)(fd - month1) % 7;
		if (x < lastDays) {
		    max++;
		}
		int value = getRolledValue(internalGet(field), amount, min, max) - 1;
		fd = month1 + value * 7 + x;
		LocalGregorianCalendar.Date d = getCalendarDate(fd);
		set(DAY_OF_MONTH, d.getDayOfMonth());
		return;
            }
	}

	set(field, getRolledValue(internalGet(field), amount, min, max));
    
public voidsetTimeZone(java.util.TimeZone zone)

	super.setTimeZone(zone);
	// To share the zone by the CalendarDate
	jdate.setZone(zone);