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: }
227:
228:
235: private GregorianCalendar(TimeZone zone, Locale locale, boolean unused)
236: {
237: super(zone, locale);
238: }
239:
240:
248: public GregorianCalendar(int year, int month, int day)
249: {
250: this(TimeZone.getDefault(), Locale.getDefault(), false);
251: set(year, month, day);
252: }
253:
254:
264: public GregorianCalendar(int year, int month, int day, int hour, int minute)
265: {
266: this(TimeZone.getDefault(), Locale.getDefault(), false);
267: set(year, month, day, hour, minute);
268: }
269:
270:
281: public GregorianCalendar(int year, int month, int day, int hour, int minute,
282: int second)
283: {
284: this(TimeZone.getDefault(), Locale.getDefault(), false);
285: set(year, month, day, hour, minute, second);
286: }
287:
288:
296: public void setGregorianChange(Date date)
297: {
298: gregorianCutover = date.getTime();
299: }
300:
301:
306: public final Date getGregorianChange()
307: {
308: return new Date(gregorianCutover);
309: }
310:
311:
327: public boolean isLeapYear(int year)
328: {
329:
330: if ((year & 3) != 0)
331: return false;
332:
333:
334: if (! isGregorian(year, 31 + 29 - 1))
335: return true;
336:
337:
338: return ((year % 100) != 0 || (year % 400) == 0);
339: }
340:
341:
349: private int getWeekDay(int year, int dayOfYear)
350: {
351: boolean greg = isGregorian(year, dayOfYear);
352: int day = (int) getLinearDay(year, dayOfYear, greg);
353:
354:
355: int weekday = (day + THURSDAY) % 7;
356: if (weekday <= 0)
357: weekday += 7;
358: return weekday;
359: }
360:
361:
364: private int getFirstDayOfMonth(int year, int month)
365: {
366: int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
367:
368: if (month > 11)
369: {
370: year += (month / 12);
371: month = month % 12;
372: }
373:
374: if (month < 0)
375: {
376: year += (int) month / 12;
377: month = month % 12;
378: if (month < 0)
379: {
380: month += 12;
381: year--;
382: }
383: }
384:
385: int dayOfYear = dayCount[month] + 1;
386: if (month > 1)
387: if (isLeapYear(year))
388: dayOfYear++;
389:
390: boolean greg = isGregorian(year, dayOfYear);
391: int day = (int) getLinearDay(year, dayOfYear, greg);
392:
393:
394: int weekday = (day + THURSDAY) % 7;
395: if (weekday <= 0)
396: weekday += 7;
397: return weekday;
398: }
399:
400:
404: private boolean isGregorian(int year, int dayOfYear)
405: {
406: int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
407: - EPOCH_DAYS;
408: int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
409: - (int) Math.floor((double) (year - 1) / 100.);
410:
411: return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover);
412: }
413:
414:
419: private void nonLeniencyCheck() throws IllegalArgumentException
420: {
421: int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
422: int year = fields[YEAR];
423: int month = fields[MONTH];
424: int leap = isLeapYear(year) ? 1 : 0;
425:
426: if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC)
427: throw new IllegalArgumentException("Illegal ERA.");
428: if (isSet[YEAR] && fields[YEAR] < 1)
429: throw new IllegalArgumentException("Illegal YEAR.");
430: if (isSet[MONTH] && (month < 0 || month > 11))
431: throw new IllegalArgumentException("Illegal MONTH.");
432: if (isSet[WEEK_OF_YEAR])
433: {
434: int daysInYear = 365 + leap;
435: daysInYear += (getFirstDayOfMonth(year, 0) - 1);
436: int last = getFirstDayOfMonth(year, 11) + 4;
437: if (last > 7)
438: last -= 7;
439: daysInYear += 7 - last;
440: int weeks = daysInYear / 7;
441: if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks)
442: throw new IllegalArgumentException("Illegal WEEK_OF_YEAR.");
443: }
444:
445: if (isSet[WEEK_OF_MONTH])
446: {
447: int weeks = (month == 1 && leap == 0) ? 5 : 6;
448: if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks)
449: throw new IllegalArgumentException("Illegal WEEK_OF_MONTH.");
450: }
451:
452: if (isSet[DAY_OF_MONTH])
453: if (fields[DAY_OF_MONTH] < 1
454: || fields[DAY_OF_MONTH] > month_days[month]
455: + ((month == 1) ? leap : 0))
456: throw new IllegalArgumentException("Illegal DAY_OF_MONTH.");
457:
458: if (isSet[DAY_OF_YEAR]
459: && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap))
460: throw new IllegalArgumentException("Illegal DAY_OF_YEAR.");
461:
462: if (isSet[DAY_OF_WEEK]
463: && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7))
464: throw new IllegalArgumentException("Illegal DAY_OF_WEEK.");
465:
466: if (isSet[DAY_OF_WEEK_IN_MONTH])
467: {
468: int weeks = (month == 1 && leap == 0) ? 4 : 5;
469: if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks
470: || fields[DAY_OF_WEEK_IN_MONTH] > weeks)
471: throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH.");
472: }
473:
474: if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM)
475: throw new IllegalArgumentException("Illegal AM_PM.");
476: if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11))
477: throw new IllegalArgumentException("Illegal HOUR.");
478: if (isSet[HOUR_OF_DAY]
479: && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23))
480: throw new IllegalArgumentException("Illegal HOUR_OF_DAY.");
481: if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59))
482: throw new IllegalArgumentException("Illegal MINUTE.");
483: if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59))
484: throw new IllegalArgumentException("Illegal SECOND.");
485: if (isSet[MILLISECOND]
486: && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999))
487: throw new IllegalArgumentException("Illegal MILLISECOND.");
488: if (isSet[ZONE_OFFSET]
489: && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L
490: || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L))
491: throw new IllegalArgumentException("Illegal ZONE_OFFSET.");
492: if (isSet[DST_OFFSET]
493: && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L
494: || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L))
495: throw new IllegalArgumentException("Illegal DST_OFFSET.");
496: }
497:
498:
505: protected synchronized void computeTime()
506: {
507: int millisInDay = 0;
508: int era = fields[ERA];
509: int year = fields[YEAR];
510: int month = fields[MONTH];
511: int day = fields[DAY_OF_MONTH];
512:
513: int minute = fields[MINUTE];
514: int second = fields[SECOND];
515: int millis = fields[MILLISECOND];
516: int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
517: int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
518: int hour = 0;
519:
520: if (! isLenient())
521: nonLeniencyCheck();
522:
523: if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
524: {
525:
526: if (isSet[WEEK_OF_YEAR])
527: {
528: int first = getFirstDayOfMonth(year, 0);
529: int offs = 1;
530: int daysInFirstWeek = getFirstDayOfWeek() - first;
531: if (daysInFirstWeek <= 0)
532: daysInFirstWeek += 7;
533:
534: if (daysInFirstWeek < getMinimalDaysInFirstWeek())
535: offs += daysInFirstWeek;
536: else
537: offs -= 7 - daysInFirstWeek;
538: month = 0;
539: day = offs + 7 * (fields[WEEK_OF_YEAR] - 1);
540: offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
541:
542: if (offs < 0)
543: offs += 7;
544: day += offs;
545: }
546: else
547: {
548:
549: month = 0;
550: day = fields[DAY_OF_YEAR];
551: }
552: }
553: else
554: {
555: if (isSet[DAY_OF_WEEK])
556: {
557: int first = getFirstDayOfMonth(year, month);
558:
559:
560: if (isSet[DAY_OF_WEEK_IN_MONTH])
561: {
562: if (fields[DAY_OF_WEEK_IN_MONTH] < 0)
563: {
564: month++;
565: first = getFirstDayOfMonth(year, month);
566: day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]);
567: }
568: else
569: day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
570:
571: int offs = fields[DAY_OF_WEEK] - first;
572: if (offs < 0)
573: offs += 7;
574: day += offs;
575: }
576: else
577: {
578: int offs = 1;
579: int daysInFirstWeek = getFirstDayOfWeek() - first;
580: if (daysInFirstWeek <= 0)
581: daysInFirstWeek += 7;
582:
583: if (daysInFirstWeek < getMinimalDaysInFirstWeek())
584: offs += daysInFirstWeek;
585: else
586: offs -= 7 - daysInFirstWeek;
587:
588: day = offs + 7 * (fields[WEEK_OF_MONTH] - 1);
589: offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
590: if (offs < 0)
591: offs += 7;
592: day += offs;
593: }
594: }
595:
596:
597: }
598: if (era == BC && year > 0)
599: year = 1 - year;
600:
601:
602:
603:
604: if (isSet[HOUR])
605: {
606: hour = fields[HOUR];
607: if (fields[AM_PM] == PM)
608: hour += 12;
609: }
610: else
611: hour = fields[HOUR_OF_DAY];
612:
613:
614:
615:
616: long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis;
617: day += allMillis / (24 * 60 * 60 * 1000L);
618: millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
619:
620: if (month < 0)
621: {
622: year += (int) month / 12;
623: month = month % 12;
624: if (month < 0)
625: {
626: month += 12;
627: year--;
628: }
629: }
630: if (month > 11)
631: {
632: year += (month / 12);
633: month = month % 12;
634: }
635:
636: month_days[1] = isLeapYear(year) ? 29 : 28;
637:
638: while (day <= 0)
639: {
640: if (month == 0)
641: {
642: year--;
643: month_days[1] = isLeapYear(year) ? 29 : 28;
644: }
645: month = (month + 11) % 12;
646: day += month_days[month];
647: }
648: while (day > month_days[month])
649: {
650: day -= (month_days[month]);
651: month = (month + 1) % 12;
652: if (month == 0)
653: {
654: year++;
655: month_days[1] = isLeapYear(year) ? 29 : 28;
656: }
657: }
658:
659:
660: int dayOfYear = dayCount[month] + day - 1;
661: if (isLeapYear(year) && month > 1)
662: dayOfYear++;
663:
664: int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
665: - EPOCH_DAYS;
666: int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
667: - (int) Math.floor((double) (year - 1) / 100.);
668:
669: if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover)
670: relativeDay += gregFactor;
671: else
672: relativeDay -= 2;
673:
674: time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay;
675:
676:
677: int weekday = (int) (relativeDay + THURSDAY) % 7;
678: if (weekday <= 0)
679: weekday += 7;
680: fields[DAY_OF_WEEK] = weekday;
681:
682:
683: TimeZone zone = getTimeZone();
684: int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET]
685: : zone.getRawOffset();
686:
687: int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET]
688: : (zone.getOffset((year < 0) ? BC : AD,
689: (year < 0) ? 1 - year
690: : year,
691: month, day, weekday,
692: millisInDay)
693: - zone.getRawOffset());
694:
695: time -= rawOffset + dstOffset;
696:
697: isTimeSet = true;
698: }
699:
700:
711: private long getLinearDay(int year, int dayOfYear, boolean gregorian)
712: {
713:
714:
715:
716:
717: long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1)
718: - EPOCH_DAYS;
719:
720: if (gregorian)
721: {
722:
723:
724:
725:
726:
727:
728:
729:
730:
731: int gregOffset = (int) Math.floor((double) (year - 1) / 400.)
732: - (int) Math.floor((double) (year - 1) / 100.);
733:
734: return julianDay + gregOffset;
735: }
736: else
737: julianDay -= 2;
738: return julianDay;
739: }
740:
741:
749: private void calculateDay(int[] fields, long day, boolean gregorian)
750: {
751:
752: int weekday = (int) (day + THURSDAY) % 7;
753: if (weekday <= 0)
754: weekday += 7;
755: fields[DAY_OF_WEEK] = weekday;
756:
757:
758:
759: int year = 1970
760: + (int) (gregorian
761: ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L
762: + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L));
763: if (day >= 0)
764: year++;
765:
766: long firstDayOfYear = getLinearDay(year, 1, gregorian);
767:
768:
769: if (day < firstDayOfYear)
770: {
771: year--;
772: firstDayOfYear = getLinearDay(year, 1, gregorian);
773: }
774:
775: day -= firstDayOfYear - 1;
776:
777: fields[DAY_OF_YEAR] = (int) day;
778: if (year <= 0)
779: {
780: fields[ERA] = BC;
781: fields[YEAR] = 1 - year;
782: }
783: else
784: {
785: fields[ERA] = AD;
786: fields[YEAR] = year;
787: }
788:
789: int leapday = isLeapYear(year) ? 1 : 0;
790: if (day <= 31 + 28 + leapday)
791: {
792: fields[MONTH] = (int) day / 32;
793: fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH];
794: }
795: else
796: {
797:
798: int scaledDay = ((int) day - leapday) * 5 + 8;
799: fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
800: fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
801: }
802: }
803:
804:
809: protected synchronized void computeFields()
810: {
811: boolean gregorian = (time >= gregorianCutover);
812:
813: TimeZone zone = getTimeZone();
814: fields[ZONE_OFFSET] = zone.getRawOffset();
815: long localTime = time + fields[ZONE_OFFSET];
816:
817: long day = localTime / (24 * 60 * 60 * 1000L);
818: int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
819:
820: if (millisInDay < 0)
821: {
822: millisInDay += (24 * 60 * 60 * 1000);
823: day--;
824: }
825:
826: calculateDay(fields, day, gregorian);
827: fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR],
828: fields[MONTH], fields[DAY_OF_MONTH],
829: fields[DAY_OF_WEEK], millisInDay)
830: - fields[ZONE_OFFSET];
831:
832: millisInDay += fields[DST_OFFSET];
833: if (millisInDay >= 24 * 60 * 60 * 1000)
834: {
835: millisInDay -= 24 * 60 * 60 * 1000;
836: calculateDay(fields, ++day, gregorian);
837: }
838:
839: fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
840:
841:
842: int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
843:
844:
845:
846:
847: int relativeWeekdayOfFirst = (relativeWeekday - fields[DAY_OF_MONTH]
848: + 1 + 35) % 7;
849:
850:
851: int minDays = getMinimalDaysInFirstWeek();
852: int weekOfFirst = ((7 - relativeWeekdayOfFirst) >= minDays) ? 1 : 0;
853:
854:
855: fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH]
856: + relativeWeekdayOfFirst - 1) / 7 + weekOfFirst;
857:
858: int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
859:
860:
861:
862: int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays)
863: - getFirstDayOfWeek()) % 7;
864: if (minDays - firstWeekday < 1)
865: weekOfYear++;
866: fields[WEEK_OF_YEAR] = weekOfYear;
867:
868: int hourOfDay = millisInDay / (60 * 60 * 1000);
869: fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
870: int hour = hourOfDay % 12;
871: fields[HOUR] = hour;
872: fields[HOUR_OF_DAY] = hourOfDay;
873: millisInDay %= (60 * 60 * 1000);
874: fields[MINUTE] = millisInDay / (60 * 1000);
875: millisInDay %= (60 * 1000);
876: fields[SECOND] = millisInDay / (1000);
877: fields[MILLISECOND] = millisInDay % 1000;
878:
879: 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;
880: }
881:
882:
887: public int hashCode()
888: {
889: int val = (int) ((gregorianCutover >>> 32) ^ (gregorianCutover & 0xffffffff));
890: return super.hashCode() ^ val;
891: }
892:
893:
908: public boolean equals(Object o)
909: {
910: if (! (o instanceof GregorianCalendar))
911: return false;
912:
913: GregorianCalendar cal = (GregorianCalendar) o;
914: return (cal.gregorianCutover == gregorianCutover
915: && super.equals(o));
916: }
917:
918:
929: public void add(int field, int amount)
930: {
931: switch (field)
932: {
933: case YEAR:
934: complete();
935: fields[YEAR] += amount;
936: isTimeSet = false;
937: break;
938: case MONTH:
939: complete();
940: int months = fields[MONTH] + amount;
941: fields[YEAR] += months / 12;
942: fields[MONTH] = months % 12;
943: if (fields[MONTH] < 0)
944: {
945: fields[MONTH] += 12;
946: fields[YEAR]--;
947: }
948: int maxDay = getActualMaximum(DAY_OF_MONTH);
949: if (fields[DAY_OF_MONTH] > maxDay)
950: fields[DAY_OF_MONTH] = maxDay;
951: set(YEAR, fields[YEAR]);
952: set(MONTH, fields[MONTH]);
953: break;
954: case DAY_OF_MONTH:
955: case DAY_OF_YEAR:
956: case DAY_OF_WEEK:
957: if (! isTimeSet)
958: computeTime();
959: time += amount * (24 * 60 * 60 * 1000L);
960: areFieldsSet = false;
961: break;
962: case WEEK_OF_YEAR:
963: case WEEK_OF_MONTH:
964: case DAY_OF_WEEK_IN_MONTH:
965: if (! isTimeSet)
966: computeTime();
967: time += amount * (7 * 24 * 60 * 60 * 1000L);
968: areFieldsSet = false;
969: break;
970: case AM_PM:
971: if (! isTimeSet)
972: computeTime();
973: time += amount * (12 * 60 * 60 * 1000L);
974: areFieldsSet = false;
975: break;
976: case HOUR:
977: case HOUR_OF_DAY:
978: if (! isTimeSet)
979: computeTime();
980: time += amount * (60 * 60 * 1000L);
981: areFieldsSet = false;
982: break;
983: case MINUTE:
984: if (! isTimeSet)
985: computeTime();
986: time += amount * (60 * 1000L);
987: areFieldsSet = false;
988: break;
989: case SECOND:
990: if (! isTimeSet)
991: computeTime();
992: time += amount * (1000L);
993: areFieldsSet = false;
994: break;
995: case MILLISECOND:
996: if (! isTimeSet)
997: computeTime();
998: time += amount;
999: areFieldsSet = false;
1000: break;
1001: case ZONE_OFFSET:
1002: case DST_OFFSET:default:
1003: throw new IllegalArgumentException("Invalid or unknown field");
1004: }
1005: }
1006:
1007:
1026: public void roll(int field, boolean up)
1027: {
1028: roll(field, up ? 1 : -1);
1029: }
1030:
1031:
1040: private void cleanUpAfterRoll(int field, int delta)
1041: {
1042: switch (field)
1043: {
1044: case ERA:
1045: case YEAR:
1046: case MONTH:
1047:
1048: if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
1049: fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
1050: isTimeSet = false;
1051: isSet[WEEK_OF_MONTH] = false;
1052: isSet[DAY_OF_WEEK] = false;
1053: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1054: isSet[DAY_OF_YEAR] = false;
1055: isSet[WEEK_OF_YEAR] = false;
1056: break;
1057: case DAY_OF_MONTH:
1058: isSet[WEEK_OF_MONTH] = false;
1059: isSet[DAY_OF_WEEK] = false;
1060: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1061: isSet[DAY_OF_YEAR] = false;
1062: isSet[WEEK_OF_YEAR] = false;
1063: time += delta * (24 * 60 * 60 * 1000L);
1064: break;
1065: case WEEK_OF_MONTH:
1066: isSet[DAY_OF_MONTH] = false;
1067: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1068: isSet[DAY_OF_YEAR] = false;
1069: isSet[WEEK_OF_YEAR] = false;
1070: time += delta * (7 * 24 * 60 * 60 * 1000L);
1071: break;
1072: case DAY_OF_WEEK_IN_MONTH:
1073: isSet[DAY_OF_MONTH] = false;
1074: isSet[WEEK_OF_MONTH] = false;
1075: isSet[DAY_OF_YEAR] = false;
1076: isSet[WEEK_OF_YEAR] = false;
1077: time += delta * (7 * 24 * 60 * 60 * 1000L);
1078: break;
1079: case DAY_OF_YEAR:
1080: isSet[MONTH] = false;
1081: isSet[DAY_OF_MONTH] = false;
1082: isSet[WEEK_OF_MONTH] = false;
1083: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1084: isSet[DAY_OF_WEEK] = false;
1085: isSet[WEEK_OF_YEAR] = false;
1086: time += delta * (24 * 60 * 60 * 1000L);
1087: break;
1088: case WEEK_OF_YEAR:
1089: isSet[MONTH] = false;
1090: isSet[DAY_OF_MONTH] = false;
1091: isSet[WEEK_OF_MONTH] = false;
1092: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1093: isSet[DAY_OF_YEAR] = false;
1094: time += delta * (7 * 24 * 60 * 60 * 1000L);
1095: break;
1096: case AM_PM:
1097: isSet[HOUR_OF_DAY] = false;
1098: time += delta * (12 * 60 * 60 * 1000L);
1099: break;
1100: case HOUR:
1101: isSet[HOUR_OF_DAY] = false;
1102: time += delta * (60 * 60 * 1000L);
1103: break;
1104: case HOUR_OF_DAY:
1105: isSet[HOUR] = false;
1106: isSet[AM_PM] = false;
1107: time += delta * (60 * 60 * 1000L);
1108: break;
1109: case MINUTE:
1110: time += delta * (60 * 1000L);
1111: break;
1112: case SECOND:
1113: time += delta * (1000L);
1114: break;
1115: case MILLISECOND:
1116: time += delta;
1117: break;
1118: }
1119: }
1120:
1121:
1139: public void roll(int field, int amount)
1140: {
1141: switch (field)
1142: {
1143: case DAY_OF_WEEK:
1144:
1145: add(field, amount);
1146: return;
1147: case ZONE_OFFSET:
1148: case DST_OFFSET:
1149: throw new IllegalArgumentException("Can't roll time zone");
1150: }
1151: complete();
1152: int min = getActualMinimum(field);
1153: int range = getActualMaximum(field) - min + 1;
1154: int oldval = fields[field];
1155: int newval = (oldval - min + range + amount) % range + min;
1156: if (newval < min)
1157: newval += range;
1158: fields[field] = newval;
1159: cleanUpAfterRoll(field, newval - oldval);
1160: }
1161:
1162:
1165: private static final int[] minimums =
1166: {
1167: BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM,
1168: 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000),
1169: 0
1170: };
1171:
1172:
1175: private static final int[] maximums =
1176: {
1177: AD, 5000000, 11, 53, 6, 31, 366,
1178: SATURDAY, 5, PM, 12, 23, 59, 59, 999,
1179: +(12 * 60 * 60 * 1000),
1180: (12 * 60 * 60 * 1000)
1181: };
1182:
1183:
1189: public int getMinimum(int field)
1190: {
1191: return minimums[field];
1192: }
1193:
1194:
1200: public int getMaximum(int field)
1201: {
1202: return maximums[field];
1203: }
1204:
1205:
1214: public int getGreatestMinimum(int field)
1215: {
1216: if (field == WEEK_OF_YEAR)
1217: return 1;
1218: return minimums[field];
1219: }
1220:
1221:
1233: public int getLeastMaximum(int field)
1234: {
1235: switch (field)
1236: {
1237: case WEEK_OF_YEAR:
1238: return 52;
1239: case DAY_OF_MONTH:
1240: return 28;
1241: case DAY_OF_YEAR:
1242: return 365;
1243: case DAY_OF_WEEK_IN_MONTH:
1244: case WEEK_OF_MONTH:
1245: return 4;
1246: default:
1247: return maximums[field];
1248: }
1249: }
1250:
1251:
1262: public int getActualMinimum(int field)
1263: {
1264: if (field == WEEK_OF_YEAR)
1265: {
1266: int min = getMinimalDaysInFirstWeek();
1267: if (min == 0)
1268: return 1;
1269: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1270: complete();
1271:
1272: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1273: int weekday = getWeekDay(year, min);
1274: if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
1275: return 1;
1276: return 0;
1277: }
1278: return minimums[field];
1279: }
1280:
1281:
1292: public int getActualMaximum(int field)
1293: {
1294: switch (field)
1295: {
1296: case WEEK_OF_YEAR:
1297: {
1298: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1299: complete();
1300:
1301:
1302:
1303:
1304: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1305: int lastDay = isLeapYear(year) ? 366 : 365;
1306: int weekday = getWeekDay(year, lastDay);
1307: int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1308:
1309: int minimalDays = getMinimalDaysInFirstWeek();
1310: int firstWeekday = getWeekDay(year, minimalDays);
1311:
1316: if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
1317: return week + 1;
1318: }
1319: case DAY_OF_MONTH:
1320: {
1321: if (! areFieldsSet || ! isSet[MONTH])
1322: complete();
1323: int month = fields[MONTH];
1324:
1325:
1326:
1327: if (month == FEBRUARY)
1328: {
1329: if (! isSet[YEAR] || ! isSet[ERA])
1330: complete();
1331: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1332: return isLeapYear(year) ? 29 : 28;
1333: }
1334: else if (month < AUGUST)
1335: return 31 - (month & 1);
1336: else
1337: return 30 + (month & 1);
1338: }
1339: case DAY_OF_YEAR:
1340: {
1341: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1342: complete();
1343: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1344: return isLeapYear(year) ? 366 : 365;
1345: }
1346: case DAY_OF_WEEK_IN_MONTH:
1347: {
1348:
1349: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1350:
1351:
1352: return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
1353: }
1354: case WEEK_OF_MONTH:
1355: {
1356: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1357: int weekday = (daysInMonth - fields[DAY_OF_MONTH]
1358: + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
1359: return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1360: }
1361: default:
1362: return maximums[field];
1363: }
1364: }
1365: }