182 |
private static final int EPOCH_DAYS = 719162; |
private static final int EPOCH_DAYS = 719162; |
183 |
|
|
184 |
/** |
/** |
|
* Retrieves the resource bundle. The resources should be loaded |
|
|
* via this method only. Iff an application uses this method, the |
|
|
* resourcebundle is required. |
|
|
* |
|
|
* @param locale the locale in use for this calendar. |
|
|
* @return A resource bundle for the calendar for the specified locale. |
|
|
*/ |
|
|
private static ResourceBundle getBundle(Locale locale) |
|
|
{ |
|
|
return ResourceBundle.getBundle(bundleName, locale, |
|
|
ClassLoader.getSystemClassLoader()); |
|
|
} |
|
|
|
|
|
/** |
|
185 |
* Constructs a new GregorianCalender representing the current |
* Constructs a new GregorianCalender representing the current |
186 |
* time, using the default time zone and the default locale. |
* time, using the default time zone and the default locale. |
187 |
*/ |
*/ |
236 |
private GregorianCalendar(TimeZone zone, Locale locale, boolean unused) |
private GregorianCalendar(TimeZone zone, Locale locale, boolean unused) |
237 |
{ |
{ |
238 |
super(zone, locale); |
super(zone, locale); |
239 |
ResourceBundle rb = getBundle(locale); |
ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale, |
240 |
|
ClassLoader |
241 |
|
.getSystemClassLoader()); |
242 |
gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime(); |
gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime(); |
243 |
} |
} |
244 |
|
|
364 |
} |
} |
365 |
|
|
366 |
/** |
/** |
367 |
* <p> |
* Returns the day of the week for the first day of a given month (0..11) |
|
* Calculate the dayOfYear from the fields array. |
|
|
* The relativeDays is used, to account for weeks that begin before |
|
|
* the Gregorian change and end after it. |
|
|
* </p> |
|
|
* <p> |
|
|
* We return two values. The first is used to determine, if we |
|
|
* should use the Gregorian calendar or the Julian calendar, in order |
|
|
* to handle the change year. The second is a relative day after the given |
|
|
* day. This is necessary for week calculation in the year in |
|
|
* which the Gregorian change occurs. |
|
|
* </p> |
|
|
* |
|
|
* @param year the year, negative for BC. |
|
|
* @return an array of two integer values, the first containing a reference |
|
|
* day in the current year, the second a relative count since this reference |
|
|
* day. |
|
368 |
*/ |
*/ |
369 |
private int[] getDayOfYear(int year) |
private int getFirstDayOfMonth(int year, int month) |
370 |
{ |
{ |
371 |
if (isSet[MONTH]) |
int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; |
372 |
{ |
int dayOfYear = dayCount[month] + 1; |
|
int dayOfYear; |
|
|
if (fields[MONTH] > FEBRUARY) |
|
|
{ |
|
|
// The months after February are regular: |
|
|
// 9 is an offset found by try and error. |
|
|
dayOfYear = (fields[MONTH] * (31 + 30 + 31 + 30 + 31) - 9) / 5; |
|
|
if (isLeapYear(year)) |
|
|
dayOfYear++; |
|
|
} |
|
|
else |
|
|
dayOfYear = 31 * fields[MONTH]; |
|
|
|
|
|
if (isSet[DAY_OF_MONTH]) |
|
|
return new int[] { dayOfYear + fields[DAY_OF_MONTH], 0 }; |
|
|
if (isSet[WEEK_OF_MONTH] && isSet[DAY_OF_WEEK]) |
|
|
{ |
|
|
// the weekday of the first day in that month is: |
|
|
int weekday = getWeekDay(year, ++dayOfYear); |
|
|
|
|
|
return new int[] |
|
|
{ |
|
|
dayOfYear, |
|
|
// the day of week in the first week |
|
|
// (weeks starting on sunday) is: |
|
|
fields[DAY_OF_WEEK] - weekday |
|
|
+ // Now jump to the right week and correct the possible |
|
|
// error made by assuming sunday is the first week day. |
|
|
7 * (fields[WEEK_OF_MONTH] |
|
|
+ (fields[DAY_OF_WEEK] < getFirstDayOfWeek() ? 0 : -1) |
|
|
+ (weekday < getFirstDayOfWeek() ? -1 : 0)) |
|
|
}; |
|
|
} |
|
|
if (isSet[DAY_OF_WEEK] && isSet[DAY_OF_WEEK_IN_MONTH]) |
|
|
{ |
|
|
// the weekday of the first day in that month is: |
|
|
int weekday = getWeekDay(year, ++dayOfYear); |
|
|
return new int[] |
|
|
{ |
|
|
dayOfYear, |
|
|
fields[DAY_OF_WEEK] - weekday |
|
|
+ 7 * (fields[DAY_OF_WEEK_IN_MONTH] |
|
|
+ (fields[DAY_OF_WEEK] < weekday ? 0 : -1)) |
|
|
}; |
|
|
} |
|
|
} |
|
373 |
|
|
374 |
// MONTH + something did not succeed. |
if (month > 1) |
375 |
if (isSet[DAY_OF_YEAR]) |
if (isLeapYear(year)) |
376 |
return new int[] { 0, fields[DAY_OF_YEAR] }; |
dayOfYear++; |
377 |
|
|
378 |
if (isSet[DAY_OF_WEEK] && isSet[WEEK_OF_YEAR]) |
boolean greg = isGregorian(year, dayOfYear); |
379 |
{ |
int day = (int) getLinearDay(year, dayOfYear, greg); |
|
int dayOfYear = getMinimalDaysInFirstWeek(); |
|
|
|
|
|
// the weekday of the day, that begins the first week |
|
|
// in that year is: |
|
|
int weekday = getWeekDay(year, dayOfYear); |
|
|
|
|
|
return new int[] |
|
|
{ |
|
|
dayOfYear, |
|
|
|
|
|
// the day of week in the first week |
|
|
// (weeks starting on sunday) is: |
|
|
fields[DAY_OF_WEEK] - weekday |
|
|
// Now jump to the right week and correct the possible |
|
|
// error made by assuming sunday is the first week day. |
|
|
+ 7 * (fields[WEEK_OF_YEAR] |
|
|
+ (fields[DAY_OF_WEEK] < getFirstDayOfWeek() ? 0 : -1) |
|
|
+ (weekday < getFirstDayOfWeek() ? -1 : 0)) |
|
|
}; |
|
|
} |
|
380 |
|
|
381 |
// As last resort return Jan, 1st. |
// The epoch was a thursday. |
382 |
return new int[] { 1, 0 }; |
int weekday = (day + THURSDAY) % 7; |
383 |
|
if (weekday <= 0) |
384 |
|
weekday += 7; |
385 |
|
return weekday; |
386 |
} |
} |
387 |
|
|
388 |
/** |
/** |
400 |
} |
} |
401 |
|
|
402 |
/** |
/** |
403 |
|
* Check set fields for validity, without leniency. |
404 |
|
* |
405 |
|
* @throws IllegalArgumentException if a field is invalid |
406 |
|
*/ |
407 |
|
private void nonLeniencyCheck() throws IllegalArgumentException |
408 |
|
{ |
409 |
|
int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
410 |
|
int year = fields[YEAR]; |
411 |
|
int month = fields[MONTH]; |
412 |
|
int leap = isLeapYear(year) ? 1 : 0; |
413 |
|
|
414 |
|
if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC) |
415 |
|
throw new IllegalArgumentException("Illegal ERA."); |
416 |
|
if (isSet[YEAR] && fields[YEAR] < 1) |
417 |
|
throw new IllegalArgumentException("Illegal YEAR."); |
418 |
|
if (isSet[MONTH] && (month < 0 || month > 11)) |
419 |
|
throw new IllegalArgumentException("Illegal MONTH."); |
420 |
|
if (isSet[WEEK_OF_YEAR]) |
421 |
|
{ |
422 |
|
int daysInYear = 365 + leap; |
423 |
|
daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week |
424 |
|
int last = getFirstDayOfMonth(year, 11) + 4; |
425 |
|
if (last > 7) |
426 |
|
last -= 7; |
427 |
|
daysInYear += 7 - last; |
428 |
|
int weeks = daysInYear / 7; |
429 |
|
if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks) |
430 |
|
throw new IllegalArgumentException("Illegal WEEK_OF_YEAR."); |
431 |
|
} |
432 |
|
|
433 |
|
if (isSet[WEEK_OF_MONTH]) |
434 |
|
{ |
435 |
|
int weeks = (month == 1 && leap == 0) ? 4 : 5; |
436 |
|
if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks) |
437 |
|
throw new IllegalArgumentException("Illegal WEEK_OF_MONTH."); |
438 |
|
} |
439 |
|
|
440 |
|
if (isSet[DAY_OF_MONTH]) |
441 |
|
if (fields[DAY_OF_MONTH] < 1 |
442 |
|
|| fields[DAY_OF_MONTH] > month_days[month] |
443 |
|
+ ((month == 1) ? leap : 0)) |
444 |
|
throw new IllegalArgumentException("Illegal DAY_OF_MONTH."); |
445 |
|
|
446 |
|
if (isSet[DAY_OF_YEAR] |
447 |
|
&& (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap)) |
448 |
|
throw new IllegalArgumentException("Illegal DAY_OF_YEAR."); |
449 |
|
|
450 |
|
if (isSet[DAY_OF_WEEK] |
451 |
|
&& (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) |
452 |
|
throw new IllegalArgumentException("Illegal DAY_OF_WEEK."); |
453 |
|
|
454 |
|
if (isSet[DAY_OF_WEEK_IN_MONTH]) |
455 |
|
{ |
456 |
|
int weeks = (month == 1 && leap == 0) ? 4 : 5; |
457 |
|
if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks |
458 |
|
|| fields[DAY_OF_WEEK_IN_MONTH] > weeks) |
459 |
|
throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH."); |
460 |
|
} |
461 |
|
|
462 |
|
if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) |
463 |
|
throw new IllegalArgumentException("Illegal AM_PM."); |
464 |
|
if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 12)) |
465 |
|
throw new IllegalArgumentException("Illegal HOUR."); |
466 |
|
if (isSet[HOUR_OF_DAY] |
467 |
|
&& (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23)) |
468 |
|
throw new IllegalArgumentException("Illegal HOUR_OF_DAY."); |
469 |
|
if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) |
470 |
|
throw new IllegalArgumentException("Illegal MINUTE."); |
471 |
|
if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) |
472 |
|
throw new IllegalArgumentException("Illegal SECOND."); |
473 |
|
if (isSet[MILLISECOND] |
474 |
|
&& (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) |
475 |
|
throw new IllegalArgumentException("Illegal MILLISECOND."); |
476 |
|
if (isSet[ZONE_OFFSET] |
477 |
|
&& (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L |
478 |
|
|| fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L)) |
479 |
|
throw new IllegalArgumentException("Illegal ZONE_OFFSET."); |
480 |
|
if (isSet[DST_OFFSET] |
481 |
|
&& (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L |
482 |
|
|| fields[DST_OFFSET] > 12 * 60 * 60 * 1000L)) |
483 |
|
throw new IllegalArgumentException("Illegal DST_OFFSET."); |
484 |
|
} |
485 |
|
|
486 |
|
/** |
487 |
* Converts the time field values (<code>fields</code>) to |
* Converts the time field values (<code>fields</code>) to |
488 |
* milliseconds since the epoch UTC (<code>time</code>). |
* milliseconds since the epoch UTC (<code>time</code>). |
489 |
* |
* |
492 |
*/ |
*/ |
493 |
protected synchronized void computeTime() |
protected synchronized void computeTime() |
494 |
{ |
{ |
495 |
|
// 1 YEAR + MONTH + DAY_OF_MONTH |
496 |
|
// 2 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK |
497 |
|
// 3 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK |
498 |
|
// 4 YEAR + DAY_OF_YEAR |
499 |
|
// 5 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR |
500 |
int millisInDay = 0; |
int millisInDay = 0; |
501 |
int era = isSet[ERA] ? fields[ERA] : AD; |
int era = fields[ERA]; |
502 |
int year = isSet[YEAR] ? fields[YEAR] : 1970; |
int year = fields[YEAR]; |
503 |
int month = isSet[MONTH] ? fields[MONTH] : 0; |
int month = fields[MONTH]; |
504 |
int day = isSet[DAY_OF_MONTH] ? fields[DAY_OF_MONTH] : 1; |
int day = fields[DAY_OF_MONTH]; |
505 |
int minute = isSet[MINUTE] ? fields[MINUTE] : 0; |
|
506 |
int second = isSet[SECOND] ? fields[SECOND] : 0; |
int minute = fields[MINUTE]; |
507 |
int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0; |
int second = fields[SECOND]; |
508 |
|
int millis = fields[MILLISECOND]; |
509 |
int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
510 |
int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; |
int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; |
511 |
int hour = 0; |
int hour = 0; |
512 |
|
|
513 |
|
if (! isLenient()) |
514 |
|
nonLeniencyCheck(); |
515 |
|
|
516 |
|
if (! isSet[MONTH]) |
517 |
|
{ |
518 |
|
if (isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]) |
519 |
|
{ // case 5 |
520 |
|
int first = getFirstDayOfMonth(year, 0); |
521 |
|
int offs; |
522 |
|
if ((8 - first) >= getMinimalDaysInFirstWeek()) |
523 |
|
// start counting on first week |
524 |
|
offs = 1; |
525 |
|
else |
526 |
|
offs = 1 + (8 - first); |
527 |
|
|
528 |
|
month = 0; |
529 |
|
day = offs + 7 * (fields[WEEK_OF_YEAR] - 1); |
530 |
|
day += fields[DAY_OF_WEEK] - first; |
531 |
|
} |
532 |
|
else |
533 |
|
{ // case 4 |
534 |
|
month = 0; |
535 |
|
day = fields[DAY_OF_YEAR]; |
536 |
|
} |
537 |
|
} |
538 |
|
else |
539 |
|
{ |
540 |
|
if (isSet[DAY_OF_WEEK]) |
541 |
|
{ |
542 |
|
int first = getFirstDayOfMonth(year, month); |
543 |
|
|
544 |
|
if (isSet[DAY_OF_WEEK_IN_MONTH]) |
545 |
|
{ // case 3 |
546 |
|
int offs = fields[DAY_OF_WEEK] - first; |
547 |
|
if (offs < 0) |
548 |
|
offs += 7; |
549 |
|
day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1); |
550 |
|
day += offs; |
551 |
|
} |
552 |
|
else |
553 |
|
{ // case 2 |
554 |
|
day = 1 + 7 * (fields[WEEK_OF_MONTH] - 1); |
555 |
|
day += fields[DAY_OF_WEEK] - first; |
556 |
|
} |
557 |
|
} |
558 |
|
|
559 |
|
// case 1 |
560 |
|
} |
561 |
if (era == BC && year > 0) |
if (era == BC && year > 0) |
562 |
year = 1 - year; |
year = 1 - year; |
563 |
|
|
564 |
|
// rest of code assumes day/month/year set |
565 |
// should negative BC years be AD? |
// should negative BC years be AD? |
566 |
// get the hour (but no check for validity) |
// get the hour (but no check for validity) |
567 |
if (isSet[HOUR_OF_DAY]) |
if (isSet[HOUR_OF_DAY]) |
577 |
hour = 0; |
hour = 0; |
578 |
} |
} |
579 |
|
|
580 |
if (isLenient()) |
// Read the era,year,month,day fields and convert as appropriate. |
581 |
{ |
// Calculate number of milliseconds into the day |
582 |
// Read the era,year,month,day fields and convert as appropriate. |
// This takes care of both h, m, s, ms over/underflows. |
583 |
// Calculate number of milliseconds into the day |
long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis; |
584 |
// This takes care of both h, m, s, ms over/underflows. |
day += allMillis / (24 * 60 * 60 * 1000L); |
585 |
long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L |
millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); |
|
+ millis; |
|
|
day += allMillis / (24 * 60 * 60 * 1000L); |
|
|
millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); |
|
586 |
|
|
587 |
if (isSet[MONTH]) |
if (month < 0) |
588 |
|
{ |
589 |
|
year += (int) month / 12; |
590 |
|
month = month % 12; |
591 |
|
if (month < 0) |
592 |
{ |
{ |
593 |
if (month < 0) |
month += 12; |
594 |
{ |
year--; |
|
year += (int) month / 12; |
|
|
month = month % 12; |
|
|
if (month < 0) |
|
|
{ |
|
|
month += 12; |
|
|
year--; |
|
|
} |
|
|
} |
|
|
if (month > 11) |
|
|
{ |
|
|
year += (month / 12); |
|
|
month = month % 12; |
|
|
} |
|
595 |
} |
} |
596 |
|
} |
597 |
|
if (month > 11) |
598 |
|
{ |
599 |
|
year += (month / 12); |
600 |
|
month = month % 12; |
601 |
|
} |
602 |
|
|
603 |
|
month_days[1] = isLeapYear(year) ? 29 : 28; |
604 |
|
|
605 |
if (isSet[DAY_OF_MONTH]) |
while (day <= 0) |
606 |
|
{ |
607 |
|
if (month == 0) |
608 |
{ |
{ |
609 |
|
year--; |
610 |
month_days[1] = isLeapYear(year) ? 29 : 28; |
month_days[1] = isLeapYear(year) ? 29 : 28; |
|
|
|
|
while (day <= 0) |
|
|
{ |
|
|
if (month == 0) |
|
|
{ |
|
|
year--; |
|
|
month_days[1] = isLeapYear(year) ? 29 : 28; |
|
|
} |
|
|
month = (month + 11) % 12; |
|
|
day += month_days[month]; |
|
|
} |
|
|
while (day > month_days[month]) |
|
|
{ |
|
|
day -= (month_days[month]); |
|
|
month = (month + 1) % 12; |
|
|
if (month == 0) |
|
|
{ |
|
|
year++; |
|
|
month_days[1] = isLeapYear(year) ? 29 : 28; |
|
|
} |
|
|
} |
|
611 |
} |
} |
612 |
|
month = (month + 11) % 12; |
613 |
|
day += month_days[month]; |
614 |
} |
} |
615 |
else |
while (day > month_days[month]) |
616 |
{ |
{ |
617 |
// non-lenient |
day -= (month_days[month]); |
618 |
if (month < 0 || month > 11 || hour < 0 || hour >= 24 || minute < 0 |
month = (month + 1) % 12; |
619 |
|| minute > 59 || second < 0 || second > 59 || millis < 0 |
if (month == 0) |
620 |
|| millis >= 1000) |
{ |
621 |
throw new IllegalArgumentException(); |
year++; |
622 |
if (day < 1 || day > month_days[month]) |
month_days[1] = isLeapYear(year) ? 29 : 28; |
623 |
throw new IllegalArgumentException(); |
} |
|
millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis; |
|
624 |
} |
} |
625 |
|
|
626 |
// ok, by here we have valid day,month,year,era and millisinday |
// ok, by here we have valid day,month,year,era and millisinday |