1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.joda.time;
17
18 import java.io.Serializable;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.joda.time.field.FieldUtils;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public class PeriodType implements Serializable {
52
53 private static final long serialVersionUID = 2274324892792009998L;
54
55
56 private static final Map<PeriodType, Object> cTypes = new HashMap<PeriodType, Object>(32);
57
58 static int YEAR_INDEX = 0;
59 static int MONTH_INDEX = 1;
60 static int WEEK_INDEX = 2;
61 static int DAY_INDEX = 3;
62 static int HOUR_INDEX = 4;
63 static int MINUTE_INDEX = 5;
64 static int SECOND_INDEX = 6;
65 static int MILLI_INDEX = 7;
66
67 private static PeriodType cStandard;
68 private static PeriodType cYMDTime;
69 private static PeriodType cYMD;
70 private static PeriodType cYWDTime;
71 private static PeriodType cYWD;
72 private static PeriodType cYDTime;
73 private static PeriodType cYD;
74 private static PeriodType cDTime;
75 private static PeriodType cTime;
76
77 private static PeriodType cYears;
78 private static PeriodType cMonths;
79 private static PeriodType cWeeks;
80 private static PeriodType cDays;
81 private static PeriodType cHours;
82 private static PeriodType cMinutes;
83 private static PeriodType cSeconds;
84 private static PeriodType cMillis;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 public static PeriodType standard() {
102 PeriodType type = cStandard;
103 if (type == null) {
104 type = new PeriodType(
105 "Standard",
106 new DurationFieldType[] {
107 DurationFieldType.years(), DurationFieldType.months(),
108 DurationFieldType.weeks(), DurationFieldType.days(),
109 DurationFieldType.hours(), DurationFieldType.minutes(),
110 DurationFieldType.seconds(), DurationFieldType.millis(),
111 },
112 new int[] { 0, 1, 2, 3, 4, 5, 6, 7, }
113 );
114 cStandard = type;
115 }
116 return type;
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 public static PeriodType yearMonthDayTime() {
134 PeriodType type = cYMDTime;
135 if (type == null) {
136 type = new PeriodType(
137 "YearMonthDayTime",
138 new DurationFieldType[] {
139 DurationFieldType.years(), DurationFieldType.months(),
140 DurationFieldType.days(),
141 DurationFieldType.hours(), DurationFieldType.minutes(),
142 DurationFieldType.seconds(), DurationFieldType.millis(),
143 },
144 new int[] { 0, 1, -1, 2, 3, 4, 5, 6, }
145 );
146 cYMDTime = type;
147 }
148 return type;
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162 public static PeriodType yearMonthDay() {
163 PeriodType type = cYMD;
164 if (type == null) {
165 type = new PeriodType(
166 "YearMonthDay",
167 new DurationFieldType[] {
168 DurationFieldType.years(), DurationFieldType.months(),
169 DurationFieldType.days(),
170 },
171 new int[] { 0, 1, -1, 2, -1, -1, -1, -1, }
172 );
173 cYMD = type;
174 }
175 return type;
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 public static PeriodType yearWeekDayTime() {
193 PeriodType type = cYWDTime;
194 if (type == null) {
195 type = new PeriodType(
196 "YearWeekDayTime",
197 new DurationFieldType[] {
198 DurationFieldType.years(),
199 DurationFieldType.weeks(), DurationFieldType.days(),
200 DurationFieldType.hours(), DurationFieldType.minutes(),
201 DurationFieldType.seconds(), DurationFieldType.millis(),
202 },
203 new int[] { 0, -1, 1, 2, 3, 4, 5, 6, }
204 );
205 cYWDTime = type;
206 }
207 return type;
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221 public static PeriodType yearWeekDay() {
222 PeriodType type = cYWD;
223 if (type == null) {
224 type = new PeriodType(
225 "YearWeekDay",
226 new DurationFieldType[] {
227 DurationFieldType.years(),
228 DurationFieldType.weeks(), DurationFieldType.days(),
229 },
230 new int[] { 0, -1, 1, 2, -1, -1, -1, -1, }
231 );
232 cYWD = type;
233 }
234 return type;
235 }
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 public static PeriodType yearDayTime() {
251 PeriodType type = cYDTime;
252 if (type == null) {
253 type = new PeriodType(
254 "YearDayTime",
255 new DurationFieldType[] {
256 DurationFieldType.years(), DurationFieldType.days(),
257 DurationFieldType.hours(), DurationFieldType.minutes(),
258 DurationFieldType.seconds(), DurationFieldType.millis(),
259 },
260 new int[] { 0, -1, -1, 1, 2, 3, 4, 5, }
261 );
262 cYDTime = type;
263 }
264 return type;
265 }
266
267
268
269
270
271
272
273
274
275
276
277 public static PeriodType yearDay() {
278 PeriodType type = cYD;
279 if (type == null) {
280 type = new PeriodType(
281 "YearDay",
282 new DurationFieldType[] {
283 DurationFieldType.years(), DurationFieldType.days(),
284 },
285 new int[] { 0, -1, -1, 1, -1, -1, -1, -1, }
286 );
287 cYD = type;
288 }
289 return type;
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304 public static PeriodType dayTime() {
305 PeriodType type = cDTime;
306 if (type == null) {
307 type = new PeriodType(
308 "DayTime",
309 new DurationFieldType[] {
310 DurationFieldType.days(),
311 DurationFieldType.hours(), DurationFieldType.minutes(),
312 DurationFieldType.seconds(), DurationFieldType.millis(),
313 },
314 new int[] { -1, -1, -1, 0, 1, 2, 3, 4, }
315 );
316 cDTime = type;
317 }
318 return type;
319 }
320
321
322
323
324
325
326
327
328
329
330
331
332 public static PeriodType time() {
333 PeriodType type = cTime;
334 if (type == null) {
335 type = new PeriodType(
336 "Time",
337 new DurationFieldType[] {
338 DurationFieldType.hours(), DurationFieldType.minutes(),
339 DurationFieldType.seconds(), DurationFieldType.millis(),
340 },
341 new int[] { -1, -1, -1, -1, 0, 1, 2, 3, }
342 );
343 cTime = type;
344 }
345 return type;
346 }
347
348
349
350
351
352
353 public static PeriodType years() {
354 PeriodType type = cYears;
355 if (type == null) {
356 type = new PeriodType(
357 "Years",
358 new DurationFieldType[] { DurationFieldType.years() },
359 new int[] { 0, -1, -1, -1, -1, -1, -1, -1, }
360 );
361 cYears = type;
362 }
363 return type;
364 }
365
366
367
368
369
370
371 public static PeriodType months() {
372 PeriodType type = cMonths;
373 if (type == null) {
374 type = new PeriodType(
375 "Months",
376 new DurationFieldType[] { DurationFieldType.months() },
377 new int[] { -1, 0, -1, -1, -1, -1, -1, -1, }
378 );
379 cMonths = type;
380 }
381 return type;
382 }
383
384
385
386
387
388
389 public static PeriodType weeks() {
390 PeriodType type = cWeeks;
391 if (type == null) {
392 type = new PeriodType(
393 "Weeks",
394 new DurationFieldType[] { DurationFieldType.weeks() },
395 new int[] { -1, -1, 0, -1, -1, -1, -1, -1, }
396 );
397 cWeeks = type;
398 }
399 return type;
400 }
401
402
403
404
405
406
407 public static PeriodType days() {
408 PeriodType type = cDays;
409 if (type == null) {
410 type = new PeriodType(
411 "Days",
412 new DurationFieldType[] { DurationFieldType.days() },
413 new int[] { -1, -1, -1, 0, -1, -1, -1, -1, }
414 );
415 cDays = type;
416 }
417 return type;
418 }
419
420
421
422
423
424
425 public static PeriodType hours() {
426 PeriodType type = cHours;
427 if (type == null) {
428 type = new PeriodType(
429 "Hours",
430 new DurationFieldType[] { DurationFieldType.hours() },
431 new int[] { -1, -1, -1, -1, 0, -1, -1, -1, }
432 );
433 cHours = type;
434 }
435 return type;
436 }
437
438
439
440
441
442
443 public static PeriodType minutes() {
444 PeriodType type = cMinutes;
445 if (type == null) {
446 type = new PeriodType(
447 "Minutes",
448 new DurationFieldType[] { DurationFieldType.minutes() },
449 new int[] { -1, -1, -1, -1, -1, 0, -1, -1, }
450 );
451 cMinutes = type;
452 }
453 return type;
454 }
455
456
457
458
459
460
461 public static PeriodType seconds() {
462 PeriodType type = cSeconds;
463 if (type == null) {
464 type = new PeriodType(
465 "Seconds",
466 new DurationFieldType[] { DurationFieldType.seconds() },
467 new int[] { -1, -1, -1, -1, -1, -1, 0, -1, }
468 );
469 cSeconds = type;
470 }
471 return type;
472 }
473
474
475
476
477
478
479 public static PeriodType millis() {
480 PeriodType type = cMillis;
481 if (type == null) {
482 type = new PeriodType(
483 "Millis",
484 new DurationFieldType[] { DurationFieldType.millis() },
485 new int[] { -1, -1, -1, -1, -1, -1, -1, 0, }
486 );
487 cMillis = type;
488 }
489 return type;
490 }
491
492
493
494
495
496
497
498
499
500
501 public static synchronized PeriodType forFields(DurationFieldType[] types) {
502 if (types == null || types.length == 0) {
503 throw new IllegalArgumentException("Types array must not be null or empty");
504 }
505 for (int i = 0; i < types.length; i++) {
506 if (types[i] == null) {
507 throw new IllegalArgumentException("Types array must not contain null");
508 }
509 }
510 Map<PeriodType, Object> cache = cTypes;
511 if (cache.isEmpty()) {
512 cache.put(standard(), standard());
513 cache.put(yearMonthDayTime(), yearMonthDayTime());
514 cache.put(yearMonthDay(), yearMonthDay());
515 cache.put(yearWeekDayTime(), yearWeekDayTime());
516 cache.put(yearWeekDay(), yearWeekDay());
517 cache.put(yearDayTime(), yearDayTime());
518 cache.put(yearDay(), yearDay());
519 cache.put(dayTime(), dayTime());
520 cache.put(time(), time());
521 cache.put(years(), years());
522 cache.put(months(), months());
523 cache.put(weeks(), weeks());
524 cache.put(days(), days());
525 cache.put(hours(), hours());
526 cache.put(minutes(), minutes());
527 cache.put(seconds(), seconds());
528 cache.put(millis(), millis());
529 }
530 PeriodType inPartType = new PeriodType(null, types, null);
531 Object cached = cache.get(inPartType);
532 if (cached instanceof PeriodType) {
533 return (PeriodType) cached;
534 }
535 if (cached != null) {
536 throw new IllegalArgumentException("PeriodType does not support fields: " + cached);
537 }
538 PeriodType type = standard();
539 List<DurationFieldType> list = new ArrayList<DurationFieldType>(Arrays.asList(types));
540 if (list.remove(DurationFieldType.years()) == false) {
541 type = type.withYearsRemoved();
542 }
543 if (list.remove(DurationFieldType.months()) == false) {
544 type = type.withMonthsRemoved();
545 }
546 if (list.remove(DurationFieldType.weeks()) == false) {
547 type = type.withWeeksRemoved();
548 }
549 if (list.remove(DurationFieldType.days()) == false) {
550 type = type.withDaysRemoved();
551 }
552 if (list.remove(DurationFieldType.hours()) == false) {
553 type = type.withHoursRemoved();
554 }
555 if (list.remove(DurationFieldType.minutes()) == false) {
556 type = type.withMinutesRemoved();
557 }
558 if (list.remove(DurationFieldType.seconds()) == false) {
559 type = type.withSecondsRemoved();
560 }
561 if (list.remove(DurationFieldType.millis()) == false) {
562 type = type.withMillisRemoved();
563 }
564 if (list.size() > 0) {
565 cache.put(inPartType, list);
566 throw new IllegalArgumentException("PeriodType does not support fields: " + list);
567 }
568
569 PeriodType checkPartType = new PeriodType(null, type.iTypes, null);
570 PeriodType checkedType = (PeriodType) cache.get(checkPartType);
571 if (checkedType != null) {
572 cache.put(checkPartType, checkedType);
573 return checkedType;
574 }
575 cache.put(checkPartType, type);
576 return type;
577 }
578
579
580
581 private final String iName;
582
583 private final DurationFieldType[] iTypes;
584
585 private final int[] iIndices;
586
587
588
589
590
591
592
593
594 protected PeriodType(String name, DurationFieldType[] types, int[] indices) {
595 super();
596 iName = name;
597 iTypes = types;
598 iIndices = indices;
599 }
600
601
602
603
604
605
606
607 public String getName() {
608 return iName;
609 }
610
611
612
613
614
615
616 public int size() {
617 return iTypes.length;
618 }
619
620
621
622
623
624
625
626
627 public DurationFieldType getFieldType(int index) {
628 return iTypes[index];
629 }
630
631
632
633
634
635
636
637 public boolean isSupported(DurationFieldType type) {
638 return (indexOf(type) >= 0);
639 }
640
641
642
643
644
645
646
647 public int indexOf(DurationFieldType type) {
648 for (int i = 0, isize = size(); i < isize; i++) {
649 if (iTypes[i] == type) {
650 return i;
651 }
652 }
653 return -1;
654 }
655
656
657
658
659
660
661 public String toString() {
662 return "PeriodType[" + getName() + "]";
663 }
664
665
666
667
668
669
670
671
672
673 int getIndexedField(ReadablePeriod period, int index) {
674 int realIndex = iIndices[index];
675 return (realIndex == -1 ? 0 : period.getValue(realIndex));
676 }
677
678
679
680
681
682
683
684
685
686
687 boolean setIndexedField(ReadablePeriod period, int index, int[] values, int newValue) {
688 int realIndex = iIndices[index];
689 if (realIndex == -1) {
690 throw new UnsupportedOperationException("Field is not supported");
691 }
692 values[realIndex] = newValue;
693 return true;
694 }
695
696
697
698
699
700
701
702
703
704
705
706 boolean addIndexedField(ReadablePeriod period, int index, int[] values, int valueToAdd) {
707 if (valueToAdd == 0) {
708 return false;
709 }
710 int realIndex = iIndices[index];
711 if (realIndex == -1) {
712 throw new UnsupportedOperationException("Field is not supported");
713 }
714 values[realIndex] = FieldUtils.safeAdd(values[realIndex], valueToAdd);
715 return true;
716 }
717
718
719
720
721
722
723
724 public PeriodType withYearsRemoved() {
725 return withFieldRemoved(0, "NoYears");
726 }
727
728
729
730
731
732
733 public PeriodType withMonthsRemoved() {
734 return withFieldRemoved(1, "NoMonths");
735 }
736
737
738
739
740
741
742 public PeriodType withWeeksRemoved() {
743 return withFieldRemoved(2, "NoWeeks");
744 }
745
746
747
748
749
750
751 public PeriodType withDaysRemoved() {
752 return withFieldRemoved(3, "NoDays");
753 }
754
755
756
757
758
759
760 public PeriodType withHoursRemoved() {
761 return withFieldRemoved(4, "NoHours");
762 }
763
764
765
766
767
768
769 public PeriodType withMinutesRemoved() {
770 return withFieldRemoved(5, "NoMinutes");
771 }
772
773
774
775
776
777
778 public PeriodType withSecondsRemoved() {
779 return withFieldRemoved(6, "NoSeconds");
780 }
781
782
783
784
785
786
787 public PeriodType withMillisRemoved() {
788 return withFieldRemoved(7, "NoMillis");
789 }
790
791
792
793
794
795
796
797
798 private PeriodType withFieldRemoved(int indicesIndex, String name) {
799 int fieldIndex = iIndices[indicesIndex];
800 if (fieldIndex == -1) {
801 return this;
802 }
803
804 DurationFieldType[] types = new DurationFieldType[size() - 1];
805 for (int i = 0; i < iTypes.length; i++) {
806 if (i < fieldIndex) {
807 types[i] = iTypes[i];
808 } else if (i > fieldIndex) {
809 types[i - 1] = iTypes[i];
810 }
811 }
812
813 int[] indices = new int[8];
814 for (int i = 0; i < indices.length; i++) {
815 if (i < indicesIndex) {
816 indices[i] = iIndices[i];
817 } else if (i > indicesIndex) {
818 indices[i] = (iIndices[i] == -1 ? -1 : iIndices[i] - 1);
819 } else {
820 indices[i] = -1;
821 }
822 }
823 return new PeriodType(getName() + name, types, indices);
824 }
825
826
827
828
829
830
831
832
833
834 public boolean equals(Object obj) {
835 if (this == obj) {
836 return true;
837 }
838 if (obj instanceof PeriodType == false) {
839 return false;
840 }
841 PeriodType other = (PeriodType) obj;
842 return (Arrays.equals(iTypes, other.iTypes));
843 }
844
845
846
847
848
849
850 public int hashCode() {
851 int hash = 0;
852 for (int i = 0; i < iTypes.length; i++) {
853 hash += iTypes[i].hashCode();
854 }
855 return hash;
856 }
857
858 }