131 |
*/ |
*/ |
132 |
public GregorianCalendar(TimeZone zone, Locale locale) |
public GregorianCalendar(TimeZone zone, Locale locale) |
133 |
{ |
{ |
134 |
|
this(zone, locale, false); |
135 |
|
setTimeInMillis(System.currentTimeMillis()); |
136 |
|
} |
137 |
|
|
138 |
|
/** |
139 |
|
* Common constructor that all constructors should call. |
140 |
|
* @param zone a time zone. |
141 |
|
* @param locale a locale. |
142 |
|
* @param unused unused parameter to make the signature differ from |
143 |
|
* the public constructor (TimeZone, Locale). |
144 |
|
*/ |
145 |
|
private GregorianCalendar(TimeZone zone, Locale locale, boolean unused) |
146 |
|
{ |
147 |
super(zone, locale); |
super(zone, locale); |
148 |
ResourceBundle rb = getBundle(locale); |
ResourceBundle rb = getBundle(locale); |
149 |
gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime(); |
gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime(); |
|
setTimeInMillis(System.currentTimeMillis()); |
|
150 |
} |
} |
151 |
|
|
152 |
/** |
/** |
158 |
*/ |
*/ |
159 |
public GregorianCalendar(int year, int month, int day) |
public GregorianCalendar(int year, int month, int day) |
160 |
{ |
{ |
161 |
super(); |
this(TimeZone.getDefault(), Locale.getDefault(), false); |
162 |
set(year, month, day); |
set(year, month, day); |
163 |
} |
} |
164 |
|
|
173 |
*/ |
*/ |
174 |
public GregorianCalendar(int year, int month, int day, int hour, int minute) |
public GregorianCalendar(int year, int month, int day, int hour, int minute) |
175 |
{ |
{ |
176 |
super(); |
this(TimeZone.getDefault(), Locale.getDefault(), false); |
177 |
set(year, month, day, hour, minute); |
set(year, month, day, hour, minute); |
178 |
} |
} |
179 |
|
|
190 |
public GregorianCalendar(int year, int month, int day, |
public GregorianCalendar(int year, int month, int day, |
191 |
int hour, int minute, int second) |
int hour, int minute, int second) |
192 |
{ |
{ |
193 |
super(); |
this(TimeZone.getDefault(), Locale.getDefault(), false); |
194 |
set(year, month, day, hour, minute, second); |
set(year, month, day, hour, minute, second); |
195 |
} |
} |
196 |
|
|
404 |
{ |
{ |
405 |
int era = isSet[ERA] ? fields[ERA] : AD; |
int era = isSet[ERA] ? fields[ERA] : AD; |
406 |
int year = isSet[YEAR] ? fields[YEAR] : 1970; |
int year = isSet[YEAR] ? fields[YEAR] : 1970; |
407 |
|
if (isLenient() && isSet[MONTH]) |
408 |
|
{ |
409 |
|
int month = fields[MONTH]; |
410 |
|
year += month / 12; |
411 |
|
month %= 12; |
412 |
|
if (month < 0) |
413 |
|
{ |
414 |
|
month += 12; |
415 |
|
year--; |
416 |
|
} |
417 |
|
fields[MONTH] = month; |
418 |
|
isSet[YEAR] = true; |
419 |
|
fields[YEAR] = year; |
420 |
|
} |
421 |
|
|
422 |
if (era == BC) |
if (era == BC) |
423 |
year = 1 - year; |
year = 1 - year; |
424 |
|
|
469 |
int rawOffset = isSet[ZONE_OFFSET] |
int rawOffset = isSet[ZONE_OFFSET] |
470 |
? fields[ZONE_OFFSET] : zone.getRawOffset(); |
? fields[ZONE_OFFSET] : zone.getRawOffset(); |
471 |
|
|
472 |
int dayOfYear = daysOfYear[0] + daysOfYear[1]; |
int day = (int) (time / (24 * 60 * 60 * 1000L)); |
473 |
// This formula isn't right, so check for month as a quick fix. |
millisInDay = (int) (time % (24 * 60 * 60 * 1000L)); |
474 |
// It doesn't compensate for leap years and puts day 30 in month 1 |
if (millisInDay < 0) |
475 |
// instead of month 0. |
{ |
476 |
int month = isSet[MONTH] |
millisInDay += (24 * 60 * 60 * 1000); |
477 |
? fields[MONTH] : (dayOfYear * 5 + 3) / (31 + 30 + 31 + 30 + 31); |
day--; |
478 |
// This formula isn't right, so check for day as a quick fix. It |
} |
479 |
// doesn't compensate for leap years, either. |
|
480 |
int day = isSet[DAY_OF_MONTH] ? fields[DAY_OF_MONTH] |
int[] f = new int[FIELD_COUNT]; |
481 |
: (6 + (dayOfYear * 5 + 3) % (31 + 30 + 31 + 30 + 31)) / 5; |
calculateDay(f, day, time - rawOffset >= gregorianCutover); |
482 |
int weekday = ((int) (time / (24 * 60 * 60 * 1000L)) + THURSDAY) % 7; |
year = f[YEAR]; |
483 |
if (weekday <= 0) |
int month = f[MONTH]; |
484 |
weekday += 7; |
day = f[DAY_OF_MONTH]; |
485 |
|
int weekday = f[DAY_OF_WEEK]; |
486 |
int dstOffset = isSet[DST_OFFSET] |
int dstOffset = isSet[DST_OFFSET] |
487 |
? fields[DST_OFFSET] : (zone.getOffset((year < 0) ? BC : AD, |
? fields[DST_OFFSET] : (zone.getOffset((year < 0) ? BC : AD, |
488 |
(year < 0) ? 1 - year : year, |
(year < 0) ? 1 - year : year, |
525 |
* @param dayOfYear the day of year of the date; 1 based. |
* @param dayOfYear the day of year of the date; 1 based. |
526 |
* @param gregorian True, if we should use Gregorian rules. |
* @param gregorian True, if we should use Gregorian rules. |
527 |
* @return the days since the epoch, may be negative. */ |
* @return the days since the epoch, may be negative. */ |
528 |
private int getLinearDay(int year, int dayOfYear, boolean gregorian) |
private long getLinearDay(int year, int dayOfYear, boolean gregorian) |
529 |
{ |
{ |
530 |
// 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 |
531 |
// Calender until the epoch. |
// Calender until the epoch. |
532 |
// 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 |
533 |
// results for negative years (and this is even more efficient). |
// results for negative years (and this is even more efficient). |
534 |
int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear - |
long julianDay = ((year * (365L * 4 + 1)) >> 2) + dayOfYear - |
535 |
((1970 * (365 * 4 + 1)) / 4 + 1 - 13); |
((1970 * (365 * 4 + 1)) / 4 + 1 - 13); |
536 |
|
|
537 |
if (gregorian) |
if (gregorian) |
559 |
* into the fields array. |
* into the fields array. |
560 |
* @param day the linear day. |
* @param day the linear day. |
561 |
*/ |
*/ |
562 |
private void calculateDay(int day, boolean gregorian) |
private void calculateDay(int[] fields, long day, boolean gregorian) |
563 |
{ |
{ |
564 |
// the epoch is a Thursday. |
// the epoch is a Thursday. |
565 |
int weekday = (day + THURSDAY) % 7; |
int weekday = (int)(day + THURSDAY) % 7; |
566 |
if (weekday <= 0) |
if (weekday <= 0) |
567 |
weekday += 7; |
weekday += 7; |
568 |
fields[DAY_OF_WEEK] = weekday; |
fields[DAY_OF_WEEK] = weekday; |
569 |
|
|
570 |
// get a first approximation of the year. This may be one |
// get a first approximation of the year. This may be one |
571 |
// year to big. |
// year too big. |
572 |
int year = 1970 + (gregorian |
int year = 1970 + (int)(gregorian |
573 |
? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1) |
? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1) |
574 |
: ((day - 100) * 4) / (365 * 4 + 1)); |
: ((day - 100) * 4) / (365 * 4 + 1)); |
575 |
if (day >= 0) |
if (day >= 0) |
576 |
year++; |
year++; |
577 |
|
|
578 |
int firstDayOfYear = getLinearDay(year, 1, gregorian); |
long firstDayOfYear = getLinearDay(year, 1, gregorian); |
579 |
|
|
580 |
// Now look in which year day really lies. |
// Now look in which year day really lies. |
581 |
if (day < firstDayOfYear) |
if (day < firstDayOfYear) |
586 |
|
|
587 |
day -= firstDayOfYear - 1; // day of year, one based. |
day -= firstDayOfYear - 1; // day of year, one based. |
588 |
|
|
589 |
fields[DAY_OF_YEAR] = day; |
fields[DAY_OF_YEAR] = (int)day; |
590 |
if (year <= 0) |
if (year <= 0) |
591 |
{ |
{ |
592 |
fields[ERA] = BC; |
fields[ERA] = BC; |
601 |
int leapday = isLeapYear(year, gregorian) ? 1 : 0; |
int leapday = isLeapYear(year, gregorian) ? 1 : 0; |
602 |
if (day <= 31 + 28 + leapday) |
if (day <= 31 + 28 + leapday) |
603 |
{ |
{ |
604 |
fields[MONTH] = day / 32; // 31->JANUARY, 32->FEBRUARY |
fields[MONTH] = (int)day / 32; // 31->JANUARY, 32->FEBRUARY |
605 |
fields[DAY_OF_MONTH] = day - 31 * fields[MONTH]; |
fields[DAY_OF_MONTH] = (int)day - 31 * fields[MONTH]; |
606 |
} |
} |
607 |
else |
else |
608 |
{ |
{ |
609 |
// A few more magic formulas |
// A few more magic formulas |
610 |
int scaledDay = (day - leapday) * 5 + 8; |
int scaledDay = ((int)day - leapday) * 5 + 8; |
611 |
fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31); |
fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31); |
612 |
fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1; |
fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1; |
613 |
} |
} |
626 |
fields[ZONE_OFFSET] = zone.getRawOffset(); |
fields[ZONE_OFFSET] = zone.getRawOffset(); |
627 |
long localTime = time + fields[ZONE_OFFSET]; |
long localTime = time + fields[ZONE_OFFSET]; |
628 |
|
|
629 |
int day = (int) (localTime / (24 * 60 * 60 * 1000L)); |
long day = localTime / (24 * 60 * 60 * 1000L); |
630 |
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); |
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); |
631 |
if (millisInDay < 0) |
if (millisInDay < 0) |
632 |
{ |
{ |
634 |
day--; |
day--; |
635 |
} |
} |
636 |
|
|
637 |
calculateDay(day, gregorian); |
calculateDay(fields, day, gregorian); |
638 |
fields[DST_OFFSET] = |
fields[DST_OFFSET] = |
639 |
zone.getOffset(fields[ERA], fields[YEAR], fields[MONTH], |
zone.getOffset(fields[ERA], fields[YEAR], fields[MONTH], |
640 |
fields[DAY_OF_MONTH], fields[DAY_OF_WEEK], |
fields[DAY_OF_MONTH], fields[DAY_OF_WEEK], |
644 |
if (millisInDay >= 24 * 60 * 60 * 1000) |
if (millisInDay >= 24 * 60 * 60 * 1000) |
645 |
{ |
{ |
646 |
millisInDay -= 24 * 60 * 60 * 1000; |
millisInDay -= 24 * 60 * 60 * 1000; |
647 |
calculateDay(++day, gregorian); |
calculateDay(fields, ++day, gregorian); |
648 |
} |
} |
649 |
|
|
650 |
fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7; |
fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7; |
737 |
* it does what you expect: Jan, 25 + 10 Days is Feb, 4. |
* it does what you expect: Jan, 25 + 10 Days is Feb, 4. |
738 |
* @param field the time field. One of the time field constants. |
* @param field the time field. One of the time field constants. |
739 |
* @param amount the amount of time. |
* @param amount the amount of time. |
740 |
|
* @exception IllegalArgumentException if <code>field</code> is |
741 |
|
* <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or invalid; or |
742 |
|
* if <code>amount</code> contains an out-of-range value and the calendar |
743 |
|
* is not in lenient mode. |
744 |
*/ |
*/ |
745 |
public void add(int field, int amount) |
public void add(int field, int amount) |
746 |
{ |
{ |
817 |
areFieldsSet = false; |
areFieldsSet = false; |
818 |
break; |
break; |
819 |
case ZONE_OFFSET: |
case ZONE_OFFSET: |
|
complete(); |
|
|
fields[ZONE_OFFSET] += amount; |
|
|
time -= amount; |
|
|
break; |
|
820 |
case DST_OFFSET: |
case DST_OFFSET: |
|
complete(); |
|
|
fields[DST_OFFSET] += amount; |
|
|
isTimeSet = false; |
|
|
break; |
|
821 |
default: |
default: |
822 |
throw new IllegalArgumentException |
throw new IllegalArgumentException("Invalid or unknown field"); |
|
("Unknown Calendar field: " + field); |
|
823 |
} |
} |
824 |
} |
} |
825 |
|
|