165 |
private static final String bundleName = "gnu.java.locale.Calendar"; |
private static final String bundleName = "gnu.java.locale.Calendar"; |
166 |
|
|
167 |
/** |
/** |
168 |
|
* Days in the epoch. Relative Jan 1, year '0' which is not a leap year. |
169 |
|
* (although there is no year zero, this does not matter.) |
170 |
|
* This is consistent with the formula: |
171 |
|
* = (year-1)*365L + ((year-1) >> 2) |
172 |
|
* |
173 |
|
* Plus the gregorian correction: |
174 |
|
* Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.); |
175 |
|
* For a correct julian date, the correction is -2 instead. |
176 |
|
* |
177 |
|
* The gregorian cutover in 1582 was 10 days, so by calculating the |
178 |
|
* correction from year zero, we have 15 non-leap days (even centuries) |
179 |
|
* minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects |
180 |
|
* this to the correct number 10. |
181 |
|
*/ |
182 |
|
private static final int EPOCH_DAYS = 719162; |
183 |
|
|
184 |
|
/** |
185 |
* Retrieves the resource bundle. The resources should be loaded |
* Retrieves the resource bundle. The resources should be loaded |
186 |
* via this method only. Iff an application uses this method, the |
* via this method only. Iff an application uses this method, the |
187 |
* resourcebundle is required. |
* resourcebundle is required. |
343 |
*/ |
*/ |
344 |
public boolean isLeapYear(int year) |
public boolean isLeapYear(int year) |
345 |
{ |
{ |
346 |
|
// Only years divisible by 4 can be leap years |
347 |
if ((year & 3) != 0) |
if ((year & 3) != 0) |
|
// Only years divisible by 4 can be leap years |
|
348 |
return false; |
return false; |
349 |
|
|
350 |
// compute the linear day of the 29. February of that year. |
// Is the leap-day a Julian date? Then it's a leap year |
351 |
// The 13 is the number of days, that were omitted in the Gregorian |
if (! isGregorian(year, 31 + 29 - 1)) |
|
// Calender until the epoch. |
|
|
int julianDay = (((year - 1) * (365 * 4 + 1)) >> 2) |
|
|
+ (31 + 29 - (((1970 - 1) * (365 * 4 + 1)) / 4 + 1 - 13)); |
|
|
|
|
|
// If that day is smaller than the gregorianChange the julian |
|
|
// rule applies: This is a leap year since it is divisible by 4. |
|
|
if (julianDay * (24 * 60 * 60 * 1000L) < gregorianCutover) |
|
352 |
return true; |
return true; |
353 |
|
|
354 |
|
// Apply gregorian rules otherwise |
355 |
return ((year % 100) != 0 || (year % 400) == 0); |
return ((year % 100) != 0 || (year % 400) == 0); |
356 |
} |
} |
357 |
|
|
358 |
/** |
/** |
|
* Get the linear time in milliseconds since the epoch. If you |
|
|
* specify a nonpositive year it is interpreted as BC as |
|
|
* following: 0 is 1 BC, -1 is 2 BC and so on. The date is |
|
|
* interpreted as gregorian if the change occurred before that date. |
|
|
* |
|
|
* @param year the year of the date. |
|
|
* @param dayOfYear the day of year of the date; 1 based. |
|
|
* @param millis the millisecond in that day. |
|
|
* @return the days since the epoch, may be negative. |
|
|
*/ |
|
|
private long getLinearTime(int year, int dayOfYear, int millis) |
|
|
{ |
|
|
// The 13 is the number of days, that were omitted in the Gregorian |
|
|
// Calendar until the epoch. |
|
|
// We shift right by 2 instead of dividing by 4, to get correct |
|
|
// results for negative years (and this is even more efficient). |
|
|
int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear |
|
|
- ((1970 * (365 * 4 + 1)) / 4 + 1 - 13); |
|
|
long time = julianDay * (24 * 60 * 60 * 1000L) + millis; |
|
|
|
|
|
if (time >= gregorianCutover) |
|
|
{ |
|
|
// subtract the days that are missing in gregorian calendar |
|
|
// with respect to julian calendar. |
|
|
// |
|
|
// Okay, here we rely on the fact that the gregorian |
|
|
// calendar was introduced in the AD era. This doesn't work |
|
|
// with negative years. |
|
|
// |
|
|
// The additional leap year factor accounts for the fact that |
|
|
// a leap day is not seen on Jan 1 of the leap year. |
|
|
// And on and after the leap day, the leap day has already been |
|
|
// included in dayOfYear. |
|
|
int gregOffset = (year / 400) - (year / 100) + 2; |
|
|
if (isLeapYear(year, true)) |
|
|
--gregOffset; |
|
|
time += gregOffset * (24 * 60 * 60 * 1000L); |
|
|
} |
|
|
return time; |
|
|
} |
|
|
|
|
|
/** |
|
359 |
* Retrieves the day of the week corresponding to the specified |
* Retrieves the day of the week corresponding to the specified |
360 |
* day of the specified year. |
* day of the specified year. |
361 |
* |
* |
365 |
*/ |
*/ |
366 |
private int getWeekDay(int year, int dayOfYear) |
private int getWeekDay(int year, int dayOfYear) |
367 |
{ |
{ |
368 |
int day = (int) (getLinearTime(year, dayOfYear, 0) / (24 * 60 * 60 * 1000L)); |
boolean greg = isGregorian(year, dayOfYear); |
369 |
|
int day = (int) getLinearDay(year, dayOfYear, greg); |
370 |
|
|
371 |
// The epoch was a thursday. |
// The epoch was a thursday. |
372 |
int weekday = (day + THURSDAY) % 7; |
int weekday = (day + THURSDAY) % 7; |
476 |
} |
} |
477 |
|
|
478 |
/** |
/** |
479 |
|
* Takes a year, and a (zero based) day of year and determines |
480 |
|
* if it is gregorian or not. |
481 |
|
*/ |
482 |
|
private boolean isGregorian(int year, int dayOfYear) |
483 |
|
{ |
484 |
|
int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear |
485 |
|
- EPOCH_DAYS; // gregorian days from 1 to epoch. |
486 |
|
int gregFactor = (int) Math.floor((double) (year - 1) / 400.) |
487 |
|
- (int) Math.floor((double) (year - 1) / 100.); |
488 |
|
|
489 |
|
return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover); |
490 |
|
} |
491 |
|
|
492 |
|
/** |
493 |
* Converts the time field values (<code>fields</code>) to |
* Converts the time field values (<code>fields</code>) to |
494 |
* milliseconds since the epoch UTC (<code>time</code>). |
* milliseconds since the epoch UTC (<code>time</code>). |
495 |
* |
* |
498 |
*/ |
*/ |
499 |
protected synchronized void computeTime() |
protected synchronized void computeTime() |
500 |
{ |
{ |
501 |
|
int millisInDay = 0; |
502 |
int era = isSet[ERA] ? fields[ERA] : AD; |
int era = isSet[ERA] ? fields[ERA] : AD; |
503 |
int year = isSet[YEAR] ? fields[YEAR] : 1970; |
int year = isSet[YEAR] ? fields[YEAR] : 1970; |
504 |
if (isLenient() && isSet[MONTH]) |
int month = isSet[MONTH] ? fields[MONTH] : 0; |
505 |
{ |
int day = isSet[DAY_OF_MONTH] ? fields[DAY_OF_MONTH] : 1; |
506 |
int month = fields[MONTH]; |
int minute = isSet[MINUTE] ? fields[MINUTE] : 0; |
507 |
year += month / 12; |
int second = isSet[SECOND] ? fields[SECOND] : 0; |
508 |
month %= 12; |
int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0; |
509 |
if (month < 0) |
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 }; |
511 |
month += 12; |
int hour = 0; |
|
year--; |
|
|
} |
|
|
fields[MONTH] = month; |
|
|
isSet[YEAR] = true; |
|
|
fields[YEAR] = year; |
|
|
} |
|
512 |
|
|
513 |
if (era == BC) |
if (era == BC && year > 0) |
514 |
year = 1 - year; |
year = 1 - year; |
515 |
|
|
516 |
int[] daysOfYear = getDayOfYear(year); |
// should negative BC years be AD? |
517 |
|
// get the hour (but no check for validity) |
|
int hour = 0; |
|
518 |
if (isSet[HOUR_OF_DAY]) |
if (isSet[HOUR_OF_DAY]) |
519 |
hour = fields[HOUR_OF_DAY]; |
hour = fields[HOUR_OF_DAY]; |
520 |
else if (isSet[HOUR]) |
else if (isSet[HOUR]) |
528 |
hour = 0; |
hour = 0; |
529 |
} |
} |
530 |
|
|
|
int minute = isSet[MINUTE] ? fields[MINUTE] : 0; |
|
|
int second = isSet[SECOND] ? fields[SECOND] : 0; |
|
|
int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0; |
|
|
int millisInDay; |
|
|
|
|
531 |
if (isLenient()) |
if (isLenient()) |
532 |
{ |
{ |
533 |
// prevent overflow |
// Read the era,year,month,day fields and convert as appropriate. |
534 |
|
// Calculate number of milliseconds into the day |
535 |
|
// This takes care of both h, m, s, ms over/underflows. |
536 |
long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L |
long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L |
537 |
+ millis; |
+ millis; |
538 |
daysOfYear[1] += allMillis / (24 * 60 * 60 * 1000L); |
day += allMillis / (24 * 60 * 60 * 1000L); |
539 |
millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); |
millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); |
540 |
|
|
541 |
|
if (isSet[MONTH]) |
542 |
|
{ |
543 |
|
if (month < 0) |
544 |
|
{ |
545 |
|
year += (int) month / 12; |
546 |
|
month = month % 12; |
547 |
|
if (month < 0) |
548 |
|
{ |
549 |
|
month += 12; |
550 |
|
year--; |
551 |
|
} |
552 |
|
} |
553 |
|
if (month > 11) |
554 |
|
{ |
555 |
|
year += (month / 12); |
556 |
|
month = month % 12; |
557 |
|
} |
558 |
|
} |
559 |
|
|
560 |
|
if (isSet[DAY_OF_MONTH]) |
561 |
|
{ |
562 |
|
month_days[1] = isLeapYear(year) ? 29 : 28; |
563 |
|
|
564 |
|
while (day <= 0) |
565 |
|
{ |
566 |
|
if (month == 0) |
567 |
|
{ |
568 |
|
year--; |
569 |
|
month_days[1] = isLeapYear(year) ? 29 : 28; |
570 |
|
} |
571 |
|
month = (month + 11) % 12; |
572 |
|
day += month_days[month]; |
573 |
|
} |
574 |
|
while (day > month_days[month]) |
575 |
|
{ |
576 |
|
day -= (month_days[month]); |
577 |
|
month = (month + 1) % 12; |
578 |
|
if (month == 0) |
579 |
|
{ |
580 |
|
year++; |
581 |
|
month_days[1] = isLeapYear(year) ? 29 : 28; |
582 |
|
} |
583 |
|
} |
584 |
|
} |
585 |
} |
} |
586 |
else |
else |
587 |
{ |
{ |
588 |
if (hour < 0 || hour >= 24 || minute < 0 || minute > 59 || second < 0 |
// non-lenient |
589 |
|| second > 59 || millis < 0 || millis >= 1000) |
if (month < 0 || month > 11 || hour < 0 || hour >= 24 || minute < 0 |
590 |
|
|| minute > 59 || second < 0 || second > 59 || millis < 0 |
591 |
|
|| millis >= 1000) |
592 |
|
throw new IllegalArgumentException(); |
593 |
|
if (day < 1 || day > month_days[month]) |
594 |
throw new IllegalArgumentException(); |
throw new IllegalArgumentException(); |
595 |
millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis; |
millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis; |
596 |
} |
} |
|
time = getLinearTime(year, daysOfYear[0], millisInDay); |
|
597 |
|
|
598 |
// Add the relative days after calculating the linear time, to |
// ok, by here we have valid day,month,year,era and millisinday |
599 |
// get right behaviour when jumping over the gregorianCutover. |
int dayOfYear = dayCount[month] + day - 1; // (day starts on 1) |
600 |
time += daysOfYear[1] * (24 * 60 * 60 * 1000L); |
if (isLeapYear(year) && month > 1) |
601 |
|
dayOfYear++; |
602 |
|
|
603 |
|
int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear |
604 |
|
- EPOCH_DAYS; // gregorian days from 1 to epoch. |
605 |
|
int gregFactor = (int) Math.floor((double) (year - 1) / 400.) |
606 |
|
- (int) Math.floor((double) (year - 1) / 100.); |
607 |
|
|
608 |
|
if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover) |
609 |
|
relativeDay += gregFactor; |
610 |
|
else |
611 |
|
relativeDay -= 2; |
612 |
|
|
613 |
|
time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay; |
614 |
|
|
615 |
TimeZone zone = getTimeZone(); |
TimeZone zone = getTimeZone(); |
616 |
int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET] |
int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET] |
617 |
: zone.getRawOffset(); |
: zone.getRawOffset(); |
618 |
|
|
619 |
int day = (int) (time / (24 * 60 * 60 * 1000L)); |
// the epoch was a Thursday. |
620 |
millisInDay = (int) (time % (24 * 60 * 60 * 1000L)); |
int weekday = (int) (relativeDay + THURSDAY) % 7; |
621 |
if (millisInDay < 0) |
if (weekday <= 0) |
622 |
{ |
weekday += 7; |
623 |
millisInDay += (24 * 60 * 60 * 1000); |
fields[DAY_OF_WEEK] = weekday; |
|
day--; |
|
|
} |
|
624 |
|
|
|
int[] f = new int[FIELD_COUNT]; |
|
|
calculateDay(f, day, time - rawOffset >= gregorianCutover); |
|
|
year = f[YEAR]; |
|
|
int month = f[MONTH]; |
|
|
day = f[DAY_OF_MONTH]; |
|
|
int weekday = f[DAY_OF_WEEK]; |
|
625 |
int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET] |
int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET] |
626 |
: (zone.getOffset((year < 0) ? BC : AD, |
: (zone.getOffset((year < 1) ? BC : AD, |
627 |
(year < 0) ? 1 - year |
(year < 1) ? 1 - year |
628 |
: year, |
: year, |
629 |
month, day, weekday, |
month, day, weekday, |
630 |
millisInDay) |
millisInDay) |
631 |
- zone.getRawOffset()); |
- zone.getRawOffset()); |
632 |
time -= rawOffset + dstOffset; |
time -= (rawOffset + dstOffset); |
633 |
isTimeSet = true; |
isTimeSet = true; |
634 |
} |
} |
635 |
|
|
636 |
/** |
/** |
|
* <p> |
|
|
* Determines if the given year is a leap year. |
|
|
* </p> |
|
|
* <p> |
|
|
* To specify a year in the BC era, use a negative value calculated |
|
|
* as 1 - y, where y is the required year in BC. So, 1 BC is 0, |
|
|
* 2 BC is -1, 3 BC is -2, etc. |
|
|
* </p> |
|
|
* |
|
|
* @param year a year (use a negative value for BC). |
|
|
* @param gregorian if true, use the gregorian leap year rule. |
|
|
* @return true, if the given year is a leap year, false otherwise. |
|
|
*/ |
|
|
private boolean isLeapYear(int year, boolean gregorian) |
|
|
{ |
|
|
if ((year & 3) != 0) |
|
|
// Only years divisible by 4 can be leap years |
|
|
return false; |
|
|
|
|
|
if (! gregorian) |
|
|
return true; |
|
|
|
|
|
// We rely on AD area here. |
|
|
return ((year % 100) != 0 || (year % 400) == 0); |
|
|
} |
|
|
|
|
|
/** |
|
637 |
* Get the linear day in days since the epoch, using the |
* Get the linear day in days since the epoch, using the |
638 |
* Julian or Gregorian calendar as specified. If you specify a |
* Julian or Gregorian calendar as specified. If you specify a |
639 |
* nonpositive year it is interpreted as BC as following: 0 is 1 |
* nonpositive year it is interpreted as BC as following: 0 is 1 |
644 |
* @param gregorian <code>true</code>, if we should use the Gregorian rules. |
* @param gregorian <code>true</code>, if we should use the Gregorian rules. |
645 |
* @return the days since the epoch, may be negative. |
* @return the days since the epoch, may be negative. |
646 |
*/ |
*/ |
647 |
private long getLinearDay(int year, int dayOfYear, boolean gregorian) |
public long getLinearDay(int year, int dayOfYear, boolean gregorian) |
648 |
{ |
{ |
649 |
// The 13 is the number of days, that were omitted in the Gregorian |
// The 13 is the number of days, that were omitted in the Gregorian |
650 |
// Calender until the epoch. |
// Calender until the epoch. |
651 |
// We shift right by 2 instead of dividing by 4, to get correct |
// We shift right by 2 instead of dividing by 4, to get correct |
652 |
// results for negative years (and this is even more efficient). |
// results for negative years (and this is even more efficient). |
653 |
long julianDay = ((year * (365L * 4 + 1)) >> 2) + dayOfYear |
long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1) |
654 |
- ((1970 * (365 * 4 + 1)) / 4 + 1 - 13); |
- EPOCH_DAYS; // gregorian days from 1 to epoch. |
655 |
|
|
656 |
if (gregorian) |
if (gregorian) |
657 |
{ |
{ |
664 |
// |
// |
665 |
// The additional leap year factor accounts for the fact that |
// The additional leap year factor accounts for the fact that |
666 |
// a leap day is not seen on Jan 1 of the leap year. |
// a leap day is not seen on Jan 1 of the leap year. |
667 |
int gregOffset = (year / 400) - (year / 100) + 2; |
int gregOffset = (int) Math.floor((double) (year - 1) / 400.) |
668 |
if (isLeapYear(year, true) && dayOfYear < 31 + 29) |
- (int) Math.floor((double) (year - 1) / 100.); |
669 |
--gregOffset; |
|
670 |
julianDay += gregOffset; |
return julianDay + gregOffset; |
671 |
} |
} |
672 |
|
else |
673 |
|
julianDay -= 2; |
674 |
return julianDay; |
return julianDay; |
675 |
} |
} |
676 |
|
|
684 |
*/ |
*/ |
685 |
private void calculateDay(int[] fields, long day, boolean gregorian) |
private void calculateDay(int[] fields, long day, boolean gregorian) |
686 |
{ |
{ |
687 |
// the epoch is a Thursday. |
// the epoch was a Thursday. |
688 |
int weekday = (int) (day + THURSDAY) % 7; |
int weekday = (int) (day + THURSDAY) % 7; |
689 |
if (weekday <= 0) |
if (weekday <= 0) |
690 |
weekday += 7; |
weekday += 7; |
694 |
// year too big. |
// year too big. |
695 |
int year = 1970 |
int year = 1970 |
696 |
+ (int) (gregorian |
+ (int) (gregorian |
697 |
? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1) |
? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L |
698 |
: ((day - 100) * 4) / (365 * 4 + 1)); |
+ 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L)); |
699 |
if (day >= 0) |
if (day >= 0) |
700 |
year++; |
year++; |
701 |
|
|
722 |
fields[YEAR] = year; |
fields[YEAR] = year; |
723 |
} |
} |
724 |
|
|
725 |
int leapday = isLeapYear(year, gregorian) ? 1 : 0; |
int leapday = isLeapYear(year) ? 1 : 0; |
726 |
if (day <= 31 + 28 + leapday) |
if (day <= 31 + 28 + leapday) |
727 |
{ |
{ |
728 |
fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY |
fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY |
752 |
|
|
753 |
long day = localTime / (24 * 60 * 60 * 1000L); |
long day = localTime / (24 * 60 * 60 * 1000L); |
754 |
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); |
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); |
755 |
|
|
756 |
if (millisInDay < 0) |
if (millisInDay < 0) |
757 |
{ |
{ |
758 |
millisInDay += (24 * 60 * 60 * 1000); |
millisInDay += (24 * 60 * 60 * 1000); |
828 |
return (cal.getTimeInMillis() == getTimeInMillis()); |
return (cal.getTimeInMillis() == getTimeInMillis()); |
829 |
} |
} |
830 |
|
|
|
// /** |
|
|
// * Compares the given calender with this. |
|
|
// * @param o the object to that we should compare. |
|
|
// * @return true, if the given object is a calendar, and this calendar |
|
|
// * represents a smaller time than the calender o. |
|
|
// */ |
|
|
// public boolean before(Object o) { |
|
|
// if (!(o instanceof GregorianCalendar)) |
|
|
// return false; |
|
|
// GregorianCalendar cal = (GregorianCalendar) o; |
|
|
// return (cal.getTimeInMillis() < getTimeInMillis()); |
|
|
// } |
|
|
// /** |
|
|
// * Compares the given calender with this. |
|
|
// * @param o the object to that we should compare. |
|
|
// * @return true, if the given object is a calendar, and this calendar |
|
|
// * represents a bigger time than the calender o. |
|
|
// */ |
|
|
// public boolean after(Object o) { |
|
|
// if (!(o instanceof GregorianCalendar)) |
|
|
// return false; |
|
|
// GregorianCalendar cal = (GregorianCalendar) o; |
|
|
// return (cal.getTimeInMillis() > getTimeInMillis()); |
|
|
// } |
|
|
|
|
831 |
/** |
/** |
832 |
* Adds the specified amount of time to the given time field. The |
* Adds the specified amount of time to the given time field. The |
833 |
* amount may be negative to subtract the time. If the field overflows |
* amount may be negative to subtract the time. If the field overflows |