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;
156:
157:
160: static final long serialVersionUID = -8125100834729963327L;
161:
162:
165: private static final String bundleName = "gnu.java.locale.Calendar";
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: ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale,
240: ClassLoader
241: .getSystemClassLoader());
242: gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime();
243: }
244:
245:
252: public GregorianCalendar(int year, int month, int day)
253: {
254: this(TimeZone.getDefault(), Locale.getDefault(), false);
255: set(year, month, day);
256: }
257:
258:
268: public GregorianCalendar(int year, int month, int day, int hour, int minute)
269: {
270: this(TimeZone.getDefault(), Locale.getDefault(), false);
271: set(year, month, day, hour, minute);
272: }
273:
274:
285: public GregorianCalendar(int year, int month, int day, int hour, int minute,
286: int second)
287: {
288: this(TimeZone.getDefault(), Locale.getDefault(), false);
289: set(year, month, day, hour, minute, second);
290: }
291:
292:
300: public void setGregorianChange(Date date)
301: {
302: gregorianCutover = date.getTime();
303: }
304:
305:
310: public final Date getGregorianChange()
311: {
312: return new Date(gregorianCutover);
313: }
314:
315:
331: public boolean isLeapYear(int year)
332: {
333:
334: if ((year & 3) != 0)
335: return false;
336:
337:
338: if (! isGregorian(year, 31 + 29 - 1))
339: return true;
340:
341:
342: return ((year % 100) != 0 || (year % 400) == 0);
343: }
344:
345:
353: private int getWeekDay(int year, int dayOfYear)
354: {
355: boolean greg = isGregorian(year, dayOfYear);
356: int day = (int) getLinearDay(year, dayOfYear, greg);
357:
358:
359: int weekday = (day + THURSDAY) % 7;
360: if (weekday <= 0)
361: weekday += 7;
362: return weekday;
363: }
364:
365:
368: private int getFirstDayOfMonth(int year, int month)
369: {
370: int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
371:
372: if (month > 11)
373: {
374: year += (month / 12);
375: month = month % 12;
376: }
377:
378: if (month < 0)
379: {
380: year += (int) month / 12;
381: month = month % 12;
382: if (month < 0)
383: {
384: month += 12;
385: year--;
386: }
387: }
388:
389: int dayOfYear = dayCount[month] + 1;
390: if (month > 1)
391: if (isLeapYear(year))
392: dayOfYear++;
393:
394: boolean greg = isGregorian(year, dayOfYear);
395: int day = (int) getLinearDay(year, dayOfYear, greg);
396:
397:
398: int weekday = (day + THURSDAY) % 7;
399: if (weekday <= 0)
400: weekday += 7;
401: return weekday;
402: }
403:
404:
408: private boolean isGregorian(int year, int dayOfYear)
409: {
410: int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
411: - EPOCH_DAYS;
412: int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
413: - (int) Math.floor((double) (year - 1) / 100.);
414:
415: return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover);
416: }
417:
418:
423: private void nonLeniencyCheck() throws IllegalArgumentException
424: {
425: int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
426: int year = fields[YEAR];
427: int month = fields[MONTH];
428: int leap = isLeapYear(year) ? 1 : 0;
429:
430: if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC)
431: throw new IllegalArgumentException("Illegal ERA.");
432: if (isSet[YEAR] && fields[YEAR] < 1)
433: throw new IllegalArgumentException("Illegal YEAR.");
434: if (isSet[MONTH] && (month < 0 || month > 11))
435: throw new IllegalArgumentException("Illegal MONTH.");
436: if (isSet[WEEK_OF_YEAR])
437: {
438: int daysInYear = 365 + leap;
439: daysInYear += (getFirstDayOfMonth(year, 0) - 1);
440: int last = getFirstDayOfMonth(year, 11) + 4;
441: if (last > 7)
442: last -= 7;
443: daysInYear += 7 - last;
444: int weeks = daysInYear / 7;
445: if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks)
446: throw new IllegalArgumentException("Illegal WEEK_OF_YEAR.");
447: }
448:
449: if (isSet[WEEK_OF_MONTH])
450: {
451: int weeks = (month == 1 && leap == 0) ? 4 : 5;
452: if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks)
453: throw new IllegalArgumentException("Illegal WEEK_OF_MONTH.");
454: }
455:
456: if (isSet[DAY_OF_MONTH])
457: if (fields[DAY_OF_MONTH] < 1
458: || fields[DAY_OF_MONTH] > month_days[month]
459: + ((month == 1) ? leap : 0))
460: throw new IllegalArgumentException("Illegal DAY_OF_MONTH.");
461:
462: if (isSet[DAY_OF_YEAR]
463: && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap))
464: throw new IllegalArgumentException("Illegal DAY_OF_YEAR.");
465:
466: if (isSet[DAY_OF_WEEK]
467: && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7))
468: throw new IllegalArgumentException("Illegal DAY_OF_WEEK.");
469:
470: if (isSet[DAY_OF_WEEK_IN_MONTH])
471: {
472: int weeks = (month == 1 && leap == 0) ? 4 : 5;
473: if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks
474: || fields[DAY_OF_WEEK_IN_MONTH] > weeks)
475: throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH.");
476: }
477:
478: if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM)
479: throw new IllegalArgumentException("Illegal AM_PM.");
480: if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11))
481: throw new IllegalArgumentException("Illegal HOUR.");
482: if (isSet[HOUR_OF_DAY]
483: && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23))
484: throw new IllegalArgumentException("Illegal HOUR_OF_DAY.");
485: if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59))
486: throw new IllegalArgumentException("Illegal MINUTE.");
487: if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59))
488: throw new IllegalArgumentException("Illegal SECOND.");
489: if (isSet[MILLISECOND]
490: && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999))
491: throw new IllegalArgumentException("Illegal MILLISECOND.");
492: if (isSet[ZONE_OFFSET]
493: && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L
494: || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L))
495: throw new IllegalArgumentException("Illegal ZONE_OFFSET.");
496: if (isSet[DST_OFFSET]
497: && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L
498: || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L))
499: throw new IllegalArgumentException("Illegal DST_OFFSET.");
500: }
501:
502:
509: protected synchronized void computeTime()
510: {
511: int millisInDay = 0;
512: int era = fields[ERA];
513: int year = fields[YEAR];
514: int month = fields[MONTH];
515: int day = fields[DAY_OF_MONTH];
516:
517: int minute = fields[MINUTE];
518: int second = fields[SECOND];
519: int millis = fields[MILLISECOND];
520: int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
521: int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
522: int hour = 0;
523:
524: if (! isLenient())
525: nonLeniencyCheck();
526:
527: if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
528: {
529:
530: if (isSet[WEEK_OF_YEAR])
531: {
532: int first = getFirstDayOfMonth(year, 0);
533: int offs = 1;
534: int daysInFirstWeek = getFirstDayOfWeek() - first;
535: if (daysInFirstWeek <= 0)
536: daysInFirstWeek += 7;
537:
538: if (daysInFirstWeek < getMinimalDaysInFirstWeek())
539: offs += daysInFirstWeek;
540: else
541: offs -= 7 - daysInFirstWeek;
542: month = 0;
543: day = offs + 7 * (fields[WEEK_OF_YEAR] - 1);
544: offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
545:
546: if (offs < 0)
547: offs += 7;
548: day += offs;
549: }
550: else
551: {
552:
553: month = 0;
554: day = fields[DAY_OF_YEAR];
555: }
556: }
557: else
558: {
559: if (isSet[DAY_OF_WEEK])
560: {
561: int first = getFirstDayOfMonth(year, month);
562:
563:
564: if (isSet[DAY_OF_WEEK_IN_MONTH])
565: {
566: if (fields[DAY_OF_WEEK_IN_MONTH] < 0)
567: {
568: month++;
569: first = getFirstDayOfMonth(year, month);
570: day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]);
571: }
572: else
573: day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
574:
575: int offs = fields[DAY_OF_WEEK] - first;
576: if (offs < 0)
577: offs += 7;
578: day += offs;
579: }
580: else
581: {
582: int offs = 1;
583: int daysInFirstWeek = getFirstDayOfWeek() - first;
584: if (daysInFirstWeek <= 0)
585: daysInFirstWeek += 7;
586:
587: if (daysInFirstWeek < getMinimalDaysInFirstWeek())
588: offs += daysInFirstWeek;
589: else
590: offs -= 7 - daysInFirstWeek;
591:
592: day = offs + 7 * (fields[WEEK_OF_MONTH] - 1);
593: offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek();
594: if (offs <= 0)
595: offs += 7;
596: day += offs;
597: }
598: }
599:
600:
601: }
602: if (era == BC && year > 0)
603: year = 1 - year;
604:
605:
606:
607:
608: if (isSet[HOUR])
609: {
610: hour = fields[HOUR];
611: if (fields[AM_PM] == PM)
612: hour += 12;
613: }
614: else
615: hour = fields[HOUR_OF_DAY];
616:
617:
618:
619:
620: long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis;
621: day += allMillis / (24 * 60 * 60 * 1000L);
622: millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
623:
624: if (month < 0)
625: {
626: year += (int) month / 12;
627: month = month % 12;
628: if (month < 0)
629: {
630: month += 12;
631: year--;
632: }
633: }
634: if (month > 11)
635: {
636: year += (month / 12);
637: month = month % 12;
638: }
639:
640: month_days[1] = isLeapYear(year) ? 29 : 28;
641:
642: while (day <= 0)
643: {
644: if (month == 0)
645: {
646: year--;
647: month_days[1] = isLeapYear(year) ? 29 : 28;
648: }
649: month = (month + 11) % 12;
650: day += month_days[month];
651: }
652: while (day > month_days[month])
653: {
654: day -= (month_days[month]);
655: month = (month + 1) % 12;
656: if (month == 0)
657: {
658: year++;
659: month_days[1] = isLeapYear(year) ? 29 : 28;
660: }
661: }
662:
663:
664: int dayOfYear = dayCount[month] + day - 1;
665: if (isLeapYear(year) && month > 1)
666: dayOfYear++;
667:
668: int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
669: - EPOCH_DAYS;
670: int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
671: - (int) Math.floor((double) (year - 1) / 100.);
672:
673: if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover)
674: relativeDay += gregFactor;
675: else
676: relativeDay -= 2;
677:
678: time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay;
679:
680:
681: int weekday = (int) (relativeDay + THURSDAY) % 7;
682: if (weekday <= 0)
683: weekday += 7;
684: fields[DAY_OF_WEEK] = weekday;
685:
686:
687: TimeZone zone = getTimeZone();
688: int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET]
689: : zone.getRawOffset();
690:
691: int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET]
692: : (zone.getOffset((year < 0) ? BC : AD,
693: (year < 0) ? 1 - year
694: : year,
695: month, day, weekday,
696: millisInDay)
697: - zone.getRawOffset());
698:
699: time -= rawOffset + dstOffset;
700:
701: isTimeSet = true;
702: }
703:
704:
715: private long getLinearDay(int year, int dayOfYear, boolean gregorian)
716: {
717:
718:
719:
720:
721: long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1)
722: - EPOCH_DAYS;
723:
724: if (gregorian)
725: {
726:
727:
728:
729:
730:
731:
732:
733:
734:
735: int gregOffset = (int) Math.floor((double) (year - 1) / 400.)
736: - (int) Math.floor((double) (year - 1) / 100.);
737:
738: return julianDay + gregOffset;
739: }
740: else
741: julianDay -= 2;
742: return julianDay;
743: }
744:
745:
753: private void calculateDay(int[] fields, long day, boolean gregorian)
754: {
755:
756: int weekday = (int) (day + THURSDAY) % 7;
757: if (weekday <= 0)
758: weekday += 7;
759: fields[DAY_OF_WEEK] = weekday;
760:
761:
762:
763: int year = 1970
764: + (int) (gregorian
765: ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L
766: + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L));
767: if (day >= 0)
768: year++;
769:
770: long firstDayOfYear = getLinearDay(year, 1, gregorian);
771:
772:
773: if (day < firstDayOfYear)
774: {
775: year--;
776: firstDayOfYear = getLinearDay(year, 1, gregorian);
777: }
778:
779: day -= firstDayOfYear - 1;
780:
781: fields[DAY_OF_YEAR] = (int) day;
782: if (year <= 0)
783: {
784: fields[ERA] = BC;
785: fields[YEAR] = 1 - year;
786: }
787: else
788: {
789: fields[ERA] = AD;
790: fields[YEAR] = year;
791: }
792:
793: int leapday = isLeapYear(year) ? 1 : 0;
794: if (day <= 31 + 28 + leapday)
795: {
796: fields[MONTH] = (int) day / 32;
797: fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH];
798: }
799: else
800: {
801:
802: int scaledDay = ((int) day - leapday) * 5 + 8;
803: fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31);
804: fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1;
805: }
806: }
807:
808:
813: protected synchronized void computeFields()
814: {
815: boolean gregorian = (time >= gregorianCutover);
816:
817: TimeZone zone = getTimeZone();
818: fields[ZONE_OFFSET] = zone.getRawOffset();
819: long localTime = time + fields[ZONE_OFFSET];
820:
821: long day = localTime / (24 * 60 * 60 * 1000L);
822: int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
823:
824: if (millisInDay < 0)
825: {
826: millisInDay += (24 * 60 * 60 * 1000);
827: day--;
828: }
829:
830: calculateDay(fields, day, gregorian);
831: fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR],
832: fields[MONTH], fields[DAY_OF_MONTH],
833: fields[DAY_OF_WEEK], millisInDay)
834: - fields[ZONE_OFFSET];
835:
836: millisInDay += fields[DST_OFFSET];
837: if (millisInDay >= 24 * 60 * 60 * 1000)
838: {
839: millisInDay -= 24 * 60 * 60 * 1000;
840: calculateDay(fields, ++day, gregorian);
841: }
842:
843: fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7;
844:
845:
846: int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7;
847:
848: fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7;
849:
850: int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7;
851:
852:
853:
854: int minDays = getMinimalDaysInFirstWeek();
855: int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays)
856: - getFirstDayOfWeek()) % 7;
857: if (minDays - firstWeekday < 1)
858: weekOfYear++;
859: fields[WEEK_OF_YEAR] = weekOfYear;
860:
861: int hourOfDay = millisInDay / (60 * 60 * 1000);
862: fields[AM_PM] = (hourOfDay < 12) ? AM : PM;
863: int hour = hourOfDay % 12;
864: fields[HOUR] = hour;
865: fields[HOUR_OF_DAY] = hourOfDay;
866: millisInDay %= (60 * 60 * 1000);
867: fields[MINUTE] = millisInDay / (60 * 1000);
868: millisInDay %= (60 * 1000);
869: fields[SECOND] = millisInDay / (1000);
870: fields[MILLISECOND] = millisInDay % 1000;
871:
872: 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;
873: }
874:
875:
880: public int hashCode()
881: {
882: int val = (int) ((gregorianCutover >>> 32) ^ (gregorianCutover & 0xffffffff));
883: return super.hashCode() ^ val;
884: }
885:
886:
901: public boolean equals(Object o)
902: {
903: if (! (o instanceof GregorianCalendar))
904: return false;
905:
906: GregorianCalendar cal = (GregorianCalendar) o;
907: return (cal.gregorianCutover == gregorianCutover
908: && super.equals(o));
909: }
910:
911:
922: public void add(int field, int amount)
923: {
924: switch (field)
925: {
926: case YEAR:
927: complete();
928: fields[YEAR] += amount;
929: isTimeSet = false;
930: break;
931: case MONTH:
932: complete();
933: int months = fields[MONTH] + amount;
934: fields[YEAR] += months / 12;
935: fields[MONTH] = months % 12;
936: if (fields[MONTH] < 0)
937: {
938: fields[MONTH] += 12;
939: fields[YEAR]--;
940: }
941: int maxDay = getActualMaximum(DAY_OF_MONTH);
942: if (fields[DAY_OF_MONTH] > maxDay)
943: fields[DAY_OF_MONTH] = maxDay;
944: set(YEAR, fields[YEAR]);
945: set(MONTH, fields[MONTH]);
946: break;
947: case DAY_OF_MONTH:
948: case DAY_OF_YEAR:
949: case DAY_OF_WEEK:
950: if (! isTimeSet)
951: computeTime();
952: time += amount * (24 * 60 * 60 * 1000L);
953: areFieldsSet = false;
954: break;
955: case WEEK_OF_YEAR:
956: case WEEK_OF_MONTH:
957: case DAY_OF_WEEK_IN_MONTH:
958: if (! isTimeSet)
959: computeTime();
960: time += amount * (7 * 24 * 60 * 60 * 1000L);
961: areFieldsSet = false;
962: break;
963: case AM_PM:
964: if (! isTimeSet)
965: computeTime();
966: time += amount * (12 * 60 * 60 * 1000L);
967: areFieldsSet = false;
968: break;
969: case HOUR:
970: case HOUR_OF_DAY:
971: if (! isTimeSet)
972: computeTime();
973: time += amount * (60 * 60 * 1000L);
974: areFieldsSet = false;
975: break;
976: case MINUTE:
977: if (! isTimeSet)
978: computeTime();
979: time += amount * (60 * 1000L);
980: areFieldsSet = false;
981: break;
982: case SECOND:
983: if (! isTimeSet)
984: computeTime();
985: time += amount * (1000L);
986: areFieldsSet = false;
987: break;
988: case MILLISECOND:
989: if (! isTimeSet)
990: computeTime();
991: time += amount;
992: areFieldsSet = false;
993: break;
994: case ZONE_OFFSET:
995: case DST_OFFSET:default:
996: throw new IllegalArgumentException("Invalid or unknown field");
997: }
998: }
999:
1000:
1019: public void roll(int field, boolean up)
1020: {
1021: roll(field, up ? 1 : -1);
1022: }
1023:
1024:
1033: private void cleanUpAfterRoll(int field, int delta)
1034: {
1035: switch (field)
1036: {
1037: case ERA:
1038: case YEAR:
1039: case MONTH:
1040:
1041: if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH))
1042: fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH);
1043: isTimeSet = false;
1044: isSet[WEEK_OF_MONTH] = false;
1045: isSet[DAY_OF_WEEK] = false;
1046: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1047: isSet[DAY_OF_YEAR] = false;
1048: isSet[WEEK_OF_YEAR] = false;
1049: break;
1050: case DAY_OF_MONTH:
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: time += delta * (24 * 60 * 60 * 1000L);
1057: break;
1058: case WEEK_OF_MONTH:
1059: isSet[DAY_OF_MONTH] = false;
1060: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1061: isSet[DAY_OF_YEAR] = false;
1062: isSet[WEEK_OF_YEAR] = false;
1063: time += delta * (7 * 24 * 60 * 60 * 1000L);
1064: break;
1065: case DAY_OF_WEEK_IN_MONTH:
1066: isSet[DAY_OF_MONTH] = false;
1067: isSet[WEEK_OF_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_YEAR:
1073: isSet[MONTH] = false;
1074: isSet[DAY_OF_MONTH] = false;
1075: isSet[WEEK_OF_MONTH] = false;
1076: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1077: isSet[DAY_OF_WEEK] = false;
1078: isSet[WEEK_OF_YEAR] = false;
1079: time += delta * (24 * 60 * 60 * 1000L);
1080: break;
1081: case WEEK_OF_YEAR:
1082: isSet[MONTH] = false;
1083: isSet[DAY_OF_MONTH] = false;
1084: isSet[WEEK_OF_MONTH] = false;
1085: isSet[DAY_OF_WEEK_IN_MONTH] = false;
1086: isSet[DAY_OF_YEAR] = false;
1087: time += delta * (7 * 24 * 60 * 60 * 1000L);
1088: break;
1089: case AM_PM:
1090: isSet[HOUR_OF_DAY] = false;
1091: time += delta * (12 * 60 * 60 * 1000L);
1092: break;
1093: case HOUR:
1094: isSet[HOUR_OF_DAY] = false;
1095: time += delta * (60 * 60 * 1000L);
1096: break;
1097: case HOUR_OF_DAY:
1098: isSet[HOUR] = false;
1099: isSet[AM_PM] = false;
1100: time += delta * (60 * 60 * 1000L);
1101: break;
1102: case MINUTE:
1103: time += delta * (60 * 1000L);
1104: break;
1105: case SECOND:
1106: time += delta * (1000L);
1107: break;
1108: case MILLISECOND:
1109: time += delta;
1110: break;
1111: }
1112: }
1113:
1114:
1132: public void roll(int field, int amount)
1133: {
1134: switch (field)
1135: {
1136: case DAY_OF_WEEK:
1137:
1138: add(field, amount);
1139: return;
1140: case ZONE_OFFSET:
1141: case DST_OFFSET:
1142: throw new IllegalArgumentException("Can't roll time zone");
1143: }
1144: complete();
1145: int min = getActualMinimum(field);
1146: int range = getActualMaximum(field) - min + 1;
1147: int oldval = fields[field];
1148: int newval = (oldval - min + range + amount) % range + min;
1149: if (newval < min)
1150: newval += range;
1151: fields[field] = newval;
1152: cleanUpAfterRoll(field, newval - oldval);
1153: }
1154:
1155:
1158: private static final int[] minimums =
1159: {
1160: BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM,
1161: 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000),
1162: 0
1163: };
1164:
1165:
1168: private static final int[] maximums =
1169: {
1170: AD, 5000000, 11, 53, 5, 31, 366,
1171: SATURDAY, 5, PM, 12, 23, 59, 59, 999,
1172: +(12 * 60 * 60 * 1000),
1173: (12 * 60 * 60 * 1000)
1174: };
1175:
1176:
1182: public int getMinimum(int field)
1183: {
1184: return minimums[field];
1185: }
1186:
1187:
1193: public int getMaximum(int field)
1194: {
1195: return maximums[field];
1196: }
1197:
1198:
1207: public int getGreatestMinimum(int field)
1208: {
1209: if (field == WEEK_OF_YEAR)
1210: return 1;
1211: return minimums[field];
1212: }
1213:
1214:
1226: public int getLeastMaximum(int field)
1227: {
1228: switch (field)
1229: {
1230: case WEEK_OF_YEAR:
1231: return 52;
1232: case DAY_OF_MONTH:
1233: return 28;
1234: case DAY_OF_YEAR:
1235: return 365;
1236: case DAY_OF_WEEK_IN_MONTH:
1237: case WEEK_OF_MONTH:
1238: return 4;
1239: default:
1240: return maximums[field];
1241: }
1242: }
1243:
1244:
1255: public int getActualMinimum(int field)
1256: {
1257: if (field == WEEK_OF_YEAR)
1258: {
1259: int min = getMinimalDaysInFirstWeek();
1260: if (min == 0)
1261: return 1;
1262: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1263: complete();
1264:
1265: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1266: int weekday = getWeekDay(year, min);
1267: if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1)
1268: return 1;
1269: return 0;
1270: }
1271: return minimums[field];
1272: }
1273:
1274:
1285: public int getActualMaximum(int field)
1286: {
1287: switch (field)
1288: {
1289: case WEEK_OF_YEAR:
1290: {
1291: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1292: complete();
1293:
1294:
1295:
1296:
1297: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1298: int lastDay = isLeapYear(year) ? 366 : 365;
1299: int weekday = getWeekDay(year, lastDay);
1300: int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1301:
1302: int minimalDays = getMinimalDaysInFirstWeek();
1303: int firstWeekday = getWeekDay(year, minimalDays);
1304:
1309: if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1)
1310: return week + 1;
1311: }
1312: case DAY_OF_MONTH:
1313: {
1314: if (! areFieldsSet || ! isSet[MONTH])
1315: complete();
1316: int month = fields[MONTH];
1317:
1318:
1319:
1320: if (month == FEBRUARY)
1321: {
1322: if (! isSet[YEAR] || ! isSet[ERA])
1323: complete();
1324: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1325: return isLeapYear(year) ? 29 : 28;
1326: }
1327: else if (month < AUGUST)
1328: return 31 - (month & 1);
1329: else
1330: return 30 + (month & 1);
1331: }
1332: case DAY_OF_YEAR:
1333: {
1334: if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR])
1335: complete();
1336: int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR];
1337: return isLeapYear(year) ? 366 : 365;
1338: }
1339: case DAY_OF_WEEK_IN_MONTH:
1340: {
1341:
1342: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1343:
1344:
1345: return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7;
1346: }
1347: case WEEK_OF_MONTH:
1348: {
1349: int daysInMonth = getActualMaximum(DAY_OF_MONTH);
1350: int weekday = (daysInMonth - fields[DAY_OF_MONTH]
1351: + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY;
1352: return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7;
1353: }
1354: default:
1355: return maximums[field];
1356: }
1357: }
1358: }