1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.joda.time.chrono;
17
18 import java.util.Locale;
19
20 import org.joda.time.Chronology;
21 import org.joda.time.DateTimeConstants;
22 import org.joda.time.DateTimeField;
23 import org.joda.time.DateTimeFieldType;
24 import org.joda.time.DateTimeZone;
25 import org.joda.time.DurationField;
26 import org.joda.time.DurationFieldType;
27 import org.joda.time.field.DividedDateTimeField;
28 import org.joda.time.field.FieldUtils;
29 import org.joda.time.field.MillisDurationField;
30 import org.joda.time.field.OffsetDateTimeField;
31 import org.joda.time.field.PreciseDateTimeField;
32 import org.joda.time.field.PreciseDurationField;
33 import org.joda.time.field.RemainderDateTimeField;
34 import org.joda.time.field.ZeroIsMaxDateTimeField;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 abstract class BasicChronology extends AssembledChronology {
51
52
53 private static final long serialVersionUID = 8283225332206808863L;
54
55 private static final DurationField cMillisField;
56 private static final DurationField cSecondsField;
57 private static final DurationField cMinutesField;
58 private static final DurationField cHoursField;
59 private static final DurationField cHalfdaysField;
60 private static final DurationField cDaysField;
61 private static final DurationField cWeeksField;
62
63 private static final DateTimeField cMillisOfSecondField;
64 private static final DateTimeField cMillisOfDayField;
65 private static final DateTimeField cSecondOfMinuteField;
66 private static final DateTimeField cSecondOfDayField;
67 private static final DateTimeField cMinuteOfHourField;
68 private static final DateTimeField cMinuteOfDayField;
69 private static final DateTimeField cHourOfDayField;
70 private static final DateTimeField cHourOfHalfdayField;
71 private static final DateTimeField cClockhourOfDayField;
72 private static final DateTimeField cClockhourOfHalfdayField;
73 private static final DateTimeField cHalfdayOfDayField;
74
75 static {
76 cMillisField = MillisDurationField.INSTANCE;
77 cSecondsField = new PreciseDurationField
78 (DurationFieldType.seconds(), DateTimeConstants.MILLIS_PER_SECOND);
79 cMinutesField = new PreciseDurationField
80 (DurationFieldType.minutes(), DateTimeConstants.MILLIS_PER_MINUTE);
81 cHoursField = new PreciseDurationField
82 (DurationFieldType.hours(), DateTimeConstants.MILLIS_PER_HOUR);
83 cHalfdaysField = new PreciseDurationField
84 (DurationFieldType.halfdays(), DateTimeConstants.MILLIS_PER_DAY / 2);
85 cDaysField = new PreciseDurationField
86 (DurationFieldType.days(), DateTimeConstants.MILLIS_PER_DAY);
87 cWeeksField = new PreciseDurationField
88 (DurationFieldType.weeks(), DateTimeConstants.MILLIS_PER_WEEK);
89
90 cMillisOfSecondField = new PreciseDateTimeField
91 (DateTimeFieldType.millisOfSecond(), cMillisField, cSecondsField);
92
93 cMillisOfDayField = new PreciseDateTimeField
94 (DateTimeFieldType.millisOfDay(), cMillisField, cDaysField);
95
96 cSecondOfMinuteField = new PreciseDateTimeField
97 (DateTimeFieldType.secondOfMinute(), cSecondsField, cMinutesField);
98
99 cSecondOfDayField = new PreciseDateTimeField
100 (DateTimeFieldType.secondOfDay(), cSecondsField, cDaysField);
101
102 cMinuteOfHourField = new PreciseDateTimeField
103 (DateTimeFieldType.minuteOfHour(), cMinutesField, cHoursField);
104
105 cMinuteOfDayField = new PreciseDateTimeField
106 (DateTimeFieldType.minuteOfDay(), cMinutesField, cDaysField);
107
108 cHourOfDayField = new PreciseDateTimeField
109 (DateTimeFieldType.hourOfDay(), cHoursField, cDaysField);
110
111 cHourOfHalfdayField = new PreciseDateTimeField
112 (DateTimeFieldType.hourOfHalfday(), cHoursField, cHalfdaysField);
113
114 cClockhourOfDayField = new ZeroIsMaxDateTimeField
115 (cHourOfDayField, DateTimeFieldType.clockhourOfDay());
116
117 cClockhourOfHalfdayField = new ZeroIsMaxDateTimeField
118 (cHourOfHalfdayField, DateTimeFieldType.clockhourOfHalfday());
119
120 cHalfdayOfDayField = new HalfdayField();
121 }
122
123 private static final int CACHE_SIZE = 1 << 10;
124 private static final int CACHE_MASK = CACHE_SIZE - 1;
125
126 private transient final YearInfo[] iYearInfoCache = new YearInfo[CACHE_SIZE];
127
128 private final int iMinDaysInFirstWeek;
129
130 BasicChronology(Chronology base, Object param, int minDaysInFirstWeek) {
131 super(base, param);
132
133 if (minDaysInFirstWeek < 1 || minDaysInFirstWeek > 7) {
134 throw new IllegalArgumentException
135 ("Invalid min days in first week: " + minDaysInFirstWeek);
136 }
137
138 iMinDaysInFirstWeek = minDaysInFirstWeek;
139 }
140
141 public DateTimeZone getZone() {
142 Chronology base;
143 if ((base = getBase()) != null) {
144 return base.getZone();
145 }
146 return DateTimeZone.UTC;
147 }
148
149 public long getDateTimeMillis(
150 int year, int monthOfYear, int dayOfMonth, int millisOfDay)
151 throws IllegalArgumentException {
152 Chronology base;
153 if ((base = getBase()) != null) {
154 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
155 }
156
157 FieldUtils.verifyValueBounds
158 (DateTimeFieldType.millisOfDay(), millisOfDay, 0, DateTimeConstants.MILLIS_PER_DAY - 1);
159 return getDateMidnightMillis(year, monthOfYear, dayOfMonth) + millisOfDay;
160 }
161
162 public long getDateTimeMillis(
163 int year, int monthOfYear, int dayOfMonth,
164 int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond)
165 throws IllegalArgumentException {
166 Chronology base;
167 if ((base = getBase()) != null) {
168 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth,
169 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
170 }
171
172 FieldUtils.verifyValueBounds(DateTimeFieldType.hourOfDay(), hourOfDay, 0, 23);
173 FieldUtils.verifyValueBounds(DateTimeFieldType.minuteOfHour(), minuteOfHour, 0, 59);
174 FieldUtils.verifyValueBounds(DateTimeFieldType.secondOfMinute(), secondOfMinute, 0, 59);
175 FieldUtils.verifyValueBounds(DateTimeFieldType.millisOfSecond(), millisOfSecond, 0, 999);
176
177 return getDateMidnightMillis(year, monthOfYear, dayOfMonth)
178 + hourOfDay * DateTimeConstants.MILLIS_PER_HOUR
179 + minuteOfHour * DateTimeConstants.MILLIS_PER_MINUTE
180 + secondOfMinute * DateTimeConstants.MILLIS_PER_SECOND
181 + millisOfSecond;
182 }
183
184 public int getMinimumDaysInFirstWeek() {
185 return iMinDaysInFirstWeek;
186 }
187
188
189
190
191
192
193
194
195 public boolean equals(Object obj) {
196 return super.equals(obj);
197 }
198
199
200
201
202
203
204
205 public int hashCode() {
206 return getClass().getName().hashCode() * 11 + getZone().hashCode() + getMinimumDaysInFirstWeek();
207 }
208
209
210
211
212
213
214
215
216 public String toString() {
217 StringBuilder sb = new StringBuilder(60);
218 String name = getClass().getName();
219 int index = name.lastIndexOf('.');
220 if (index >= 0) {
221 name = name.substring(index + 1);
222 }
223 sb.append(name);
224 sb.append('[');
225 DateTimeZone zone = getZone();
226 if (zone != null) {
227 sb.append(zone.getID());
228 }
229 if (getMinimumDaysInFirstWeek() != 4) {
230 sb.append(",mdfw=");
231 sb.append(getMinimumDaysInFirstWeek());
232 }
233 sb.append(']');
234 return sb.toString();
235 }
236
237 protected void assemble(Fields fields) {
238
239
240
241 fields.millis = cMillisField;
242 fields.seconds = cSecondsField;
243 fields.minutes = cMinutesField;
244 fields.hours = cHoursField;
245 fields.halfdays = cHalfdaysField;
246 fields.days = cDaysField;
247 fields.weeks = cWeeksField;
248
249 fields.millisOfSecond = cMillisOfSecondField;
250 fields.millisOfDay = cMillisOfDayField;
251 fields.secondOfMinute = cSecondOfMinuteField;
252 fields.secondOfDay = cSecondOfDayField;
253 fields.minuteOfHour = cMinuteOfHourField;
254 fields.minuteOfDay = cMinuteOfDayField;
255 fields.hourOfDay = cHourOfDayField;
256 fields.hourOfHalfday = cHourOfHalfdayField;
257 fields.clockhourOfDay = cClockhourOfDayField;
258 fields.clockhourOfHalfday = cClockhourOfHalfdayField;
259 fields.halfdayOfDay = cHalfdayOfDayField;
260
261
262
263
264 fields.year = new BasicYearDateTimeField(this);
265 fields.yearOfEra = new GJYearOfEraDateTimeField(fields.year, this);
266
267
268 DateTimeField field = new OffsetDateTimeField(
269 fields.yearOfEra, 99);
270 fields.centuryOfEra = new DividedDateTimeField(
271 field, DateTimeFieldType.centuryOfEra(), 100);
272
273 field = new RemainderDateTimeField(
274 (DividedDateTimeField) fields.centuryOfEra);
275 fields.yearOfCentury = new OffsetDateTimeField(
276 field, DateTimeFieldType.yearOfCentury(), 1);
277
278 fields.era = new GJEraDateTimeField(this);
279 fields.dayOfWeek = new GJDayOfWeekDateTimeField(this, fields.days);
280 fields.dayOfMonth = new BasicDayOfMonthDateTimeField(this, fields.days);
281 fields.dayOfYear = new BasicDayOfYearDateTimeField(this, fields.days);
282 fields.monthOfYear = new GJMonthOfYearDateTimeField(this);
283 fields.weekyear = new BasicWeekyearDateTimeField(this);
284 fields.weekOfWeekyear = new BasicWeekOfWeekyearDateTimeField(this, fields.weeks);
285
286 field = new RemainderDateTimeField(
287 fields.weekyear, DateTimeFieldType.weekyearOfCentury(), 100);
288 fields.weekyearOfCentury = new OffsetDateTimeField(
289 field, DateTimeFieldType.weekyearOfCentury(), 1);
290
291
292
293
294 fields.years = fields.year.getDurationField();
295 fields.centuries = fields.centuryOfEra.getDurationField();
296 fields.months = fields.monthOfYear.getDurationField();
297 fields.weekyears = fields.weekyear.getDurationField();
298 }
299
300
301
302
303
304
305
306 int getDaysInYearMax() {
307 return 366;
308 }
309
310
311
312
313
314
315
316 int getDaysInYear(int year) {
317 return isLeapYear(year) ? 366 : 365;
318 }
319
320
321
322
323
324
325
326 int getWeeksInYear(int year) {
327 long firstWeekMillis1 = getFirstWeekOfYearMillis(year);
328 long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1);
329 return (int) ((firstWeekMillis2 - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK);
330 }
331
332
333
334
335
336
337
338 long getFirstWeekOfYearMillis(int year) {
339 long jan1millis = getYearMillis(year);
340 int jan1dayOfWeek = getDayOfWeek(jan1millis);
341
342 if (jan1dayOfWeek > (8 - iMinDaysInFirstWeek)) {
343
344 return jan1millis + (8 - jan1dayOfWeek)
345 * (long)DateTimeConstants.MILLIS_PER_DAY;
346 } else {
347
348 return jan1millis - (jan1dayOfWeek - 1)
349 * (long)DateTimeConstants.MILLIS_PER_DAY;
350 }
351 }
352
353
354
355
356
357
358
359 long getYearMillis(int year) {
360 return getYearInfo(year).iFirstDayMillis;
361 }
362
363
364
365
366
367
368
369
370 long getYearMonthMillis(int year, int month) {
371 long millis = getYearMillis(year);
372 millis += getTotalMillisByYearMonth(year, month);
373 return millis;
374 }
375
376
377
378
379
380
381
382
383
384 long getYearMonthDayMillis(int year, int month, int dayOfMonth) {
385 long millis = getYearMillis(year);
386 millis += getTotalMillisByYearMonth(year, month);
387 return millis + (dayOfMonth - 1) * (long)DateTimeConstants.MILLIS_PER_DAY;
388 }
389
390
391
392
393 int getYear(long instant) {
394
395
396
397
398
399 long unitMillis = getAverageMillisPerYearDividedByTwo();
400 long i2 = (instant >> 1) + getApproxMillisAtEpochDividedByTwo();
401 if (i2 < 0) {
402 i2 = i2 - unitMillis + 1;
403 }
404 int year = (int) (i2 / unitMillis);
405
406 long yearStart = getYearMillis(year);
407 long diff = instant - yearStart;
408
409 if (diff < 0) {
410 year--;
411 } else if (diff >= DateTimeConstants.MILLIS_PER_DAY * 365L) {
412
413 long oneYear;
414 if (isLeapYear(year)) {
415 oneYear = DateTimeConstants.MILLIS_PER_DAY * 366L;
416 } else {
417 oneYear = DateTimeConstants.MILLIS_PER_DAY * 365L;
418 }
419
420 yearStart += oneYear;
421
422 if (yearStart <= instant) {
423
424 year++;
425 }
426 }
427
428 return year;
429 }
430
431
432
433
434 int getMonthOfYear(long millis) {
435 return getMonthOfYear(millis, getYear(millis));
436 }
437
438
439
440
441
442 abstract int getMonthOfYear(long millis, int year);
443
444
445
446
447 int getDayOfMonth(long millis) {
448 int year = getYear(millis);
449 int month = getMonthOfYear(millis, year);
450 return getDayOfMonth(millis, year, month);
451 }
452
453
454
455
456
457 int getDayOfMonth(long millis, int year) {
458 int month = getMonthOfYear(millis, year);
459 return getDayOfMonth(millis, year, month);
460 }
461
462
463
464
465
466
467 int getDayOfMonth(long millis, int year, int month) {
468 long dateMillis = getYearMillis(year);
469 dateMillis += getTotalMillisByYearMonth(year, month);
470 return (int) ((millis - dateMillis) / DateTimeConstants.MILLIS_PER_DAY) + 1;
471 }
472
473
474
475
476 int getDayOfYear(long instant) {
477 return getDayOfYear(instant, getYear(instant));
478 }
479
480
481
482
483
484 int getDayOfYear(long instant, int year) {
485 long yearStart = getYearMillis(year);
486 return (int) ((instant - yearStart) / DateTimeConstants.MILLIS_PER_DAY) + 1;
487 }
488
489
490
491
492 int getWeekyear(long instant) {
493 int year = getYear(instant);
494 int week = getWeekOfWeekyear(instant, year);
495 if (week == 1) {
496 return getYear(instant + DateTimeConstants.MILLIS_PER_WEEK);
497 } else if (week > 51) {
498 return getYear(instant - (2 * DateTimeConstants.MILLIS_PER_WEEK));
499 } else {
500 return year;
501 }
502 }
503
504
505
506
507 int getWeekOfWeekyear(long instant) {
508 return getWeekOfWeekyear(instant, getYear(instant));
509 }
510
511
512
513
514
515 int getWeekOfWeekyear(long instant, int year) {
516 long firstWeekMillis1 = getFirstWeekOfYearMillis(year);
517 if (instant < firstWeekMillis1) {
518 return getWeeksInYear(year - 1);
519 }
520 long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1);
521 if (instant >= firstWeekMillis2) {
522 return 1;
523 }
524 return (int) ((instant - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK) + 1;
525 }
526
527
528
529
530 int getDayOfWeek(long instant) {
531
532
533 long daysSince19700101;
534 if (instant >= 0) {
535 daysSince19700101 = instant / DateTimeConstants.MILLIS_PER_DAY;
536 } else {
537 daysSince19700101 = (instant - (DateTimeConstants.MILLIS_PER_DAY - 1))
538 / DateTimeConstants.MILLIS_PER_DAY;
539 if (daysSince19700101 < -3) {
540 return 7 + (int) ((daysSince19700101 + 4) % 7);
541 }
542 }
543
544 return 1 + (int) ((daysSince19700101 + 3) % 7);
545 }
546
547
548
549
550 int getMillisOfDay(long instant) {
551 if (instant >= 0) {
552 return (int) (instant % DateTimeConstants.MILLIS_PER_DAY);
553 } else {
554 return (DateTimeConstants.MILLIS_PER_DAY - 1)
555 + (int) ((instant + 1) % DateTimeConstants.MILLIS_PER_DAY);
556 }
557 }
558
559
560
561
562
563
564 int getDaysInMonthMax() {
565 return 31;
566 }
567
568
569
570
571
572
573
574 int getDaysInMonthMax(long instant) {
575 int thisYear = getYear(instant);
576 int thisMonth = getMonthOfYear(instant, thisYear);
577 return getDaysInYearMonth(thisYear, thisMonth);
578 }
579
580
581
582
583
584
585
586
587
588
589 int getDaysInMonthMaxForSet(long instant, int value) {
590 return getDaysInMonthMax(instant);
591 }
592
593
594
595
596
597
598
599
600
601
602 long getDateMidnightMillis(int year, int monthOfYear, int dayOfMonth) {
603 FieldUtils.verifyValueBounds(DateTimeFieldType.year(), year, getMinYear(), getMaxYear());
604 FieldUtils.verifyValueBounds(DateTimeFieldType.monthOfYear(), monthOfYear, 1, getMaxMonth(year));
605 FieldUtils.verifyValueBounds(DateTimeFieldType.dayOfMonth(), dayOfMonth, 1, getDaysInYearMonth(year, monthOfYear));
606 return getYearMonthDayMillis(year, monthOfYear, dayOfMonth);
607 }
608
609
610
611
612
613
614
615
616 abstract long getYearDifference(long minuendInstant, long subtrahendInstant);
617
618
619
620
621
622
623
624 abstract boolean isLeapYear(int year);
625
626
627
628
629
630
631
632
633 abstract int getDaysInYearMonth(int year, int month);
634
635
636
637
638
639
640
641 abstract int getDaysInMonthMax(int month);
642
643
644
645
646
647
648
649
650
651 abstract long getTotalMillisByYearMonth(int year, int month);
652
653
654
655
656
657
658 abstract long calculateFirstDayOfYearMillis(int year);
659
660
661
662
663
664
665 abstract int getMinYear();
666
667
668
669
670
671
672 abstract int getMaxYear();
673
674
675
676
677
678
679
680
681 int getMaxMonth(int year) {
682 return getMaxMonth();
683 }
684
685
686
687
688
689
690 int getMaxMonth() {
691 return 12;
692 }
693
694
695
696
697
698
699 abstract long getAverageMillisPerYear();
700
701
702
703
704
705
706 abstract long getAverageMillisPerYearDividedByTwo();
707
708
709
710
711
712
713 abstract long getAverageMillisPerMonth();
714
715
716
717
718
719
720
721
722
723
724 abstract long getApproxMillisAtEpochDividedByTwo();
725
726
727
728
729
730
731
732
733 abstract long setYear(long instant, int year);
734
735
736
737 private YearInfo getYearInfo(int year) {
738 YearInfo info = iYearInfoCache[year & CACHE_MASK];
739 if (info == null || info.iYear != year) {
740 info = new YearInfo(year, calculateFirstDayOfYearMillis(year));
741 iYearInfoCache[year & CACHE_MASK] = info;
742 }
743 return info;
744 }
745
746 private static class HalfdayField extends PreciseDateTimeField {
747 private static final long serialVersionUID = 581601443656929254L;
748
749 HalfdayField() {
750 super(DateTimeFieldType.halfdayOfDay(), cHalfdaysField, cDaysField);
751 }
752
753 public String getAsText(int fieldValue, Locale locale) {
754 return GJLocaleSymbols.forLocale(locale).halfdayValueToText(fieldValue);
755 }
756
757 public long set(long millis, String text, Locale locale) {
758 return set(millis, GJLocaleSymbols.forLocale(locale).halfdayTextToValue(text));
759 }
760
761 public int getMaximumTextLength(Locale locale) {
762 return GJLocaleSymbols.forLocale(locale).getHalfdayMaxTextLength();
763 }
764 }
765
766 private static class YearInfo {
767 public final int iYear;
768 public final long iFirstDayMillis;
769
770 YearInfo(int year, long firstDayMillis) {
771 iYear = year;
772 iFirstDayMillis = firstDayMillis;
773 }
774 }
775
776 }