1:
38:
39:
40: package ;
41:
42:
43:
134: public class GregorianCalendar extends Calendar
135: {
136:
139: public static final int BC = 0;
140:
141:
144: public static final int AD = 1;
145:
146:
155: private long gregorianCutover = (new Date((24 * 60 * 60 * 1000L) * (((1582 * (365 * 4
156: + 1)) / 4
157: + (java.util.Calendar.OCTOBER * (31
158: + 30 + 31 + 30 + 31) - 9) / 5 + 5)
159: - ((1970 * (365 * 4 + 1)) / 4 + 1
160: - 13)))).getTime();
161:
162:
165: static final long serialVersionUID = -8125100834729963327L;
166:
167:
182: private static final int EPOCH_DAYS = 719162;
183:
184:
188: public GregorianCalendar()
189: {
190: this(TimeZone.getDefault(), Locale.getDefault());
191: }
192:
193:
199: public GregorianCalendar(TimeZone zone)
200: {
201: this(zone, Locale.getDefault());
202: }
203:
204:
210: public GregorianCalendar(Locale locale)
211: {
212: this(TimeZone.getDefault(), locale);
213: }
214:
215:
222: public GregorianCalendar(TimeZone zone, Locale locale)
223: {
224: this(zone, locale, false);
225: setTimeInMillis(System.currentTimeMillis());
226: complete();
227: }
228:
229:
236: private GregorianCalendar(TimeZone zone, Locale locale, boolean unused)
237: {
238: super(zone, locale);
239: }
240:
241:
249: public GregorianCalendar(int year, int month, int day)
250: {
251: this(TimeZone.getDefault(), Locale.getDefault(), false);
252: set(year, month, day);
253: }
254:
255:
265: public GregorianCalendar(int year, int month, int day, int hour, int minute)
266: {
267: this(TimeZone.getDefault(), Locale.getDefault(), false);
268: set(year, month, day, hour, minute);
269: }
270:
271:
282: public GregorianCalendar(int year, int month, int day, int hour, int minute,
283: int second)
284: {
285: this(TimeZone.getDefault(), Locale.getDefault(), false);
286: set(year, month, day, hour, minute, second);
287: }
288:
289:
297: public void setGregorianChange(Date date)
298: {
299: gregorianCutover = date.getTime();
300: }
301:
302:
307: public final Date getGregorianChange()
308: {
309: return new Date(gregorianCutover);
310: }
311:
312:
328: public boolean isLeapYear(int year)
329: {
330:
331: if ((year & 3) != 0)
332: return false;
333:
334:
335: if (! isGregorian(year, 31 + 29 - 1))
336: return true;
337:
338:
339: return ((year % 100) != 0 || (year % 400) == 0);
340: }
341:
342:
350: private int getWeekDay(int year, int dayOfYear)
351: {
352: boolean greg = isGregorian(year, dayOfYear);
353: int day = (int) getLinearDay(year, dayOfYear, greg);
354:
355:
356: int weekday = (day + THURSDAY) % 7;
357: if (weekday <= 0)
358: weekday += 7;
359: return weekday;
360: }
361:
362:
365: private int getFirstDayOfMonth(int year, int month)
366: {
367: int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
368:
369: if (month > 11)
370: {
371: year += (month / 12);
372: month = month % 12;
373: }
374:
375: if (month < 0)
376: {
377: year += (int) month / 12;
378: month = month % 12;
379: if (month < 0)
380: {
381: month += 12;
382: year--;
383: }
384: }
385:
386: int dayOfYear = dayCount[month] + 1;
387: if (month > 1)
388: if (isLeapYear(year))
389: dayOfYear++;
390:
391: boolean greg = isGregorian(year, dayOfYear);
392: int day = (int) getLinearDay(year, dayOfYear, greg);
393:
394:
395: int weekday = (day + THURSDAY) % 7;
396: if (weekday <= 0)
397: weekday += 7;
398: return weekday;
399: }
400:
401:
405: private boolean isGregorian(int year, int dayOfYear)
406: {
407: int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
408: - EPOCH_DAYS;
409: int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
410: - (int) Math.floor((double) (year - 1) / 100.);
411:
412: return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover);
413: }
414:
415:
420: private void nonLeniencyCheck() throws IllegalArgumentException
421: {
422: int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
423: int year = fields[YEAR];
424: int month = fields[MONTH];
425: int leap = isLeapYear(year) ? 1 : 0;
426:
427: if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC)
428: throw new IllegalArgumentException("Illegal ERA.");
429: if (isSet[YEAR] && fields[YEAR] < 1)
430: throw new IllegalArgumentException("Illegal YEAR.");
431: if (isSet[MONTH] && (month < 0 || month > 11))
432: throw new IllegalArgumentException("Illegal MONTH.");
433: if (isSet[WEEK_OF_YEAR])
434: {
435: int daysInYear = 365 + leap;
436: daysInYear += (getFirstDayOfMonth(year, 0) - 1);
437: int last = getFirstDayOfMonth(year, 11) + 4;
438: if (last > 7)
439: last -= 7;
440: daysInYear += 7 - last;
441: int weeks = daysInYear / 7;
442: if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks)
443: throw new IllegalArgumentException("Illegal WEEK_OF_YEAR.");
444: }
445:
446: if (isSet[WEEK_OF_MONTH])
447: {
448: int weeks = (month == 1 && leap == 0) ? 4 : 5;
449: if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks)
450: throw new IllegalArgumentException("Illegal WEEK_OF_MONTH.");
451: }
452:
453: if (isSet[DAY_OF_MONTH])
454: if (fields[DAY_OF_MONTH] < 1
455: || fields[DAY_OF_MONTH] > month_days[month]
456: + ((month == 1) ? leap : 0))
457: throw new IllegalArgumentException("Illegal DAY_OF_MONTH.");
458:
459: if (isSet[DAY_OF_YEAR]
460: && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap))
461: throw new IllegalArgumentException("Illegal DAY_OF_YEAR.");
462:
463: if (isSet[DAY_OF_WEEK]
464: && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7))
465: throw new IllegalArgumentException("Illegal DAY_OF_WEEK.");
466:
467: if (isSet[DAY_OF_WEEK_IN_MONTH])
468: {
469: int weeks = (month == 1 && leap == 0) ? 4 : 5;
470: if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks
471: || fields[DAY_OF_WEEK_IN_MONTH] > weeks)
472: throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH.");
473: }
474:
475: if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM)
476: throw new IllegalArgumentException("Illegal AM_PM.");
477: if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11))
478: throw new IllegalArgumentException("Illegal HOUR.");
479: if (isSet[HOUR_OF_DAY]
480: && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23))
481: throw new IllegalArgumentException("Illegal HOUR_OF_DAY.");
482: if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59))
483: throw new IllegalArgumentException("Illegal MINUTE.");
484: if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59))
485: throw new IllegalArgumentException("Illegal SECOND.");
486: if (isSet[MILLISECOND]
487: && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999))
488: throw new IllegalArgumentException("Illegal MILLISECOND.");
489: if (isSet[ZONE_OFFSET]
490: && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L
491: || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L))
492: throw new IllegalArgumentException("Illegal ZONE_OFFSET.");
493: if (isSet[DST_OFFSET]
494: && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L
495: || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L))
496: throw new IllegalArgumentException("Illegal DST_OFFSET.");
497: }
498:
499:
506: protected synchronized void computeTime()
507: {
508: int millisInDay = 0;
509: int era = fields[ERA];
510: int year = fields[YEAR];
511: int month = fields[MONTH];
512: int day = fields[DAY_OF_MONTH];
513:
514: int minute = fields[MINUTE];
515: int second = fields[SECOND];
516: int millis = fields[MILLISECOND];
517: int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
518: int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
519: int hour = 0;
520:
521: if (! isLenient())
522: nonLeniencyCheck();
523:
524: if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
525: {
526:
527: if (isSet[WEEK_OF_YEAR])
528: {
529: int first = getFirstDayOfMonth(year, 0);
530: int offs = 1;
531: int daysInFirstWeek = getFirstDayOfWeek() - first;
532: if (daysInFirstWeek <= 0)
533: daysInFirstWeek += 7;
534:
535: if (daysInFirstWeek < getMinimalDaysInFirstWeek())
536: offs += daysInFirstWeek;
537: else
538: offs -= 7 - daysInFirstWeek;
539: month = 0;
540: day = offs + 7 * (fields[WEEK_OF_YEAR] - 1);
541: offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
542:
543: if (offs < 0)
544: offs += 7;
545: day += offs;
546: }
547: else
548: {
549:
550: month = 0;
551: day = fields[DAY_OF_YEAR];
552: }
553: }
554: else
555: {
556: if (isSet[DAY_OF_WEEK])
557: {
558: int first = getFirstDayOfMonth(year, month);
559:
560:
561: if (isSet[DAY_OF_WEEK_IN_MONTH])
562: {
563: if (fields[DAY_OF_WEEK_IN_MONTH] < 0)
564: {
565: month++;
566: first = getFirstDayOfMonth(year, month);
567: day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]);
568: }
569: else
570: day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
571:
572: int offs = fields[DAY_OF_WEEK] - first;
573: if (offs < 0)
574: offs += 7;
575: day += offs;
576: }
577: else
578: {
579: int offs = 1;
580: int daysInFirstWeek = getFirstDayOfWeek() - first;
581: if (daysInFirstWeek <= 0)
582: daysInFirstWeek += 7;
583:
584: if (daysInFirstWeek < getMinimalDaysInFirstWeek())
585: offs += daysInFirstWeek;
586: else
587: offs -= 7 - daysInFirstWeek;
588:
589: day = offs + 7 * (fields[WEEK_OF_MONTH] - 1);
590: offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
591: if (offs <= 0)
592: offs += 7;
593: day += offs;
594: }
595: }
596:
597:
598: }
599: if (era == BC && year > 0)
600: year = 1 - year;
601:
602:
603:
604:
605: if (isSet[HOUR])
606: {
607: hour = fields[HOUR];
608: if (fields[AM_PM] == PM)
609: hour += 12;
610: }
611: else
612: hour = fields[HOUR_OF_DAY];
613:
614:
615:
616:
617: long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis;
618: day += allMillis / (24 * 60 * 60 * 1000L);
619: millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
620:
621: if (month < 0)
622: {
623: year += (int) month / 12;
624: month = month % 12;
625: if (month < 0)
626: {
627: month += 12;
628: year--;
629: }
630: }
631: if (month > 11)
632: {
633: year += (month / 12);
634: month = month % 12;
635: }
636:
637: month_days[1] = isLeapYear(year) ? 29 : 28;
638:
639: while (day <= 0)
640: {
641: if (month == 0)
642: {
643: year--;
644: month_days[1] = isLeapYear(year) ? 29 : 28;
645: }
646: month = (month + 11) % 12;
647: day += month_days[month];
648: }
649: while (day > month_days[month])
650: {
651: day -= (month_days[month]);
652: month = (month + 1) % 12;
653: if (month == 0)
654: {
655: year++;
656: month_days[1] = isLeapYear(year) ? 29 : 28;
657: }
658: }
659:
660:
661: int dayOfYear = dayCount[month] + day - 1;
662: if (isLeapYear(year) && month > 1)
663: dayOfYear++;
664:
665: int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
666: - EPOCH_DAYS;
667: int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
668: - (int) Math.floor((double) (year - 1) / 100.);
669:
670: if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover)
671: relativeDay += gregFactor;
672: else
673: relativeDay -= 2;
674:
675: time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay;
676:
677:
678: int weekday = (int) (relativeDay + THURSDAY) % 7;
679: if (weekday <= 0)
680: weekday += 7;
681: fields[DAY_OF_WEEK] = weekday;
682:
683:
684: TimeZone zone = getTimeZone();
685: int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET]
686: : zone.getRawOffset();
687:
688: int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET]
689: : (zone.getOffset((year < 0) ? BC : AD,
690: (year < 0) ? 1 - year
691: : year,
692: month, day, weekday,
693: millisInDay)
694: - zone.getRawOffset());
695:
696: time -= rawOffset + dstOffset;
697:
698: isTimeSet = true;
699: }
700:
701:
712: private long getLinearDay(int year, int dayOfYear, boolean gregorian)
713: {
714:
715:
716:
717:
718: long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1)
719: - EPOCH_DAYS;
720:
721: if (gregorian)
722: {
723:
724:
725:
726:
727:
728:
729:
730:
731:
732: int gregOffset = (int) Math.floor((double) (year - 1) / 400.)
733: - (int) Math.floor((double) (year - 1) / 100.);
734:
735: return julianDay + gregOffset;
736: }
737: else
738: julianDay -= 2;
739: return julianDay;
740: }
741:
742:
750: private void calculateDay(int[] fields, long day, boolean gregorian)
751: {
752:
753: int weekday = (int) (day + THURSDAY) % 7;
754: if (weekday <= 0)
755: weekday += 7;
756: fields[DAY_OF_WEEK] = weekday;
757:
758:
759:
760: int year = 1970
761: + (int) (gregorian
762: ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L
763: + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L));
764: if (day >= 0)
765: year++;
766:
767: long firstDayOfYear = getLinearDay(year, 1, gregorian);
768:
769:
770: if (day < firstDayOfYear)
771: {
772: year--;
773: firstDayOfYear = getLinearDay(year, 1, gregorian);
774: }
775:
776: day -= firstDayOfYear - 1;
777:
778: fields[DAY_OF_YEAR] = (int) day;
779: if (year <= 0)
780: {
781: fields[ERA] = BC;
782: fields[YEAR] = 1 - year;
783: }
784: else
785: {
786: fields[ERA] = AD;
787: fields[YEAR] = year;
788: }
789:
790: int leapday = isLeapYear(year) ? 1 : 0;
791: if (day <= 31 + 28 + leapday)
792: {
793: fields[MONTH] = (int) day / 32;
794: fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH];
795: }
796: else
797: {
798:
799: int scaledDay = ((int) day - leapday) * 5 + 8;
800: fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
801: fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
802: }
803: }
804:
805:
810: protected synchronized void computeFields()
811: {
812: boolean gregorian = (time >= gregorianCutover);
813:
814: TimeZone zone = getTimeZone();
815: fields[ZONE_OFFSET] = zone.getRawOffset();
816: long localTime = time + fields[ZONE_OFFSET];
817:
818: long day = localTime / (24 * 60 * 60 * 1000L);
819: int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
820:
821: if (millisInDay < 0)
822: {
823: millisInDay += (24 * 60 * 60 * 1000);
824: day--;
825: }
826:
827: calculateDay(fields, day, gregorian);
828: fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR],
829: fields[MONTH], fields[DAY_OF_MONTH],
830: fields[DAY_OF_WEEK], millisInDay)
831: - fields[ZONE_OFFSET];
832:
833: millisInDay += fields[DST_OFFSET];
834: if (millisInDay >= 24 * 60 * 60 * 1000)
835: {
836: millisInDay -= 24 * 60 * 60 * 1000;
837: calculateDay(fields, ++day, gregorian);
838: }
839:
840: fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
841:
842:
843: int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
844:
845: fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7;
846:
847: int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
848:
849:
850:
851: int minDays = getMinimalDaysInFirstWeek();
852: int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays)
853: - getFirstDayOfWeek()) % 7;
854: if (minDays - firstWeekday < 1)
855: weekOfYear++;
856: fields[WEEK_OF_YEAR] = weekOfYear;
857:
858: int hourOfDay = millisInDay / (60 * 60 * 1000);
859: fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
860: int hour = hourOfDay % 12;
861: fields[HOUR] = hour;
862: fields[HOUR_OF_DAY] = hourOfDay;
863: millisInDay %= (60 * 60 * 1000);
864: fields[MINUTE] = millisInDay / (60 * 1000);
865: millisInDay %= (60 * 1000);
866: fields[SECOND] = millisInDay / (1000);
867: fields[MILLISECOND] = millisInDay % 1000;
868:
869: areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] = isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] = isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] = isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] = isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
870: }
871:
872:
887: public boolean equals(Object o)
888: {
889: if (! (o instanceof GregorianCalendar))
890: return false;
891:
892: GregorianCalendar cal = (GregorianCalendar) o;
893: return (cal.getTimeInMillis() == getTimeInMillis());
894: }
895:
896:
907: public void add(int field, int amount)
908: {
909: switch (field)
910: {
911: case YEAR:
912: complete();
913: fields[YEAR] += amount;
914: isTimeSet = false;
915: break;
916: case MONTH:
917: complete();
918: int months = fields[MONTH] + amount;
919: fields[YEAR] += months / 12;
920: fields[MONTH] = months % 12;
921: if (fields[MONTH] < 0)
922: {
923: fields[MONTH] += 12;
924: fields[YEAR]--;
925: }
926: int maxDay = getActualMaximum(DAY_OF_MONTH);
927: if (fields[DAY_OF_MONTH] > maxDay)
928: fields[DAY_OF_MONTH] = maxDay;
929: set(YEAR, fields[YEAR]);
930: set(MONTH, fields[MONTH]);
931: break;
932: case DAY_OF_MONTH:
933: case DAY_OF_YEAR:
934: case DAY_OF_WEEK:
935: if (! isTimeSet)
936: computeTime();
937: time += amount * (24 * 60 * 60 * 1000L);
938: areFieldsSet = false;
939: break;
940: case WEEK_OF_YEAR:
941: case WEEK_OF_MONTH:
942: case DAY_OF_WEEK_IN_MONTH:
943: if (! isTimeSet)
944: computeTime();
945: time += amount * (7 * 24 * 60 * 60 * 1000L);
946: areFieldsSet = false;
947: break;
948: case AM_PM:
949: if (! isTimeSet)
950: computeTime();
951: time += amount * (12 * 60 * 60 * 1000L);
952: areFieldsSet = false;
953: break;
954: case HOUR:
955: case HOUR_OF_DAY:
956: if (! isTimeSet)
957: computeTime();
958: time += amount * (60 * 60 * 1000L);
959: areFieldsSet = false;
960: break;
961: case MINUTE:
962: if (! isTimeSet)
963: computeTime();
964: time += amount * (60 * 1000L);
965: areFieldsSet = false;
966: break;
967: case SECOND:
968: if (! isTimeSet)
969: computeTime();
970: time += amount * (1000L);
971: areFieldsSet = false;
972: break;
973: case MILLISECOND:
974: if (! isTimeSet)
975: computeTime();
976: time += amount;
977: areFieldsSet = false;
978: break;
979: case ZONE_OFFSET:
980: case DST_OFFSET:default:
981: throw new IllegalArgumentException("Invalid or unknown field");
982: }
983: }
984:
985:
1004: public void roll(int field, boolean up)
1005: {
1006: roll(field, up ? 1 : -1);
1007: }
1008:
1009:
1018: private void cleanUpAfterRoll(int field, int delta)
1019: {
1020: switch (field)
1021: {
1022: case ERA:
1023: case YEAR:
1024: case MONTH:
1025:
1026: if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
1027: fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
1028: isTimeSet = false;
1029: isSet[WEEK_OF_MONTH] = false;
1030: isSet[DAY_OF_WEEK] = false;
1031: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1032: isSet[DAY_OF_YEAR] = false;
1033: isSet[WEEK_OF_YEAR] = false;
1034: break;
1035: case DAY_OF_MONTH:
1036: isSet[WEEK_OF_MONTH] = false;
1037: isSet[DAY_OF_WEEK] = false;
1038: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1039: isSet[DAY_OF_YEAR] = false;
1040: isSet[WEEK_OF_YEAR] = false;
1041: time += delta * (24 * 60 * 60 * 1000L);
1042: break;
1043: case WEEK_OF_MONTH:
1044: isSet[DAY_OF_MONTH] = false;
1045: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1046: isSet[DAY_OF_YEAR] = false;
1047: isSet[WEEK_OF_YEAR] = false;
1048: time += delta * (7 * 24 * 60 * 60 * 1000L);
1049: break;
1050: case DAY_OF_WEEK_IN_MONTH:
1051: isSet[DAY_OF_MONTH] = false;
1052: isSet[WEEK_OF_MONTH] = false;
1053: isSet[DAY_OF_YEAR] = false;
1054: isSet[WEEK_OF_YEAR] = false;
1055: time += delta * (7 * 24 * 60 * 60 * 1000L);
1056: break;
1057: case DAY_OF_YEAR:
1058: isSet[MONTH] = false;
1059: isSet[DAY_OF_MONTH] = false;
1060: isSet[WEEK_OF_MONTH] = false;
1061: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1062: isSet[DAY_OF_WEEK] = false;
1063: isSet[WEEK_OF_YEAR] = false;
1064: time += delta * (24 * 60 * 60 * 1000L);
1065: break;
1066: case WEEK_OF_YEAR:
1067: isSet[MONTH] = false;
1068: isSet[DAY_OF_MONTH] = false;
1069: isSet[WEEK_OF_MONTH] = false;
1070: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1071: isSet[DAY_OF_YEAR] = false;
1072: time += delta * (7 * 24 * 60 * 60 * 1000L);
1073: break;
1074: case AM_PM:
1075: isSet[HOUR_OF_DAY] = false;
1076: time += delta * (12 * 60 * 60 * 1000L);
1077: break;
1078: case HOUR:
1079: isSet[HOUR_OF_DAY] = false;
1080: time += delta * (60 * 60 * 1000L);
1081: break;
1082: case HOUR_OF_DAY:
1083: isSet[HOUR] = false;
1084: isSet[AM_PM] = false;
1085: time += delta * (60 * 60 * 1000L);
1086: break;
1087: case MINUTE:
1088: time += delta * (60 * 1000L);
1089: break;
1090: case SECOND:
1091: time += delta * (1000L);
1092: break;
1093: case MILLISECOND:
1094: time += delta;
1095: break;
1096: }
1097: }
1098:
1099:
1117: public void roll(int field, int amount)
1118: {
1119: switch (field)
1120: {
1121: case DAY_OF_WEEK:
1122:
1123: add(field, amount);
1124: return;
1125: case ZONE_OFFSET:
1126: case DST_OFFSET:
1127: throw new IllegalArgumentException("Can't roll time zone");
1128: }
1129: complete();
1130: int min = getActualMinimum(field);
1131: int range = getActualMaximum(field) - min + 1;
1132: int oldval = fields[field];
1133: int newval = (oldval - min + range + amount) % range + min;
1134: if (newval < min)
1135: newval += range;
1136: fields[field] = newval;
1137: cleanUpAfterRoll(field, newval - oldval);
1138: }
1139:
1140:
1143: private static final int[] minimums =
1144: {
1145: BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM,
1146: 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000),
1147: 0
1148: };
1149:
1150:
1153: private static final int[] maximums =
1154: {
1155: AD, 5000000, 11, 53, 5, 31, 366,
1156: SATURDAY, 5, PM, 12, 23, 59, 59, 999,
1157: +(12 * 60 * 60 * 1000),
1158: (12 * 60 * 60 * 1000)
1159: };
1160:
1161:
1167: public int getMinimum(int field)
1168: {
1169: return minimums[field];
1170: }
1171:
1172:
1178: public int getMaximum(int field)
1179: {
1180: return maximums[field];
1181: }
1182:
1183:
1192: public int getGreatestMinimum(int field)
1193: {
1194: if (field == WEEK_OF_YEAR)
1195: return 1;
1196: return minimums[field];
1197: }
1198:
1199:
1211: public int getLeastMaximum(int field)
1212: {
1213: switch (field)
1214: {
1215: case WEEK_OF_YEAR:
1216: return 52;
1217: case DAY_OF_MONTH:
1218: return 28;
1219: case DAY_OF_YEAR:
1220: return 365;
1221: case DAY_OF_WEEK_IN_MONTH:
1222: case WEEK_OF_MONTH:
1223: return 4;
1224: default:
1225: return maximums[field];
1226: }
1227: }
1228:
1229:
1240: public int getActualMinimum(int field)
1241: {
1242: if (field == WEEK_OF_YEAR)
1243: {
1244: int min = getMinimalDaysInFirstWeek();
1245: if (min == 0)
1246: return 1;
1247: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1248: complete();
1249:
1250: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1251: int weekday = getWeekDay(year, min);
1252: if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
1253: return 1;
1254: return 0;
1255: }
1256: return minimums[field];
1257: }
1258:
1259:
1270: public int getActualMaximum(int field)
1271: {
1272: switch (field)
1273: {
1274: case WEEK_OF_YEAR:
1275: {
1276: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1277: complete();
1278:
1279:
1280:
1281:
1282: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1283: int lastDay = isLeapYear(year) ? 366 : 365;
1284: int weekday = getWeekDay(year, lastDay);
1285: int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1286:
1287: int minimalDays = getMinimalDaysInFirstWeek();
1288: int firstWeekday = getWeekDay(year, minimalDays);
1289:
1294: if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
1295: return week + 1;
1296: }
1297: case DAY_OF_MONTH:
1298: {
1299: if (! areFieldsSet || ! isSet[MONTH])
1300: complete();
1301: int month = fields[MONTH];
1302:
1303:
1304:
1305: if (month == FEBRUARY)
1306: {
1307: if (! isSet[YEAR] || ! isSet[ERA])
1308: complete();
1309: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1310: return isLeapYear(year) ? 29 : 28;
1311: }
1312: else if (month < AUGUST)
1313: return 31 - (month & 1);
1314: else
1315: return 30 + (month & 1);
1316: }
1317: case DAY_OF_YEAR:
1318: {
1319: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1320: complete();
1321: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1322: return isLeapYear(year) ? 366 : 365;
1323: }
1324: case DAY_OF_WEEK_IN_MONTH:
1325: {
1326:
1327: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1328:
1329:
1330: return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
1331: }
1332: case WEEK_OF_MONTH:
1333: {
1334: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1335: int weekday = (daysInMonth - fields[DAY_OF_MONTH]
1336: + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
1337: return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1338: }
1339: default:
1340: return maximums[field];
1341: }
1342: }
1343: }