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:
877: public int hashCode()
878: {
879: int val = (int) ((gregorianCutover >>> 32) ^ (gregorianCutover & 0xffffffff));
880: return super.hashCode() ^ val;
881: }
882:
883:
898: public boolean equals(Object o)
899: {
900: if (! (o instanceof GregorianCalendar))
901: return false;
902:
903: GregorianCalendar cal = (GregorianCalendar) o;
904: return (cal.gregorianCutover == gregorianCutover
905: && super.equals(o));
906: }
907:
908:
919: public void add(int field, int amount)
920: {
921: switch (field)
922: {
923: case YEAR:
924: complete();
925: fields[YEAR] += amount;
926: isTimeSet = false;
927: break;
928: case MONTH:
929: complete();
930: int months = fields[MONTH] + amount;
931: fields[YEAR] += months / 12;
932: fields[MONTH] = months % 12;
933: if (fields[MONTH] < 0)
934: {
935: fields[MONTH] += 12;
936: fields[YEAR]--;
937: }
938: int maxDay = getActualMaximum(DAY_OF_MONTH);
939: if (fields[DAY_OF_MONTH] > maxDay)
940: fields[DAY_OF_MONTH] = maxDay;
941: set(YEAR, fields[YEAR]);
942: set(MONTH, fields[MONTH]);
943: break;
944: case DAY_OF_MONTH:
945: case DAY_OF_YEAR:
946: case DAY_OF_WEEK:
947: if (! isTimeSet)
948: computeTime();
949: time += amount * (24 * 60 * 60 * 1000L);
950: areFieldsSet = false;
951: break;
952: case WEEK_OF_YEAR:
953: case WEEK_OF_MONTH:
954: case DAY_OF_WEEK_IN_MONTH:
955: if (! isTimeSet)
956: computeTime();
957: time += amount * (7 * 24 * 60 * 60 * 1000L);
958: areFieldsSet = false;
959: break;
960: case AM_PM:
961: if (! isTimeSet)
962: computeTime();
963: time += amount * (12 * 60 * 60 * 1000L);
964: areFieldsSet = false;
965: break;
966: case HOUR:
967: case HOUR_OF_DAY:
968: if (! isTimeSet)
969: computeTime();
970: time += amount * (60 * 60 * 1000L);
971: areFieldsSet = false;
972: break;
973: case MINUTE:
974: if (! isTimeSet)
975: computeTime();
976: time += amount * (60 * 1000L);
977: areFieldsSet = false;
978: break;
979: case SECOND:
980: if (! isTimeSet)
981: computeTime();
982: time += amount * (1000L);
983: areFieldsSet = false;
984: break;
985: case MILLISECOND:
986: if (! isTimeSet)
987: computeTime();
988: time += amount;
989: areFieldsSet = false;
990: break;
991: case ZONE_OFFSET:
992: case DST_OFFSET:default:
993: throw new IllegalArgumentException("Invalid or unknown field");
994: }
995: }
996:
997:
1016: public void roll(int field, boolean up)
1017: {
1018: roll(field, up ? 1 : -1);
1019: }
1020:
1021:
1030: private void cleanUpAfterRoll(int field, int delta)
1031: {
1032: switch (field)
1033: {
1034: case ERA:
1035: case YEAR:
1036: case MONTH:
1037:
1038: if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
1039: fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
1040: isTimeSet = false;
1041: isSet[WEEK_OF_MONTH] = false;
1042: isSet[DAY_OF_WEEK] = false;
1043: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1044: isSet[DAY_OF_YEAR] = false;
1045: isSet[WEEK_OF_YEAR] = false;
1046: break;
1047: case DAY_OF_MONTH:
1048: isSet[WEEK_OF_MONTH] = false;
1049: isSet[DAY_OF_WEEK] = false;
1050: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1051: isSet[DAY_OF_YEAR] = false;
1052: isSet[WEEK_OF_YEAR] = false;
1053: time += delta * (24 * 60 * 60 * 1000L);
1054: break;
1055: case WEEK_OF_MONTH:
1056: isSet[DAY_OF_MONTH] = false;
1057: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1058: isSet[DAY_OF_YEAR] = false;
1059: isSet[WEEK_OF_YEAR] = false;
1060: time += delta * (7 * 24 * 60 * 60 * 1000L);
1061: break;
1062: case DAY_OF_WEEK_IN_MONTH:
1063: isSet[DAY_OF_MONTH] = false;
1064: isSet[WEEK_OF_MONTH] = false;
1065: isSet[DAY_OF_YEAR] = false;
1066: isSet[WEEK_OF_YEAR] = false;
1067: time += delta * (7 * 24 * 60 * 60 * 1000L);
1068: break;
1069: case DAY_OF_YEAR:
1070: isSet[MONTH] = false;
1071: isSet[DAY_OF_MONTH] = false;
1072: isSet[WEEK_OF_MONTH] = false;
1073: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1074: isSet[DAY_OF_WEEK] = false;
1075: isSet[WEEK_OF_YEAR] = false;
1076: time += delta * (24 * 60 * 60 * 1000L);
1077: break;
1078: case WEEK_OF_YEAR:
1079: isSet[MONTH] = false;
1080: isSet[DAY_OF_MONTH] = false;
1081: isSet[WEEK_OF_MONTH] = false;
1082: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1083: isSet[DAY_OF_YEAR] = false;
1084: time += delta * (7 * 24 * 60 * 60 * 1000L);
1085: break;
1086: case AM_PM:
1087: isSet[HOUR_OF_DAY] = false;
1088: time += delta * (12 * 60 * 60 * 1000L);
1089: break;
1090: case HOUR:
1091: isSet[HOUR_OF_DAY] = false;
1092: time += delta * (60 * 60 * 1000L);
1093: break;
1094: case HOUR_OF_DAY:
1095: isSet[HOUR] = false;
1096: isSet[AM_PM] = false;
1097: time += delta * (60 * 60 * 1000L);
1098: break;
1099: case MINUTE:
1100: time += delta * (60 * 1000L);
1101: break;
1102: case SECOND:
1103: time += delta * (1000L);
1104: break;
1105: case MILLISECOND:
1106: time += delta;
1107: break;
1108: }
1109: }
1110:
1111:
1129: public void roll(int field, int amount)
1130: {
1131: switch (field)
1132: {
1133: case DAY_OF_WEEK:
1134:
1135: add(field, amount);
1136: return;
1137: case ZONE_OFFSET:
1138: case DST_OFFSET:
1139: throw new IllegalArgumentException("Can't roll time zone");
1140: }
1141: complete();
1142: int min = getActualMinimum(field);
1143: int range = getActualMaximum(field) - min + 1;
1144: int oldval = fields[field];
1145: int newval = (oldval - min + range + amount) % range + min;
1146: if (newval < min)
1147: newval += range;
1148: fields[field] = newval;
1149: cleanUpAfterRoll(field, newval - oldval);
1150: }
1151:
1152:
1155: private static final int[] minimums =
1156: {
1157: BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM,
1158: 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000),
1159: 0
1160: };
1161:
1162:
1165: private static final int[] maximums =
1166: {
1167: AD, 5000000, 11, 53, 5, 31, 366,
1168: SATURDAY, 5, PM, 12, 23, 59, 59, 999,
1169: +(12 * 60 * 60 * 1000),
1170: (12 * 60 * 60 * 1000)
1171: };
1172:
1173:
1179: public int getMinimum(int field)
1180: {
1181: return minimums[field];
1182: }
1183:
1184:
1190: public int getMaximum(int field)
1191: {
1192: return maximums[field];
1193: }
1194:
1195:
1204: public int getGreatestMinimum(int field)
1205: {
1206: if (field == WEEK_OF_YEAR)
1207: return 1;
1208: return minimums[field];
1209: }
1210:
1211:
1223: public int getLeastMaximum(int field)
1224: {
1225: switch (field)
1226: {
1227: case WEEK_OF_YEAR:
1228: return 52;
1229: case DAY_OF_MONTH:
1230: return 28;
1231: case DAY_OF_YEAR:
1232: return 365;
1233: case DAY_OF_WEEK_IN_MONTH:
1234: case WEEK_OF_MONTH:
1235: return 4;
1236: default:
1237: return maximums[field];
1238: }
1239: }
1240:
1241:
1252: public int getActualMinimum(int field)
1253: {
1254: if (field == WEEK_OF_YEAR)
1255: {
1256: int min = getMinimalDaysInFirstWeek();
1257: if (min == 0)
1258: return 1;
1259: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1260: complete();
1261:
1262: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1263: int weekday = getWeekDay(year, min);
1264: if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
1265: return 1;
1266: return 0;
1267: }
1268: return minimums[field];
1269: }
1270:
1271:
1282: public int getActualMaximum(int field)
1283: {
1284: switch (field)
1285: {
1286: case WEEK_OF_YEAR:
1287: {
1288: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1289: complete();
1290:
1291:
1292:
1293:
1294: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1295: int lastDay = isLeapYear(year) ? 366 : 365;
1296: int weekday = getWeekDay(year, lastDay);
1297: int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1298:
1299: int minimalDays = getMinimalDaysInFirstWeek();
1300: int firstWeekday = getWeekDay(year, minimalDays);
1301:
1306: if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
1307: return week + 1;
1308: }
1309: case DAY_OF_MONTH:
1310: {
1311: if (! areFieldsSet || ! isSet[MONTH])
1312: complete();
1313: int month = fields[MONTH];
1314:
1315:
1316:
1317: if (month == FEBRUARY)
1318: {
1319: if (! isSet[YEAR] || ! isSet[ERA])
1320: complete();
1321: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1322: return isLeapYear(year) ? 29 : 28;
1323: }
1324: else if (month < AUGUST)
1325: return 31 - (month & 1);
1326: else
1327: return 30 + (month & 1);
1328: }
1329: case DAY_OF_YEAR:
1330: {
1331: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1332: complete();
1333: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1334: return isLeapYear(year) ? 366 : 365;
1335: }
1336: case DAY_OF_WEEK_IN_MONTH:
1337: {
1338:
1339: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1340:
1341:
1342: return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
1343: }
1344: case WEEK_OF_MONTH:
1345: {
1346: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1347: int weekday = (daysInMonth - fields[DAY_OF_MONTH]
1348: + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
1349: return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1350: }
1351: default:
1352: return maximums[field];
1353: }
1354: }
1355: }