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.ArrayList;
19 import java.util.HashMap;
20 import java.util.Locale;
21 import java.util.Map;
22
23 import org.joda.time.Chronology;
24 import org.joda.time.DateTimeField;
25 import org.joda.time.DateTimeUtils;
26 import org.joda.time.DateTimeZone;
27 import org.joda.time.DurationField;
28 import org.joda.time.IllegalFieldValueException;
29 import org.joda.time.Instant;
30 import org.joda.time.ReadableInstant;
31 import org.joda.time.ReadablePartial;
32 import org.joda.time.field.BaseDateTimeField;
33 import org.joda.time.field.DecoratedDurationField;
34 import org.joda.time.format.DateTimeFormatter;
35 import org.joda.time.format.ISODateTimeFormat;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public final class GJChronology extends AssembledChronology {
75
76
77 private static final long serialVersionUID = -2545574827706931671L;
78
79
80
81
82 private static long convertByYear(long instant, Chronology from, Chronology to) {
83 return to.getDateTimeMillis
84 (from.year().get(instant),
85 from.monthOfYear().get(instant),
86 from.dayOfMonth().get(instant),
87 from.millisOfDay().get(instant));
88 }
89
90
91
92
93 private static long convertByWeekyear(final long instant, Chronology from, Chronology to) {
94 long newInstant;
95 newInstant = to.weekyear().set(0, from.weekyear().get(instant));
96 newInstant = to.weekOfWeekyear().set(newInstant, from.weekOfWeekyear().get(instant));
97 newInstant = to.dayOfWeek().set(newInstant, from.dayOfWeek().get(instant));
98 newInstant = to.millisOfDay().set(newInstant, from.millisOfDay().get(instant));
99 return newInstant;
100 }
101
102
103
104
105 static final Instant DEFAULT_CUTOVER = new Instant(-12219292800000L);
106
107
108 private static final Map<DateTimeZone, ArrayList<GJChronology>> cCache = new HashMap<DateTimeZone, ArrayList<GJChronology>>();
109
110
111
112
113
114
115
116
117
118
119
120
121
122 public static GJChronology getInstanceUTC() {
123 return getInstance(DateTimeZone.UTC, DEFAULT_CUTOVER, 4);
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138 public static GJChronology getInstance() {
139 return getInstance(DateTimeZone.getDefault(), DEFAULT_CUTOVER, 4);
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public static GJChronology getInstance(DateTimeZone zone) {
155 return getInstance(zone, DEFAULT_CUTOVER, 4);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169 public static GJChronology getInstance(
170 DateTimeZone zone,
171 ReadableInstant gregorianCutover) {
172
173 return getInstance(zone, gregorianCutover, 4);
174 }
175
176
177
178
179
180
181
182
183
184 public static synchronized GJChronology getInstance(
185 DateTimeZone zone,
186 ReadableInstant gregorianCutover,
187 int minDaysInFirstWeek) {
188
189 zone = DateTimeUtils.getZone(zone);
190 Instant cutoverInstant;
191 if (gregorianCutover == null) {
192 cutoverInstant = DEFAULT_CUTOVER;
193 } else {
194 cutoverInstant = gregorianCutover.toInstant();
195 }
196
197 GJChronology chrono;
198
199 ArrayList<GJChronology> chronos = cCache.get(zone);
200 if (chronos == null) {
201 chronos = new ArrayList<GJChronology>(2);
202 cCache.put(zone, chronos);
203 } else {
204 for (int i=chronos.size(); --i>=0; ) {
205 chrono = chronos.get(i);
206 if (minDaysInFirstWeek == chrono.getMinimumDaysInFirstWeek() &&
207 cutoverInstant.equals(chrono.getGregorianCutover())) {
208
209 return chrono;
210 }
211 }
212 }
213
214 if (zone == DateTimeZone.UTC) {
215 chrono = new GJChronology
216 (JulianChronology.getInstance(zone, minDaysInFirstWeek),
217 GregorianChronology.getInstance(zone, minDaysInFirstWeek),
218 cutoverInstant);
219 } else {
220 chrono = getInstance(DateTimeZone.UTC, cutoverInstant, minDaysInFirstWeek);
221 chrono = new GJChronology
222 (ZonedChronology.getInstance(chrono, zone),
223 chrono.iJulianChronology,
224 chrono.iGregorianChronology,
225 chrono.iCutoverInstant);
226 }
227
228 chronos.add(chrono);
229
230 return chrono;
231 }
232
233
234
235
236
237
238
239
240
241 public static GJChronology getInstance(
242 DateTimeZone zone,
243 long gregorianCutover,
244 int minDaysInFirstWeek) {
245
246 Instant cutoverInstant;
247 if (gregorianCutover == DEFAULT_CUTOVER.getMillis()) {
248 cutoverInstant = null;
249 } else {
250 cutoverInstant = new Instant(gregorianCutover);
251 }
252 return getInstance(zone, cutoverInstant, minDaysInFirstWeek);
253 }
254
255
256 private JulianChronology iJulianChronology;
257 private GregorianChronology iGregorianChronology;
258 private Instant iCutoverInstant;
259
260 private long iCutoverMillis;
261 private long iGapDuration;
262
263
264
265
266
267
268 private GJChronology(JulianChronology julian,
269 GregorianChronology gregorian,
270 Instant cutoverInstant) {
271 super(null, new Object[] {julian, gregorian, cutoverInstant});
272 }
273
274
275
276
277 private GJChronology(Chronology base,
278 JulianChronology julian,
279 GregorianChronology gregorian,
280 Instant cutoverInstant) {
281 super(base, new Object[] {julian, gregorian, cutoverInstant});
282 }
283
284
285
286
287 private Object readResolve() {
288 return getInstance(getZone(), iCutoverInstant, getMinimumDaysInFirstWeek());
289 }
290
291 public DateTimeZone getZone() {
292 Chronology base;
293 if ((base = getBase()) != null) {
294 return base.getZone();
295 }
296 return DateTimeZone.UTC;
297 }
298
299
300
301
302
303
304
305
306 public Chronology withUTC() {
307 return withZone(DateTimeZone.UTC);
308 }
309
310
311
312
313
314
315
316 public Chronology withZone(DateTimeZone zone) {
317 if (zone == null) {
318 zone = DateTimeZone.getDefault();
319 }
320 if (zone == getZone()) {
321 return this;
322 }
323 return getInstance(zone, iCutoverInstant, getMinimumDaysInFirstWeek());
324 }
325
326 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
327 int millisOfDay)
328 throws IllegalArgumentException
329 {
330 Chronology base;
331 if ((base = getBase()) != null) {
332 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
333 }
334
335
336 long instant = iGregorianChronology.getDateTimeMillis
337 (year, monthOfYear, dayOfMonth, millisOfDay);
338 if (instant < iCutoverMillis) {
339
340 instant = iJulianChronology.getDateTimeMillis
341 (year, monthOfYear, dayOfMonth, millisOfDay);
342 if (instant >= iCutoverMillis) {
343
344 throw new IllegalArgumentException("Specified date does not exist");
345 }
346 }
347 return instant;
348 }
349
350 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
351 int hourOfDay, int minuteOfHour,
352 int secondOfMinute, int millisOfSecond)
353 throws IllegalArgumentException
354 {
355 Chronology base;
356 if ((base = getBase()) != null) {
357 return base.getDateTimeMillis
358 (year, monthOfYear, dayOfMonth,
359 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
360 }
361
362
363 long instant;
364 try {
365 instant = iGregorianChronology.getDateTimeMillis
366 (year, monthOfYear, dayOfMonth,
367 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
368 } catch (IllegalFieldValueException ex) {
369 if (monthOfYear != 2 || dayOfMonth != 29) {
370 throw ex;
371 }
372 instant = iGregorianChronology.getDateTimeMillis
373 (year, monthOfYear, 28,
374 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
375 if (instant >= iCutoverMillis) {
376 throw ex;
377 }
378 }
379 if (instant < iCutoverMillis) {
380
381 instant = iJulianChronology.getDateTimeMillis
382 (year, monthOfYear, dayOfMonth,
383 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
384 if (instant >= iCutoverMillis) {
385
386 throw new IllegalArgumentException("Specified date does not exist");
387 }
388 }
389 return instant;
390 }
391
392
393
394
395
396 public Instant getGregorianCutover() {
397 return iCutoverInstant;
398 }
399
400
401
402
403
404
405 public int getMinimumDaysInFirstWeek() {
406 return iGregorianChronology.getMinimumDaysInFirstWeek();
407 }
408
409
410
411
412
413
414
415
416 public boolean equals(Object obj) {
417 return super.equals(obj);
418 }
419
420
421
422
423
424
425
426 public int hashCode() {
427 return "GJ".hashCode() * 11 + iJulianChronology.hashCode() +
428 iGregorianChronology.hashCode() + iCutoverInstant.hashCode();
429 }
430
431
432
433
434
435
436
437
438 public String toString() {
439 StringBuffer sb = new StringBuffer(60);
440 sb.append("GJChronology");
441 sb.append('[');
442 sb.append(getZone().getID());
443
444 if (iCutoverMillis != DEFAULT_CUTOVER.getMillis()) {
445 sb.append(",cutover=");
446 DateTimeFormatter printer;
447 if (withUTC().dayOfYear().remainder(iCutoverMillis) == 0) {
448 printer = ISODateTimeFormat.date();
449 } else {
450 printer = ISODateTimeFormat.dateTime();
451 }
452 printer.withChronology(withUTC()).printTo(sb, iCutoverMillis);
453 }
454
455 if (getMinimumDaysInFirstWeek() != 4) {
456 sb.append(",mdfw=");
457 sb.append(getMinimumDaysInFirstWeek());
458 }
459 sb.append(']');
460
461 return sb.toString();
462 }
463
464 protected void assemble(Fields fields) {
465 Object[] params = (Object[])getParam();
466
467 JulianChronology julian = (JulianChronology)params[0];
468 GregorianChronology gregorian = (GregorianChronology)params[1];
469 Instant cutoverInstant = (Instant)params[2];
470 iCutoverMillis = cutoverInstant.getMillis();
471
472 iJulianChronology = julian;
473 iGregorianChronology = gregorian;
474 iCutoverInstant = cutoverInstant;
475
476 if (getBase() != null) {
477 return;
478 }
479
480 if (julian.getMinimumDaysInFirstWeek() != gregorian.getMinimumDaysInFirstWeek()) {
481 throw new IllegalArgumentException();
482 }
483
484
485 iGapDuration = iCutoverMillis - julianToGregorianByYear(iCutoverMillis);
486
487
488
489
490
491 fields.copyFieldsFrom(gregorian);
492
493
494
495
496
497 if (gregorian.millisOfDay().get(iCutoverMillis) == 0) {
498
499
500
501 fields.millisOfSecond = new CutoverField(julian.millisOfSecond(), fields.millisOfSecond, iCutoverMillis);
502 fields.millisOfDay = new CutoverField(julian.millisOfDay(), fields.millisOfDay, iCutoverMillis);
503 fields.secondOfMinute = new CutoverField(julian.secondOfMinute(), fields.secondOfMinute, iCutoverMillis);
504 fields.secondOfDay = new CutoverField(julian.secondOfDay(), fields.secondOfDay, iCutoverMillis);
505 fields.minuteOfHour = new CutoverField(julian.minuteOfHour(), fields.minuteOfHour, iCutoverMillis);
506 fields.minuteOfDay = new CutoverField(julian.minuteOfDay(), fields.minuteOfDay, iCutoverMillis);
507 fields.hourOfDay = new CutoverField(julian.hourOfDay(), fields.hourOfDay, iCutoverMillis);
508 fields.hourOfHalfday = new CutoverField(julian.hourOfHalfday(), fields.hourOfHalfday, iCutoverMillis);
509 fields.clockhourOfDay = new CutoverField(julian.clockhourOfDay(), fields.clockhourOfDay, iCutoverMillis);
510 fields.clockhourOfHalfday = new CutoverField(julian.clockhourOfHalfday(),
511 fields.clockhourOfHalfday, iCutoverMillis);
512 fields.halfdayOfDay = new CutoverField(julian.halfdayOfDay(), fields.halfdayOfDay, iCutoverMillis);
513 }
514
515
516 {
517 fields.era = new CutoverField(julian.era(), fields.era, iCutoverMillis);
518 }
519
520
521
522
523
524
525 {
526 long cutover = gregorian.year().roundCeiling(iCutoverMillis);
527 fields.dayOfYear = new CutoverField(
528 julian.dayOfYear(), fields.dayOfYear, cutover);
529 }
530
531 {
532 long cutover = gregorian.weekyear().roundCeiling(iCutoverMillis);
533 fields.weekOfWeekyear = new CutoverField(
534 julian.weekOfWeekyear(), fields.weekOfWeekyear, cutover, true);
535 }
536
537
538
539
540 {
541 fields.year = new ImpreciseCutoverField(
542 julian.year(), fields.year, iCutoverMillis);
543 fields.years = fields.year.getDurationField();
544 fields.yearOfEra = new ImpreciseCutoverField(
545 julian.yearOfEra(), fields.yearOfEra, fields.years, iCutoverMillis);
546 fields.yearOfCentury = new ImpreciseCutoverField(
547 julian.yearOfCentury(), fields.yearOfCentury, fields.years, iCutoverMillis);
548
549 fields.centuryOfEra = new ImpreciseCutoverField(
550 julian.centuryOfEra(), fields.centuryOfEra, iCutoverMillis);
551 fields.centuries = fields.centuryOfEra.getDurationField();
552
553 fields.monthOfYear = new ImpreciseCutoverField(
554 julian.monthOfYear(), fields.monthOfYear, iCutoverMillis);
555 fields.months = fields.monthOfYear.getDurationField();
556
557 fields.weekyear = new ImpreciseCutoverField(
558 julian.weekyear(), fields.weekyear, null, iCutoverMillis, true);
559 fields.weekyearOfCentury = new ImpreciseCutoverField(
560 julian.weekyearOfCentury(), fields.weekyearOfCentury, fields.weekyears, iCutoverMillis);
561 fields.weekyears = fields.weekyear.getDurationField();
562 }
563
564
565
566 {
567 CutoverField cf = new CutoverField
568 (julian.dayOfMonth(), fields.dayOfMonth, iCutoverMillis);
569 cf.iRangeDurationField = fields.months;
570 fields.dayOfMonth = cf;
571 }
572 }
573
574 long julianToGregorianByYear(long instant) {
575 return convertByYear(instant, iJulianChronology, iGregorianChronology);
576 }
577
578 long gregorianToJulianByYear(long instant) {
579 return convertByYear(instant, iGregorianChronology, iJulianChronology);
580 }
581
582 long julianToGregorianByWeekyear(long instant) {
583 return convertByWeekyear(instant, iJulianChronology, iGregorianChronology);
584 }
585
586 long gregorianToJulianByWeekyear(long instant) {
587 return convertByWeekyear(instant, iGregorianChronology, iJulianChronology);
588 }
589
590
591
592
593
594
595 private class CutoverField extends BaseDateTimeField {
596 private static final long serialVersionUID = 3528501219481026402L;
597
598 final DateTimeField iJulianField;
599 final DateTimeField iGregorianField;
600 final long iCutover;
601 final boolean iConvertByWeekyear;
602
603 protected DurationField iDurationField;
604 protected DurationField iRangeDurationField;
605
606
607
608
609
610
611 CutoverField(DateTimeField julianField, DateTimeField gregorianField, long cutoverMillis) {
612 this(julianField, gregorianField, cutoverMillis, false);
613 }
614
615
616
617
618
619
620
621 CutoverField(DateTimeField julianField, DateTimeField gregorianField,
622 long cutoverMillis, boolean convertByWeekyear) {
623 super(gregorianField.getType());
624 iJulianField = julianField;
625 iGregorianField = gregorianField;
626 iCutover = cutoverMillis;
627 iConvertByWeekyear = convertByWeekyear;
628
629
630 iDurationField = gregorianField.getDurationField();
631
632 DurationField rangeField = gregorianField.getRangeDurationField();
633 if (rangeField == null) {
634 rangeField = julianField.getRangeDurationField();
635 }
636 iRangeDurationField = rangeField;
637 }
638
639 public boolean isLenient() {
640 return false;
641 }
642
643 public int get(long instant) {
644 if (instant >= iCutover) {
645 return iGregorianField.get(instant);
646 } else {
647 return iJulianField.get(instant);
648 }
649 }
650
651 public String getAsText(long instant, Locale locale) {
652 if (instant >= iCutover) {
653 return iGregorianField.getAsText(instant, locale);
654 } else {
655 return iJulianField.getAsText(instant, locale);
656 }
657 }
658
659 public String getAsText(int fieldValue, Locale locale) {
660 return iGregorianField.getAsText(fieldValue, locale);
661 }
662
663 public String getAsShortText(long instant, Locale locale) {
664 if (instant >= iCutover) {
665 return iGregorianField.getAsShortText(instant, locale);
666 } else {
667 return iJulianField.getAsShortText(instant, locale);
668 }
669 }
670
671 public String getAsShortText(int fieldValue, Locale locale) {
672 return iGregorianField.getAsShortText(fieldValue, locale);
673 }
674
675 public long add(long instant, int value) {
676 return iGregorianField.add(instant, value);
677 }
678
679 public long add(long instant, long value) {
680 return iGregorianField.add(instant, value);
681 }
682
683 public int[] add(ReadablePartial partial, int fieldIndex, int[] values, int valueToAdd) {
684
685
686 if (valueToAdd == 0) {
687 return values;
688 }
689 if (DateTimeUtils.isContiguous(partial)) {
690 long instant = 0L;
691 for (int i = 0, isize = partial.size(); i < isize; i++) {
692 instant = partial.getFieldType(i).getField(GJChronology.this).set(instant, values[i]);
693 }
694 instant = add(instant, valueToAdd);
695 return GJChronology.this.get(partial, instant);
696 } else {
697 return super.add(partial, fieldIndex, values, valueToAdd);
698 }
699 }
700
701 public int getDifference(long minuendInstant, long subtrahendInstant) {
702 return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
703 }
704
705 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
706 return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
707 }
708
709 public long set(long instant, int value) {
710 if (instant >= iCutover) {
711 instant = iGregorianField.set(instant, value);
712 if (instant < iCutover) {
713
714 if (instant + iGapDuration < iCutover) {
715 instant = gregorianToJulian(instant);
716 }
717
718 if (get(instant) != value) {
719 throw new IllegalFieldValueException
720 (iGregorianField.getType(), Integer.valueOf(value), null, null);
721 }
722 }
723 } else {
724 instant = iJulianField.set(instant, value);
725 if (instant >= iCutover) {
726
727 if (instant - iGapDuration >= iCutover) {
728 instant = julianToGregorian(instant);
729 }
730
731 if (get(instant) != value) {
732 throw new IllegalFieldValueException
733 (iJulianField.getType(), Integer.valueOf(value), null, null);
734 }
735 }
736 }
737 return instant;
738 }
739
740 public long set(long instant, String text, Locale locale) {
741 if (instant >= iCutover) {
742 instant = iGregorianField.set(instant, text, locale);
743 if (instant < iCutover) {
744
745 if (instant + iGapDuration < iCutover) {
746 instant = gregorianToJulian(instant);
747 }
748
749 }
750 } else {
751 instant = iJulianField.set(instant, text, locale);
752 if (instant >= iCutover) {
753
754 if (instant - iGapDuration >= iCutover) {
755 instant = julianToGregorian(instant);
756 }
757
758 }
759 }
760 return instant;
761 }
762
763 public DurationField getDurationField() {
764 return iDurationField;
765 }
766
767 public DurationField getRangeDurationField() {
768 return iRangeDurationField;
769 }
770
771 public boolean isLeap(long instant) {
772 if (instant >= iCutover) {
773 return iGregorianField.isLeap(instant);
774 } else {
775 return iJulianField.isLeap(instant);
776 }
777 }
778
779 public int getLeapAmount(long instant) {
780 if (instant >= iCutover) {
781 return iGregorianField.getLeapAmount(instant);
782 } else {
783 return iJulianField.getLeapAmount(instant);
784 }
785 }
786
787 public DurationField getLeapDurationField() {
788 return iGregorianField.getLeapDurationField();
789 }
790
791
792 public int getMinimumValue() {
793
794
795 return iJulianField.getMinimumValue();
796 }
797
798 public int getMinimumValue(ReadablePartial partial) {
799 return iJulianField.getMinimumValue(partial);
800 }
801
802 public int getMinimumValue(ReadablePartial partial, int[] values) {
803 return iJulianField.getMinimumValue(partial, values);
804 }
805
806 public int getMinimumValue(long instant) {
807 if (instant < iCutover) {
808 return iJulianField.getMinimumValue(instant);
809 }
810
811 int min = iGregorianField.getMinimumValue(instant);
812
813
814
815 instant = iGregorianField.set(instant, min);
816 if (instant < iCutover) {
817 min = iGregorianField.get(iCutover);
818 }
819
820 return min;
821 }
822
823 public int getMaximumValue() {
824
825
826 return iGregorianField.getMaximumValue();
827 }
828
829 public int getMaximumValue(long instant) {
830 if (instant >= iCutover) {
831 return iGregorianField.getMaximumValue(instant);
832 }
833
834 int max = iJulianField.getMaximumValue(instant);
835
836
837
838 instant = iJulianField.set(instant, max);
839 if (instant >= iCutover) {
840 max = iJulianField.get(iJulianField.add(iCutover, -1));
841 }
842
843 return max;
844 }
845
846 public int getMaximumValue(ReadablePartial partial) {
847 long instant = GJChronology.getInstanceUTC().set(partial, 0L);
848 return getMaximumValue(instant);
849 }
850
851 public int getMaximumValue(ReadablePartial partial, int[] values) {
852 Chronology chrono = GJChronology.getInstanceUTC();
853 long instant = 0L;
854 for (int i = 0, isize = partial.size(); i < isize; i++) {
855 DateTimeField field = partial.getFieldType(i).getField(chrono);
856 if (values[i] <= field.getMaximumValue(instant)) {
857 instant = field.set(instant, values[i]);
858 }
859 }
860 return getMaximumValue(instant);
861 }
862
863 public long roundFloor(long instant) {
864 if (instant >= iCutover) {
865 instant = iGregorianField.roundFloor(instant);
866 if (instant < iCutover) {
867
868 if (instant + iGapDuration < iCutover) {
869 instant = gregorianToJulian(instant);
870 }
871 }
872 } else {
873 instant = iJulianField.roundFloor(instant);
874 }
875 return instant;
876 }
877
878 public long roundCeiling(long instant) {
879 if (instant >= iCutover) {
880 instant = iGregorianField.roundCeiling(instant);
881 } else {
882 instant = iJulianField.roundCeiling(instant);
883 if (instant >= iCutover) {
884
885 if (instant - iGapDuration >= iCutover) {
886 instant = julianToGregorian(instant);
887 }
888 }
889 }
890 return instant;
891 }
892
893 public int getMaximumTextLength(Locale locale) {
894 return Math.max(iJulianField.getMaximumTextLength(locale),
895 iGregorianField.getMaximumTextLength(locale));
896 }
897
898 public int getMaximumShortTextLength(Locale locale) {
899 return Math.max(iJulianField.getMaximumShortTextLength(locale),
900 iGregorianField.getMaximumShortTextLength(locale));
901 }
902
903 protected long julianToGregorian(long instant) {
904 if (iConvertByWeekyear) {
905 return julianToGregorianByWeekyear(instant);
906 } else {
907 return julianToGregorianByYear(instant);
908 }
909 }
910
911 protected long gregorianToJulian(long instant) {
912 if (iConvertByWeekyear) {
913 return gregorianToJulianByWeekyear(instant);
914 } else {
915 return gregorianToJulianByYear(instant);
916 }
917 }
918 }
919
920
921
922
923
924
925
926
927 private final class ImpreciseCutoverField extends CutoverField {
928 private static final long serialVersionUID = 3410248757173576441L;
929
930
931
932
933 ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField, long cutoverMillis) {
934 this(julianField, gregorianField, null, cutoverMillis, false);
935 }
936
937
938
939
940
941
942 ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField,
943 DurationField durationField, long cutoverMillis)
944 {
945 this(julianField, gregorianField, durationField, cutoverMillis, false);
946 }
947
948
949
950
951
952
953 ImpreciseCutoverField(DateTimeField julianField, DateTimeField gregorianField,
954 DurationField durationField,
955 long cutoverMillis, boolean convertByWeekyear)
956 {
957 super(julianField, gregorianField, cutoverMillis, convertByWeekyear);
958 if (durationField == null) {
959 durationField = new LinkedDurationField(iDurationField, this);
960 }
961 iDurationField = durationField;
962 }
963
964 public long add(long instant, int value) {
965 if (instant >= iCutover) {
966 instant = iGregorianField.add(instant, value);
967 if (instant < iCutover) {
968
969 if (instant + iGapDuration < iCutover) {
970 instant = gregorianToJulian(instant);
971 }
972 }
973 } else {
974 instant = iJulianField.add(instant, value);
975 if (instant >= iCutover) {
976
977 if (instant - iGapDuration >= iCutover) {
978 instant = julianToGregorian(instant);
979 }
980 }
981 }
982 return instant;
983 }
984
985 public long add(long instant, long value) {
986 if (instant >= iCutover) {
987 instant = iGregorianField.add(instant, value);
988 if (instant < iCutover) {
989
990 if (instant + iGapDuration < iCutover) {
991 instant = gregorianToJulian(instant);
992 }
993 }
994 } else {
995 instant = iJulianField.add(instant, value);
996 if (instant >= iCutover) {
997
998 if (instant - iGapDuration >= iCutover) {
999 instant = julianToGregorian(instant);
1000 }
1001 }
1002 }
1003 return instant;
1004 }
1005
1006 public int getDifference(long minuendInstant, long subtrahendInstant) {
1007 if (minuendInstant >= iCutover) {
1008 if (subtrahendInstant >= iCutover) {
1009 return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
1010 }
1011
1012
1013 minuendInstant = gregorianToJulian(minuendInstant);
1014 return iJulianField.getDifference(minuendInstant, subtrahendInstant);
1015 } else {
1016 if (subtrahendInstant < iCutover) {
1017 return iJulianField.getDifference(minuendInstant, subtrahendInstant);
1018 }
1019
1020
1021 minuendInstant = julianToGregorian(minuendInstant);
1022 return iGregorianField.getDifference(minuendInstant, subtrahendInstant);
1023 }
1024 }
1025
1026 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
1027 if (minuendInstant >= iCutover) {
1028 if (subtrahendInstant >= iCutover) {
1029 return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1030 }
1031
1032
1033 minuendInstant = gregorianToJulian(minuendInstant);
1034 return iJulianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1035 } else {
1036 if (subtrahendInstant < iCutover) {
1037 return iJulianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1038 }
1039
1040
1041 minuendInstant = julianToGregorian(minuendInstant);
1042 return iGregorianField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1043 }
1044 }
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056 public int getMinimumValue(long instant) {
1057 if (instant >= iCutover) {
1058 return iGregorianField.getMinimumValue(instant);
1059 } else {
1060 return iJulianField.getMinimumValue(instant);
1061 }
1062 }
1063
1064 public int getMaximumValue(long instant) {
1065 if (instant >= iCutover) {
1066 return iGregorianField.getMaximumValue(instant);
1067 } else {
1068 return iJulianField.getMaximumValue(instant);
1069 }
1070 }
1071 }
1072
1073
1074
1075
1076
1077 private static class LinkedDurationField extends DecoratedDurationField {
1078 private static final long serialVersionUID = 4097975388007713084L;
1079
1080 private final ImpreciseCutoverField iField;
1081
1082 LinkedDurationField(DurationField durationField, ImpreciseCutoverField dateTimeField) {
1083 super(durationField, durationField.getType());
1084 iField = dateTimeField;
1085 }
1086
1087 public long add(long instant, int value) {
1088 return iField.add(instant, value);
1089 }
1090
1091 public long add(long instant, long value) {
1092 return iField.add(instant, value);
1093 }
1094
1095 public int getDifference(long minuendInstant, long subtrahendInstant) {
1096 return iField.getDifference(minuendInstant, subtrahendInstant);
1097 }
1098
1099 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
1100 return iField.getDifferenceAsLong(minuendInstant, subtrahendInstant);
1101 }
1102 }
1103
1104 }