Method from java.util.GregorianCalendar Detail: |
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) {
int year = internalGet(YEAR);
if (internalGetEra() == CE) {
year += amount;
if (year > 0) {
set(YEAR, year);
} else { // year < = 0
set(YEAR, 1 - year);
// if year == 0, you get 1 BCE.
set(ERA, BCE);
}
}
else { // era == BCE
year -= amount;
if (year > 0) {
set(YEAR, year);
} else { // year < = 0
set(YEAR, 1 - year);
// if year == 0, you get 1 CE
set(ERA, CE);
}
}
pinDayOfMonth();
} else if (field == MONTH) {
int month = internalGet(MONTH) + amount;
int year = internalGet(YEAR);
int y_amount;
if (month >= 0) {
y_amount = month/12;
} else {
y_amount = (month+1)/12 - 1;
}
if (y_amount != 0) {
if (internalGetEra() == CE) {
year += y_amount;
if (year > 0) {
set(YEAR, year);
} else { // year < = 0
set(YEAR, 1 - year);
// if year == 0, you get 1 BCE
set(ERA, BCE);
}
}
else { // era == BCE
year -= y_amount;
if (year > 0) {
set(YEAR, year);
} else { // year < = 0
set(YEAR, 1 - year);
// if year == 0, you get 1 CE
set(ERA, CE);
}
}
}
if (month >= 0) {
set(MONTH, (int) (month % 12));
} else {
// month < 0
month %= 12;
if (month < 0) {
month += 12;
}
set(MONTH, JANUARY + month);
}
pinDayOfMonth();
} else if (field == ERA) {
int era = internalGet(ERA) + amount;
if (era < 0) {
era = 0;
}
if (era > 1) {
era = 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 minutes
break;
case MINUTE:
delta *= 60 * 1000; // minutes to seconds
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 = getCurrentFixedDate();
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 = getCurrentFixedDate();
// If the adjustment has changed the date, then take
// the previous one.
if (fd2 != fd) {
setTimeInMillis(time - zoneOffset);
}
}
}
}
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. |
public Object clone() {
GregorianCalendar other = (GregorianCalendar) super.clone();
other.gdate = (BaseCalendar.Date) gdate.clone();
if (cdate != null) {
if (cdate != gdate) {
other.cdate = (BaseCalendar.Date) cdate.clone();
} else {
other.cdate = other.gdate;
}
}
other.originalFields = null;
other.zoneOffsets = null;
return other;
}
|
protected void computeFields() {
int mask = 0;
if (isPartiallyNormalized()) {
// Determine which calendar fields need to be computed.
mask = getSetStateFields();
int fieldMask = ~mask & ALL_FIELDS;
// We have to call computTime in case calsys == null in
// order to set calsys and cdate. (6263644)
if (fieldMask != 0 || calsys == null) {
mask |= computeFields(fieldMask,
mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
assert mask == ALL_FIELDS;
}
} else {
mask = ALL_FIELDS;
computeFields(mask, 0);
}
// After computing all the fields, set the field state to `COMPUTED'.
setFieldsComputed(mask);
}
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. |
protected void computeTime() {
// 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();
// The year defaults to the epoch start. We don't check
// fieldMask for YEAR because YEAR is a mandatory field to
// determine the date.
int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
int era = internalGetEra();
if (era == BCE) {
year = 1 - year;
} else if (era != CE) {
// Even in lenient mode we disallow ERA values other than CE & BCE.
// (The same normalization rule as add()/roll() could be
// applied here in lenient mode. But this checking is kept
// unchanged for compatibility as of 1.5.)
throw new IllegalArgumentException("Invalid era");
}
// If year is 0 or negative, we need to set the ERA value later.
if (year < = 0 && !isSet(ERA)) {
fieldMask |= ERA_MASK;
setFieldsComputed(ERA_MASK);
}
// 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).
calculateFixedDate: {
long gfd, jfd;
if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
if (gfd >= gregorianCutoverDate) {
fixedDate = gfd;
break calculateFixedDate;
}
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
} else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
if (jfd < gregorianCutoverDate) {
fixedDate = jfd;
break calculateFixedDate;
}
gfd = jfd;
} else {
jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
}
// Now we have to determine which calendar date it is.
// If the date is relative from the beginning of the year
// in the Julian calendar, then use jfd;
if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) {
if (gregorianCutoverYear == gregorianCutoverYearJulian) {
fixedDate = jfd;
break calculateFixedDate;
} else if (year == gregorianCutoverYear) {
fixedDate = gfd;
break calculateFixedDate;
}
}
if (gfd >= gregorianCutoverDate) {
if (jfd >= gregorianCutoverDate) {
fixedDate = gfd;
} else {
// The date is in an "overlapping" period. No way
// to disambiguate it. Determine it using the
// previous date calculation.
if (calsys == gcal || calsys == null) {
fixedDate = gfd;
} else {
fixedDate = jfd;
}
}
} else {
if (jfd < gregorianCutoverDate) {
fixedDate = jfd;
} else {
// The date is in a "missing" period.
if (!isLenient()) {
throw new IllegalArgumentException("the specified date doesn't exist");
}
// Take the Julian date for compatibility, which
// will produce a Gregorian date.
fixedDate = jfd;
}
}
}
// 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 {
int gmtOffset = isFieldSet(fieldMask, ZONE_OFFSET) ?
internalGet(ZONE_OFFSET) : zone.getRawOffset();
zone.getOffsets(millis - gmtOffset, 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)) {
String s = originalFields[field] + " - > " + internalGet(field);
// Restore the original field values
System.arraycopy(originalFields, 0, fields, 0, fields.length);
throw new IllegalArgumentException(getFieldName(field) + ": " + s);
}
}
}
setFieldsNormalized(mask);
}
Converts calendar field values to the time value (millisecond
offset from the Epoch). |
public boolean equals(Object obj) {
return obj instanceof GregorianCalendar &&
super.equals(obj) &&
gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
}
Compares this GregorianCalendar to the specified
Object . The result is true if and
only if the argument is a GregorianCalendar object
that represents the same time value (millisecond offset from
the Epoch) under the same
Calendar parameters and Gregorian change date as
this object. |
public int getActualMaximum(int field) {
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);
}
GregorianCalendar gc = getNormalizedCalendar();
BaseCalendar.Date date = gc.cdate;
BaseCalendar cal = gc.calsys;
int normalizedYear = date.getNormalizedYear();
int value = -1;
switch (field) {
case MONTH:
{
if (!gc.isCutoverYear(normalizedYear)) {
value = DECEMBER;
break;
}
// January 1 of the next year may or may not exist.
long nextJan1;
do {
nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
} while (nextJan1 < gregorianCutoverDate);
BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
value = d.getMonth() - 1;
}
break;
case DAY_OF_MONTH:
{
value = cal.getMonthLength(date);
if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
break;
}
// Handle cutover year.
long fd = gc.getCurrentFixedDate();
if (fd >= gregorianCutoverDate) {
break;
}
int monthLength = gc.actualMonthLength();
long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
// Convert the fixed date to its calendar date.
BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
value = d.getDayOfMonth();
}
break;
case DAY_OF_YEAR:
{
if (!gc.isCutoverYear(normalizedYear)) {
value = cal.getYearLength(date);
break;
}
// Handle cutover year.
long jan1;
if (gregorianCutoverYear == gregorianCutoverYearJulian) {
BaseCalendar cocal = gc.getCutoverCalendarSystem();
jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
} else if (normalizedYear == gregorianCutoverYearJulian) {
jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
} else {
jan1 = gregorianCutoverDate;
}
// January 1 of the next year may or may not exist.
long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
if (nextJan1 < gregorianCutoverDate) {
nextJan1 = gregorianCutoverDate;
}
assert jan1 < = cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
date.getDayOfMonth(), date);
assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
date.getDayOfMonth(), date);
value = (int)(nextJan1 - jan1);
}
break;
case WEEK_OF_YEAR:
{
if (!gc.isCutoverYear(normalizedYear)) {
// Get the day of week of January 1 of the year
CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
int dayOfWeek = cal.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 (gc == this) {
gc = (GregorianCalendar) gc.clone();
}
int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
gc.set(DAY_OF_YEAR, maxDayOfYear);
value = gc.get(WEEK_OF_YEAR);
if (internalGet(YEAR) != gc.getWeekYear()) {
gc.set(DAY_OF_YEAR, maxDayOfYear - 7);
value = gc.get(WEEK_OF_YEAR);
}
}
break;
case WEEK_OF_MONTH:
{
if (!gc.isCutoverYear(normalizedYear)) {
CalendarDate d = cal.newCalendarDate(null);
d.setDate(date.getYear(), date.getMonth(), 1);
int dayOfWeek = cal.getDayOfWeek(d);
int monthLength = cal.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++;
}
}
break;
}
// Cutover year handling
if (gc == this) {
gc = (GregorianCalendar) gc.clone();
}
int y = gc.internalGet(YEAR);
int m = gc.internalGet(MONTH);
do {
value = gc.get(WEEK_OF_MONTH);
gc.add(WEEK_OF_MONTH, +1);
} while (gc.get(YEAR) == y && gc.get(MONTH) == m);
}
break;
case DAY_OF_WEEK_IN_MONTH:
{
// may be in the Gregorian cutover month
int ndays, dow1;
int dow = date.getDayOfWeek();
if (!gc.isCutoverYear(normalizedYear)) {
BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
ndays = cal.getMonthLength(d);
d.setDayOfMonth(1);
cal.normalize(d);
dow1 = d.getDayOfWeek();
} else {
// Let a cloned GregorianCalendar take care of the cutover cases.
if (gc == this) {
gc = (GregorianCalendar) clone();
}
ndays = gc.actualMonthLength();
gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
dow1 = gc.get(DAY_OF_WEEK);
}
int x = dow - dow1;
if (x < 0) {
x += 7;
}
ndays -= x;
value = (ndays + 6) / 7;
}
break;
case YEAR:
/* The year computation is no different, in principle, from the
* others, however, the range of possible maxima is large. In
* addition, the way we know we've exceeded the range is different.
* For these reasons, we use the special case code below to handle
* this field.
*
* The actual maxima for YEAR depend on the type of calendar:
*
* Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
* Julian = Dec 2, 292269055 BCE - Jan 3, 292272993 CE
* Hybrid = Dec 2, 292269055 BCE - Aug 17, 292278994 CE
*
* We know we've exceeded the maximum when either the month, date,
* time, or era changes in response to setting the year. We don't
* check for month, date, and time here because the year and era are
* sufficient to detect an invalid year setting. NOTE: If code is
* added to check the month and date in the future for some reason,
* Feb 29 must be allowed to shift to Mar 1 when setting the year.
*/
{
if (gc == this) {
gc = (GregorianCalendar) clone();
}
// Calculate the millisecond offset from the beginning
// of the year of this calendar and adjust the max
// year value if we are beyond the limit in the max
// year.
long current = gc.getYearOffsetInMillis();
if (gc.internalGetEra() == CE) {
gc.setTimeInMillis(Long.MAX_VALUE);
value = gc.get(YEAR);
long maxEnd = gc.getYearOffsetInMillis();
if (current > maxEnd) {
value--;
}
} else {
CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
gcal : getJulianCalendarSystem();
CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
maxEnd *= 60;
maxEnd += d.getMinutes();
maxEnd *= 60;
maxEnd += d.getSeconds();
maxEnd *= 1000;
maxEnd += d.getMillis();
value = d.getYear();
if (value < = 0) {
assert mincal == gcal;
value = 1 - value;
}
if (current < maxEnd) {
value--;
}
}
}
break;
default:
throw new ArrayIndexOutOfBoundsException(field);
}
return value;
}
Returns the maximum value that this calendar field could have,
taking into consideration the given time value and the current
values of the
getFirstDayOfWeek ,
getMinimalDaysInFirstWeek ,
getGregorianChange and
getTimeZone methods.
For example, if the date of this instance is February 1, 2004,
the actual maximum value of the DAY_OF_MONTH field
is 29 because 2004 is a leap year, and if the date of this
instance is February 1, 2005, it's 28.
This method calculates the maximum value of WEEK_OF_YEAR based on the YEAR (calendar year) value, not the week year. Call #getWeeksInWeekYear() to get the maximum value of {@code
WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}. |
public int getActualMinimum(int field) {
if (field == DAY_OF_MONTH) {
GregorianCalendar gc = getNormalizedCalendar();
int year = gc.cdate.getNormalizedYear();
if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
BaseCalendar.Date d = getCalendarDate(month1);
return d.getDayOfMonth();
}
}
return getMinimum(field);
}
Returns the minimum value that this calendar field could have,
taking into consideration the given time value and the current
values of the
getFirstDayOfWeek ,
getMinimalDaysInFirstWeek ,
getGregorianChange and
getTimeZone methods.
For example, if the Gregorian change date is January 10,
1970 and the date of this GregorianCalendar is
January 20, 1970, the actual minimum value of the
DAY_OF_MONTH field is 10 because the previous date
of January 10, 1970 is December 27, 1996 (in the Julian
calendar). Therefore, December 28, 1969 to January 9, 1970
don't exist. |
public int getGreatestMinimum(int field) {
if (field == DAY_OF_MONTH) {
BaseCalendar.Date d = getGregorianCutoverDate();
long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
d = getCalendarDate(mon1);
return Math.max(MIN_VALUES[field], d.getDayOfMonth());
}
return MIN_VALUES[field];
}
|
public final Date getGregorianChange() {
return new Date(gregorianCutover);
}
Gets the Gregorian Calendar change date. This is the point when the
switch from Julian dates to Gregorian dates occurred. Default is
October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
calendar. |
public int getLeastMaximum(int field) {
switch (field) {
case MONTH:
case DAY_OF_MONTH:
case DAY_OF_YEAR:
case WEEK_OF_YEAR:
case WEEK_OF_MONTH:
case DAY_OF_WEEK_IN_MONTH:
case YEAR:
{
GregorianCalendar gc = (GregorianCalendar) clone();
gc.setLenient(true);
gc.setTimeInMillis(gregorianCutover);
int v1 = gc.getActualMaximum(field);
gc.setTimeInMillis(gregorianCutover-1);
int v2 = gc.getActualMaximum(field);
return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
}
}
return LEAST_MAX_VALUES[field];
}
|
public int getMaximum(int field) {
switch (field) {
case MONTH:
case DAY_OF_MONTH:
case DAY_OF_YEAR:
case WEEK_OF_YEAR:
case WEEK_OF_MONTH:
case DAY_OF_WEEK_IN_MONTH:
case YEAR:
{
// On or after Gregorian 200-3-1, Julian and Gregorian
// calendar dates are the same or Gregorian dates are
// larger (i.e., there is a "gap") after 300-3-1.
if (gregorianCutoverYear > 200) {
break;
}
// There might be "overlapping" dates.
GregorianCalendar gc = (GregorianCalendar) clone();
gc.setLenient(true);
gc.setTimeInMillis(gregorianCutover);
int v1 = gc.getActualMaximum(field);
gc.setTimeInMillis(gregorianCutover-1);
int v2 = gc.getActualMaximum(field);
return Math.max(MAX_VALUES[field], Math.max(v1, v2));
}
}
return MAX_VALUES[field];
}
|
public int getMinimum(int field) {
return MIN_VALUES[field];
}
|
public TimeZone getTimeZone() {
TimeZone zone = super.getTimeZone();
// To share the zone by CalendarDates
gdate.setZone(zone);
if (cdate != null && cdate != gdate) {
cdate.setZone(zone);
}
return zone;
}
|
public int getWeekYear() {
int year = get(YEAR); // implicitly calls complete()
if (internalGetEra() == BCE) {
year = 1 - year;
}
// Fast path for the Gregorian calendar years that are never
// affected by the Julian-Gregorian transition
if (year > gregorianCutoverYear + 1) {
int weekOfYear = internalGet(WEEK_OF_YEAR);
if (internalGet(MONTH) == JANUARY) {
if (weekOfYear >= 52) {
--year;
}
} else {
if (weekOfYear == 1) {
++year;
}
}
return year;
}
// General (slow) path
int dayOfYear = internalGet(DAY_OF_YEAR);
int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
int minimalDays = getMinimalDaysInFirstWeek();
// Quickly check the possibility of year adjustments before
// cloning this GregorianCalendar.
if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) {
return year;
}
// Create a clone to work on the calculation
GregorianCalendar cal = (GregorianCalendar) clone();
cal.setLenient(true);
// Use GMT so that intermediate date calculations won't
// affect the time of day fields.
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
// Go to the first day of the year, which is usually January 1.
cal.set(DAY_OF_YEAR, 1);
cal.complete();
// Get the first day of the first day-of-week in the year.
int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
if (delta != 0) {
if (delta < 0) {
delta += 7;
}
cal.add(DAY_OF_YEAR, delta);
}
int minDayOfYear = cal.get(DAY_OF_YEAR);
if (dayOfYear < minDayOfYear) {
if (minDayOfYear < = minimalDays) {
--year;
}
} else {
cal.set(YEAR, year + 1);
cal.set(DAY_OF_YEAR, 1);
cal.complete();
int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
if (del != 0) {
if (del < 0) {
del += 7;
}
cal.add(DAY_OF_YEAR, del);
}
minDayOfYear = cal.get(DAY_OF_YEAR) - 1;
if (minDayOfYear == 0) {
minDayOfYear = 7;
}
if (minDayOfYear >= minimalDays) {
int days = maxDayOfYear - dayOfYear + 1;
if (days < = (7 - minDayOfYear)) {
++year;
}
}
}
return year;
}
|
public int getWeeksInWeekYear() {
GregorianCalendar gc = getNormalizedCalendar();
int weekYear = gc.getWeekYear();
if (weekYear == gc.internalGet(YEAR)) {
return gc.getActualMaximum(WEEK_OF_YEAR);
}
// Use the 2nd week for calculating the max of WEEK_OF_YEAR
if (gc == this) {
gc = (GregorianCalendar) gc.clone();
}
gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
return gc.getActualMaximum(WEEK_OF_YEAR);
}
Returns the number of weeks in the week year
represented by this {@code GregorianCalendar}.
For example, if this {@code GregorianCalendar}'s date is
December 31, 2008 with the ISO
8601 compatible setting, this method will return 53 for the
period: December 29, 2008 to January 3, 2010 while getActualMaximum(WEEK_OF_YEAR) will return
52 for the period: December 31, 2007 to December 28, 2008. |
public int hashCode() {
return super.hashCode() ^ (int)gregorianCutoverDate;
}
Generates the hash code for this GregorianCalendar object. |
public boolean isLeapYear(int year) {
if ((year & 3) != 0) {
return false;
}
if (year > gregorianCutoverYear) {
return (year%100 != 0) || (year%400 == 0); // Gregorian
}
if (year < gregorianCutoverYearJulian) {
return true; // Julian
}
boolean gregorian;
// If the given year is the Gregorian cutover year, we need to
// determine which calendar system to be applied to February in the year.
if (gregorianCutoverYear == gregorianCutoverYearJulian) {
BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
gregorian = d.getMonth() < BaseCalendar.MARCH;
} else {
gregorian = year == gregorianCutoverYear;
}
return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
}
Determines if the given year is a leap year. Returns true if
the given year is a leap year. To specify BC year numbers,
1 - year number must be given. For example, year BC 4 is
specified as -3. |
public final boolean isWeekDateSupported() {
return true;
}
Returns {@code true} indicating this {@code GregorianCalendar}
supports week dates. |
public void roll(int field,
boolean up) {
roll(field, up ? +1 : -1);
}
Adds or subtracts (up/down) a single unit of time on the given time
field without changing larger fields.
Example: Consider a GregorianCalendar
originally set to December 31, 1999. Calling roll(Calendar.MONTH, true)
sets the calendar to January 31, 1999. The YEAR field is unchanged
because it is a larger field than MONTH . |
public void roll(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;
}
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 AM_PM:
case ERA:
case YEAR:
case MINUTE:
case SECOND:
case MILLISECOND:
// These fields are handled simply, since they have fixed minima
// and maxima. The field DAY_OF_MONTH is almost as simple. Other
// fields are complicated, since the range within they must roll
// varies depending on the date.
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 = calsys.getCalendarDate(time, getZone());
if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
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 = calsys.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 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 (!isCutoverYear(cdate.getNormalizedYear())) {
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 {
// We need to take care of different lengths in
// year and month due to the cutover.
int yearLength = getActualMaximum(MONTH) + 1;
int mon = (internalGet(MONTH) + amount) % yearLength;
if (mon < 0) {
mon += yearLength;
}
set(MONTH, mon);
int monthLen = getActualMaximum(DAY_OF_MONTH);
if (internalGet(DAY_OF_MONTH) > monthLen) {
set(DAY_OF_MONTH, monthLen);
}
}
return;
}
case WEEK_OF_YEAR:
{
int y = cdate.getNormalizedYear();
max = getActualMaximum(WEEK_OF_YEAR);
set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
int woy = internalGet(WEEK_OF_YEAR);
int value = woy + amount;
if (!isCutoverYear(y)) {
// 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 = getCurrentFixedDate();
// Make sure that the min week has the current DAY_OF_WEEK
long day1 = fd - (7 * (woy - min));
if (calsys.getYearFromFixedDate(day1) != y) {
min++;
}
// Make sure the same thing for the max week
fd += 7 * (max - internalGet(WEEK_OF_YEAR));
if (calsys.getYearFromFixedDate(fd) != y) {
max--;
}
break;
}
// Handle cutover here.
long fd = getCurrentFixedDate();
BaseCalendar cal;
if (gregorianCutoverYear == gregorianCutoverYearJulian) {
cal = getCutoverCalendarSystem();
} else if (y == gregorianCutoverYear) {
cal = gcal;
} else {
cal = getJulianCalendarSystem();
}
long day1 = fd - (7 * (woy - min));
// Make sure that the min week has the current DAY_OF_WEEK
if (cal.getYearFromFixedDate(day1) != y) {
min++;
}
// Make sure the same thing for the max week
fd += 7 * (max - woy);
cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
if (cal.getYearFromFixedDate(fd) != y) {
max--;
}
// value: the new WEEK_OF_YEAR which must be converted
// to month and day of month.
value = getRolledValue(woy, amount, min, max) - 1;
BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
set(MONTH, d.getMonth() - 1);
set(DAY_OF_MONTH, d.getDayOfMonth());
return;
}
case WEEK_OF_MONTH:
{
boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
// dow: relative day of week from first day of week
int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
if (dow < 0) {
dow += 7;
}
long fd = getCurrentFixedDate();
long month1; // fixed date of the first day (usually 1) of the month
int monthLength; // actual month length
if (isCutoverYear) {
month1 = getFixedDateMonth1(cdate, fd);
monthLength = actualMonthLength();
} else {
month1 = fd - internalGet(DAY_OF_MONTH) + 1;
monthLength = calsys.getMonthLength(cdate);
}
// the first day of week of the month.
long monthDay1st = calsys.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;
}
int dayOfMonth;
if (isCutoverYear) {
// If we are in the cutover year, convert nfd to
// its calendar date and use dayOfMonth.
BaseCalendar.Date d = getCalendarDate(nfd);
dayOfMonth = d.getDayOfMonth();
} else {
dayOfMonth = (int)(nfd - month1) + 1;
}
set(DAY_OF_MONTH, dayOfMonth);
return;
}
case DAY_OF_MONTH:
{
if (!isCutoverYear(cdate.getNormalizedYear())) {
max = calsys.getMonthLength(cdate);
break;
}
// Cutover year handling
long fd = getCurrentFixedDate();
long month1 = getFixedDateMonth1(cdate, fd);
// 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)(fd - month1), amount, 0, actualMonthLength() - 1);
BaseCalendar.Date d = getCalendarDate(month1 + value);
assert d.getMonth()-1 == internalGet(MONTH);
set(DAY_OF_MONTH, d.getDayOfMonth());
return;
}
case DAY_OF_YEAR:
{
max = getActualMaximum(field);
if (!isCutoverYear(cdate.getNormalizedYear())) {
break;
}
// Handle cutover here.
long fd = getCurrentFixedDate();
long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
set(MONTH, d.getMonth() - 1);
set(DAY_OF_MONTH, d.getDayOfMonth());
return;
}
case DAY_OF_WEEK:
{
if (!isCutoverYear(cdate.getNormalizedYear())) {
// 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, weekOfYear); // update stamp[WEEK_OF_YEAR]
max = SATURDAY;
break;
}
}
// We need to handle it in a different way around year
// boundaries and in the cutover 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 = getCurrentFixedDate();
long dowFirst = calsys.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
fd += amount;
if (fd < dowFirst) {
fd += 7;
} else if (fd >= dowFirst + 7) {
fd -= 7;
}
BaseCalendar.Date d = getCalendarDate(fd);
set(ERA, (d.getNormalizedYear() < = 0 ? BCE : CE));
set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
return;
}
case DAY_OF_WEEK_IN_MONTH:
{
min = 1; // after normalized, min should be 1.
if (!isCutoverYear(cdate.getNormalizedYear())) {
int dom = internalGet(DAY_OF_MONTH);
int monthLength = calsys.getMonthLength(cdate);
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;
}
// Cutover year handling
long fd = getCurrentFixedDate();
long month1 = getFixedDateMonth1(cdate, 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;
BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
cal.getCalendarDateFromFixedDate(d, fd);
set(DAY_OF_MONTH, d.getDayOfMonth());
return;
}
}
set(field, getRolledValue(internalGet(field), amount, min, max));
}
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 #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.
Example: Consider a GregorianCalendar
originally set to August 31, 1999. Calling roll(Calendar.MONTH,
8) sets the calendar to April 30, 1999. Using a
GregorianCalendar , the DAY_OF_MONTH field cannot
be 31 in the month April. DAY_OF_MONTH is set to the closest possible
value, 30. The YEAR field maintains the value of 1999 because it
is a larger field than MONTH .
Example: Consider a GregorianCalendar
originally set to Sunday June 6, 1999. Calling
roll(Calendar.WEEK_OF_MONTH, -1) sets the calendar to
Tuesday June 1, 1999, whereas calling
add(Calendar.WEEK_OF_MONTH, -1) sets the calendar to
Sunday May 30, 1999. This is because the roll rule imposes an
additional constraint: The MONTH must not change when the
WEEK_OF_MONTH is rolled. Taken together with add rule 1,
the resultant date must be between Tuesday June 1 and Saturday June
5. According to add rule 2, the DAY_OF_WEEK , an invariant
when changing the WEEK_OF_MONTH , is set to Tuesday, the
closest possible value to Sunday (where Sunday is the first day of the
week). |
public void setGregorianChange(Date date) {
long cutoverTime = date.getTime();
if (cutoverTime == gregorianCutover) {
return;
}
// Before changing the cutover date, make sure to have the
// time of this calendar.
complete();
setGregorianChange(cutoverTime);
}
Sets the GregorianCalendar change date. This is the point when the switch
from Julian dates to Gregorian dates occurred. Default is October 15,
1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
To obtain a pure Julian calendar, set the change date to
Date(Long.MAX_VALUE) . To obtain a pure Gregorian calendar,
set the change date to Date(Long.MIN_VALUE) . |
public void setTimeZone(TimeZone zone) {
super.setTimeZone(zone);
// To share the zone by CalendarDates
gdate.setZone(zone);
if (cdate != null && cdate != gdate) {
cdate.setZone(zone);
}
}
|
public void setWeekDate(int weekYear,
int weekOfYear,
int dayOfWeek) {
if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {
throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek);
}
// To avoid changing the time of day fields by date
// calculations, use a clone with the GMT time zone.
GregorianCalendar gc = (GregorianCalendar) clone();
gc.setLenient(true);
int era = gc.get(ERA);
gc.clear();
gc.setTimeZone(TimeZone.getTimeZone("GMT"));
gc.set(ERA, era);
gc.set(YEAR, weekYear);
gc.set(WEEK_OF_YEAR, 1);
gc.set(DAY_OF_WEEK, getFirstDayOfWeek());
int days = dayOfWeek - getFirstDayOfWeek();
if (days < 0) {
days += 7;
}
days += 7 * (weekOfYear - 1);
if (days != 0) {
gc.add(DAY_OF_YEAR, days);
} else {
gc.complete();
}
if (!isLenient() &&
(gc.getWeekYear() != weekYear
|| gc.internalGet(WEEK_OF_YEAR) != weekOfYear
|| gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) {
throw new IllegalArgumentException();
}
set(ERA, gc.internalGet(ERA));
set(YEAR, gc.internalGet(YEAR));
set(MONTH, gc.internalGet(MONTH));
set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH));
// to avoid throwing an IllegalArgumentException in
// non-lenient, set WEEK_OF_YEAR internally
internalSet(WEEK_OF_YEAR, weekOfYear);
complete();
}
Sets this {@code GregorianCalendar} to the date given by the
date specifiers - {@code weekYear},
{@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear}
follows the {@code WEEK_OF_YEAR}
numbering. The {@code dayOfWeek} value must be one of the
DAY_OF_WEEK values: SUNDAY to SATURDAY .
Note that the numeric day-of-week representation differs from
the ISO 8601 standard, and that the {@code weekOfYear}
numbering is compatible with the standard when {@code
getFirstDayOfWeek()} is {@code MONDAY} and {@code
getMinimalDaysInFirstWeek()} is 4.
Unlike the {@code set} method, all of the calendar fields
and the instant of time value are calculated upon return.
If {@code weekOfYear} is out of the valid week-of-year
range in {@code weekYear}, the {@code weekYear}
and {@code weekOfYear} values are adjusted in lenient
mode, or an {@code IllegalArgumentException} is thrown in
non-lenient mode. |