in modules/luni/src/main/java/java/util/GregorianCalendar.java [695:900]
protected void computeTime() {
if (!isLenient()) {
if (isSet[HOUR_OF_DAY]) {
if (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23) {
throw new IllegalArgumentException();
}
} else if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) {
throw new IllegalArgumentException();
}
if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) {
throw new IllegalArgumentException();
}
if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) {
throw new IllegalArgumentException();
}
if (isSet[MILLISECOND]
&& (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) {
throw new IllegalArgumentException();
}
if (isSet[WEEK_OF_YEAR]
&& (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > 53)) {
throw new IllegalArgumentException();
}
if (isSet[DAY_OF_WEEK]
&& (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) {
throw new IllegalArgumentException();
}
if (isSet[DAY_OF_WEEK_IN_MONTH]
&& (fields[DAY_OF_WEEK_IN_MONTH] < 1 || fields[DAY_OF_WEEK_IN_MONTH] > 6)) {
throw new IllegalArgumentException();
}
if (isSet[WEEK_OF_MONTH]
&& (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > 6)) {
throw new IllegalArgumentException();
}
if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) {
throw new IllegalArgumentException();
}
if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) {
throw new IllegalArgumentException();
}
if (isSet[YEAR]) {
if (isSet[ERA] && fields[ERA] == BC
&& (fields[YEAR] < 1 || fields[YEAR] > 292269054)) {
throw new IllegalArgumentException();
} else if (fields[YEAR] < 1 || fields[YEAR] > 292278994) {
throw new IllegalArgumentException();
}
}
if (isSet[MONTH] && (fields[MONTH] < 0 || fields[MONTH] > 11)) {
throw new IllegalArgumentException();
}
}
long timeVal;
long hour = 0;
if (isSet[HOUR_OF_DAY] && lastTimeFieldSet != HOUR) {
hour = fields[HOUR_OF_DAY];
} else if (isSet[HOUR]) {
hour = (fields[AM_PM] * 12) + fields[HOUR];
}
timeVal = hour * 3600000;
if (isSet[MINUTE]) {
timeVal += ((long) fields[MINUTE]) * 60000;
}
if (isSet[SECOND]) {
timeVal += ((long) fields[SECOND]) * 1000;
}
if (isSet[MILLISECOND]) {
timeVal += fields[MILLISECOND];
}
long days;
int year = isSet[YEAR] ? fields[YEAR] : 1970;
if (isSet[ERA]) {
// Always test for valid ERA, even if the Calendar is lenient
if (fields[ERA] != BC && fields[ERA] != AD) {
throw new IllegalArgumentException();
}
if (fields[ERA] == BC) {
year = 1 - year;
}
}
boolean weekMonthSet = isSet[WEEK_OF_MONTH]
|| isSet[DAY_OF_WEEK_IN_MONTH];
boolean useMonth = (isSet[DATE] || isSet[MONTH] || weekMonthSet)
&& lastDateFieldSet != DAY_OF_YEAR;
if (useMonth
&& (lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_YEAR)) {
if (isSet[WEEK_OF_YEAR] && isSet[DAY_OF_WEEK]) {
useMonth = lastDateFieldSet != WEEK_OF_YEAR && weekMonthSet
&& isSet[DAY_OF_WEEK];
} else if (isSet[DAY_OF_YEAR]) {
useMonth = isSet[DATE] && isSet[MONTH];
}
}
if (useMonth) {
int month = fields[MONTH];
year += month / 12;
month %= 12;
if (month < 0) {
year--;
month += 12;
}
boolean leapYear = isLeapYear(year);
days = daysFromBaseYear(year) + daysInYear(leapYear, month);
boolean useDate = isSet[DATE];
if (useDate
&& (lastDateFieldSet == DAY_OF_WEEK
|| lastDateFieldSet == WEEK_OF_MONTH || lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) {
useDate = !(isSet[DAY_OF_WEEK] && weekMonthSet);
}
if (useDate) {
if (!isLenient()
&& (fields[DATE] < 1 || fields[DATE] > daysInMonth(
leapYear, month))) {
throw new IllegalArgumentException();
}
days += fields[DATE] - 1;
} else {
int dayOfWeek;
if (isSet[DAY_OF_WEEK]) {
dayOfWeek = fields[DAY_OF_WEEK] - 1;
} else {
dayOfWeek = getFirstDayOfWeek() - 1;
}
if (isSet[WEEK_OF_MONTH]
&& lastDateFieldSet != DAY_OF_WEEK_IN_MONTH) {
int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1));
days += (fields[WEEK_OF_MONTH] - 1) * 7
+ mod7(skew + dayOfWeek - (days - 3)) - skew;
} else if (isSet[DAY_OF_WEEK_IN_MONTH]) {
if (fields[DAY_OF_WEEK_IN_MONTH] >= 0) {
days += mod7(dayOfWeek - (days - 3))
+ (fields[DAY_OF_WEEK_IN_MONTH] - 1) * 7;
} else {
days += daysInMonth(leapYear, month)
+ mod7(dayOfWeek
- (days + daysInMonth(leapYear, month) - 3))
+ fields[DAY_OF_WEEK_IN_MONTH] * 7;
}
} else if (isSet[DAY_OF_WEEK]) {
int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1));
days += mod7(mod7(skew + dayOfWeek - (days - 3)) - skew);
}
}
} else {
boolean useWeekYear = isSet[WEEK_OF_YEAR]
&& lastDateFieldSet != DAY_OF_YEAR;
if (useWeekYear && isSet[DAY_OF_YEAR]) {
useWeekYear = isSet[DAY_OF_WEEK];
}
days = daysFromBaseYear(year);
if (useWeekYear) {
int dayOfWeek;
if (isSet[DAY_OF_WEEK]) {
dayOfWeek = fields[DAY_OF_WEEK] - 1;
} else {
dayOfWeek = getFirstDayOfWeek() - 1;
}
int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1));
days += (fields[WEEK_OF_YEAR] - 1) * 7
+ mod7(skew + dayOfWeek - (days - 3)) - skew;
if (7 - skew < getMinimalDaysInFirstWeek()) {
days += 7;
}
} else if (isSet[DAY_OF_YEAR]) {
if (!isLenient()
&& (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > (365 + (isLeapYear(year) ? 1
: 0)))) {
throw new IllegalArgumentException();
}
days += fields[DAY_OF_YEAR] - 1;
} else if (isSet[DAY_OF_WEEK]) {
days += mod7(fields[DAY_OF_WEEK] - 1 - (days - 3));
}
}
lastDateFieldSet = 0;
timeVal += days * 86400000;
// Use local time to compare with the gregorian change
if (year == changeYear
&& timeVal >= gregorianCutover + julianError() * 86400000L) {
timeVal -= julianError() * 86400000L;
}
// It is not possible to simply subtract getOffset(timeVal) from timeVal
// to get UTC.
// The trick is needed for the moment when DST transition occurs,
// say 1:00 is a transition time when DST offset becomes +1 hour,
// then wall time in the interval 1:00 - 2:00 is invalid and is
// treated as UTC time.
long timeValWithoutDST = timeVal - getOffset(timeVal)
+ getTimeZone().getRawOffset();
timeVal -= getOffset(timeValWithoutDST);
// Need to update wall time in fields, since it was invalid due to DST
// transition
this.time = timeVal;
if (timeValWithoutDST != timeVal) {
computeFields();
areFieldsSet = true;
}
}