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.HashMap;
19 import java.util.Locale;
20
21 import org.joda.time.Chronology;
22 import org.joda.time.DateTime;
23 import org.joda.time.DateTimeField;
24 import org.joda.time.DateTimeZone;
25 import org.joda.time.DurationField;
26 import org.joda.time.MutableDateTime;
27 import org.joda.time.ReadableDateTime;
28 import org.joda.time.field.DecoratedDateTimeField;
29 import org.joda.time.field.DecoratedDurationField;
30 import org.joda.time.field.FieldUtils;
31 import org.joda.time.format.DateTimeFormatter;
32 import org.joda.time.format.ISODateTimeFormat;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public final class LimitChronology extends AssembledChronology {
50
51
52 private static final long serialVersionUID = 7670866536893052522L;
53
54
55
56
57
58
59
60
61
62
63
64 public static LimitChronology getInstance(Chronology base,
65 ReadableDateTime lowerLimit,
66 ReadableDateTime upperLimit) {
67 if (base == null) {
68 throw new IllegalArgumentException("Must supply a chronology");
69 }
70
71 lowerLimit = lowerLimit == null ? null : lowerLimit.toDateTime();
72 upperLimit = upperLimit == null ? null : upperLimit.toDateTime();
73
74 if (lowerLimit != null && upperLimit != null) {
75 if (!lowerLimit.isBefore(upperLimit)) {
76 throw new IllegalArgumentException
77 ("The lower limit must be come before than the upper limit");
78 }
79 }
80
81 return new LimitChronology(base, (DateTime)lowerLimit, (DateTime)upperLimit);
82 }
83
84 final DateTime iLowerLimit;
85 final DateTime iUpperLimit;
86
87 private transient LimitChronology iWithUTC;
88
89
90
91
92
93
94
95
96
97 private LimitChronology(Chronology base,
98 DateTime lowerLimit, DateTime upperLimit) {
99 super(base, null);
100
101 iLowerLimit = lowerLimit;
102 iUpperLimit = upperLimit;
103 }
104
105
106
107
108
109
110 public DateTime getLowerLimit() {
111 return iLowerLimit;
112 }
113
114
115
116
117
118
119 public DateTime getUpperLimit() {
120 return iUpperLimit;
121 }
122
123
124
125
126
127
128 public Chronology withUTC() {
129 return withZone(DateTimeZone.UTC);
130 }
131
132
133
134
135
136
137 public Chronology withZone(DateTimeZone zone) {
138 if (zone == null) {
139 zone = DateTimeZone.getDefault();
140 }
141 if (zone == getZone()) {
142 return this;
143 }
144
145 if (zone == DateTimeZone.UTC && iWithUTC != null) {
146 return iWithUTC;
147 }
148
149 DateTime lowerLimit = iLowerLimit;
150 if (lowerLimit != null) {
151 MutableDateTime mdt = lowerLimit.toMutableDateTime();
152 mdt.setZoneRetainFields(zone);
153 lowerLimit = mdt.toDateTime();
154 }
155
156 DateTime upperLimit = iUpperLimit;
157 if (upperLimit != null) {
158 MutableDateTime mdt = upperLimit.toMutableDateTime();
159 mdt.setZoneRetainFields(zone);
160 upperLimit = mdt.toDateTime();
161 }
162
163 LimitChronology chrono = getInstance
164 (getBase().withZone(zone), lowerLimit, upperLimit);
165
166 if (zone == DateTimeZone.UTC) {
167 iWithUTC = chrono;
168 }
169
170 return chrono;
171 }
172
173 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
174 int millisOfDay)
175 throws IllegalArgumentException
176 {
177 long instant = getBase().getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
178 checkLimits(instant, "resulting");
179 return instant;
180 }
181
182 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
183 int hourOfDay, int minuteOfHour,
184 int secondOfMinute, int millisOfSecond)
185 throws IllegalArgumentException
186 {
187 long instant = getBase().getDateTimeMillis
188 (year, monthOfYear, dayOfMonth,
189 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
190 checkLimits(instant, "resulting");
191 return instant;
192 }
193
194 public long getDateTimeMillis(long instant,
195 int hourOfDay, int minuteOfHour,
196 int secondOfMinute, int millisOfSecond)
197 throws IllegalArgumentException
198 {
199 checkLimits(instant, null);
200 instant = getBase().getDateTimeMillis
201 (instant, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
202 checkLimits(instant, "resulting");
203 return instant;
204 }
205
206 protected void assemble(Fields fields) {
207
208
209 HashMap<Object, Object> converted = new HashMap<Object, Object>();
210
211
212
213 fields.eras = convertField(fields.eras, converted);
214 fields.centuries = convertField(fields.centuries, converted);
215 fields.years = convertField(fields.years, converted);
216 fields.months = convertField(fields.months, converted);
217 fields.weekyears = convertField(fields.weekyears, converted);
218 fields.weeks = convertField(fields.weeks, converted);
219 fields.days = convertField(fields.days, converted);
220
221 fields.halfdays = convertField(fields.halfdays, converted);
222 fields.hours = convertField(fields.hours, converted);
223 fields.minutes = convertField(fields.minutes, converted);
224 fields.seconds = convertField(fields.seconds, converted);
225 fields.millis = convertField(fields.millis, converted);
226
227
228
229 fields.year = convertField(fields.year, converted);
230 fields.yearOfEra = convertField(fields.yearOfEra, converted);
231 fields.yearOfCentury = convertField(fields.yearOfCentury, converted);
232 fields.centuryOfEra = convertField(fields.centuryOfEra, converted);
233 fields.era = convertField(fields.era, converted);
234 fields.dayOfWeek = convertField(fields.dayOfWeek, converted);
235 fields.dayOfMonth = convertField(fields.dayOfMonth, converted);
236 fields.dayOfYear = convertField(fields.dayOfYear, converted);
237 fields.monthOfYear = convertField(fields.monthOfYear, converted);
238 fields.weekOfWeekyear = convertField(fields.weekOfWeekyear, converted);
239 fields.weekyear = convertField(fields.weekyear, converted);
240 fields.weekyearOfCentury = convertField(fields.weekyearOfCentury, converted);
241
242 fields.millisOfSecond = convertField(fields.millisOfSecond, converted);
243 fields.millisOfDay = convertField(fields.millisOfDay, converted);
244 fields.secondOfMinute = convertField(fields.secondOfMinute, converted);
245 fields.secondOfDay = convertField(fields.secondOfDay, converted);
246 fields.minuteOfHour = convertField(fields.minuteOfHour, converted);
247 fields.minuteOfDay = convertField(fields.minuteOfDay, converted);
248 fields.hourOfDay = convertField(fields.hourOfDay, converted);
249 fields.hourOfHalfday = convertField(fields.hourOfHalfday, converted);
250 fields.clockhourOfDay = convertField(fields.clockhourOfDay, converted);
251 fields.clockhourOfHalfday = convertField(fields.clockhourOfHalfday, converted);
252 fields.halfdayOfDay = convertField(fields.halfdayOfDay, converted);
253 }
254
255 private DurationField convertField(DurationField field, HashMap<Object, Object> converted) {
256 if (field == null || !field.isSupported()) {
257 return field;
258 }
259 if (converted.containsKey(field)) {
260 return (DurationField)converted.get(field);
261 }
262 LimitDurationField limitField = new LimitDurationField(field);
263 converted.put(field, limitField);
264 return limitField;
265 }
266
267 private DateTimeField convertField(DateTimeField field, HashMap<Object, Object> converted) {
268 if (field == null || !field.isSupported()) {
269 return field;
270 }
271 if (converted.containsKey(field)) {
272 return (DateTimeField)converted.get(field);
273 }
274 LimitDateTimeField limitField =
275 new LimitDateTimeField(field,
276 convertField(field.getDurationField(), converted),
277 convertField(field.getRangeDurationField(), converted),
278 convertField(field.getLeapDurationField(), converted));
279 converted.put(field, limitField);
280 return limitField;
281 }
282
283 void checkLimits(long instant, String desc) {
284 DateTime limit;
285 if ((limit = iLowerLimit) != null && instant < limit.getMillis()) {
286 throw new LimitException(desc, true);
287 }
288 if ((limit = iUpperLimit) != null && instant >= limit.getMillis()) {
289 throw new LimitException(desc, false);
290 }
291 }
292
293
294
295
296
297
298
299
300
301
302 public boolean equals(Object obj) {
303 if (this == obj) {
304 return true;
305 }
306 if (obj instanceof LimitChronology == false) {
307 return false;
308 }
309 LimitChronology chrono = (LimitChronology) obj;
310 return
311 getBase().equals(chrono.getBase()) &&
312 FieldUtils.equals(getLowerLimit(), chrono.getLowerLimit()) &&
313 FieldUtils.equals(getUpperLimit(), chrono.getUpperLimit());
314 }
315
316
317
318
319
320
321
322 public int hashCode() {
323 int hash = 317351877;
324 hash += (getLowerLimit() != null ? getLowerLimit().hashCode() : 0);
325 hash += (getUpperLimit() != null ? getUpperLimit().hashCode() : 0);
326 hash += getBase().hashCode() * 7;
327 return hash;
328 }
329
330
331
332
333
334
335 public String toString() {
336 return "LimitChronology[" + getBase().toString() + ", " +
337 (getLowerLimit() == null ? "NoLimit" : getLowerLimit().toString()) + ", " +
338 (getUpperLimit() == null ? "NoLimit" : getUpperLimit().toString()) + ']';
339 }
340
341
342
343
344
345
346 private class LimitException extends IllegalArgumentException {
347 private static final long serialVersionUID = -5924689995607498581L;
348
349 private final boolean iIsLow;
350
351 LimitException(String desc, boolean isLow) {
352 super(desc);
353 iIsLow = isLow;
354 }
355
356 public String getMessage() {
357 StringBuffer buf = new StringBuffer(85);
358 buf.append("The");
359 String desc = super.getMessage();
360 if (desc != null) {
361 buf.append(' ');
362 buf.append(desc);
363 }
364 buf.append(" instant is ");
365
366 DateTimeFormatter p = ISODateTimeFormat.dateTime();
367 p = p.withChronology(getBase());
368 if (iIsLow) {
369 buf.append("below the supported minimum of ");
370 p.printTo(buf, getLowerLimit().getMillis());
371 } else {
372 buf.append("above the supported maximum of ");
373 p.printTo(buf, getUpperLimit().getMillis());
374 }
375
376 buf.append(" (");
377 buf.append(getBase());
378 buf.append(')');
379
380 return buf.toString();
381 }
382
383 public String toString() {
384 return "IllegalArgumentException: " + getMessage();
385 }
386 }
387
388 private class LimitDurationField extends DecoratedDurationField {
389 private static final long serialVersionUID = 8049297699408782284L;
390
391 LimitDurationField(DurationField field) {
392 super(field, field.getType());
393 }
394
395 public int getValue(long duration, long instant) {
396 checkLimits(instant, null);
397 return getWrappedField().getValue(duration, instant);
398 }
399
400 public long getValueAsLong(long duration, long instant) {
401 checkLimits(instant, null);
402 return getWrappedField().getValueAsLong(duration, instant);
403 }
404
405 public long getMillis(int value, long instant) {
406 checkLimits(instant, null);
407 return getWrappedField().getMillis(value, instant);
408 }
409
410 public long getMillis(long value, long instant) {
411 checkLimits(instant, null);
412 return getWrappedField().getMillis(value, instant);
413 }
414
415 public long add(long instant, int amount) {
416 checkLimits(instant, null);
417 long result = getWrappedField().add(instant, amount);
418 checkLimits(result, "resulting");
419 return result;
420 }
421
422 public long add(long instant, long amount) {
423 checkLimits(instant, null);
424 long result = getWrappedField().add(instant, amount);
425 checkLimits(result, "resulting");
426 return result;
427 }
428
429 public int getDifference(long minuendInstant, long subtrahendInstant) {
430 checkLimits(minuendInstant, "minuend");
431 checkLimits(subtrahendInstant, "subtrahend");
432 return getWrappedField().getDifference(minuendInstant, subtrahendInstant);
433 }
434
435 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
436 checkLimits(minuendInstant, "minuend");
437 checkLimits(subtrahendInstant, "subtrahend");
438 return getWrappedField().getDifferenceAsLong(minuendInstant, subtrahendInstant);
439 }
440
441 }
442
443 private class LimitDateTimeField extends DecoratedDateTimeField {
444 private static final long serialVersionUID = -2435306746995699312L;
445
446 private final DurationField iDurationField;
447 private final DurationField iRangeDurationField;
448 private final DurationField iLeapDurationField;
449
450 LimitDateTimeField(DateTimeField field,
451 DurationField durationField,
452 DurationField rangeDurationField,
453 DurationField leapDurationField) {
454 super(field, field.getType());
455 iDurationField = durationField;
456 iRangeDurationField = rangeDurationField;
457 iLeapDurationField = leapDurationField;
458 }
459
460 public int get(long instant) {
461 checkLimits(instant, null);
462 return getWrappedField().get(instant);
463 }
464
465 public String getAsText(long instant, Locale locale) {
466 checkLimits(instant, null);
467 return getWrappedField().getAsText(instant, locale);
468 }
469
470 public String getAsShortText(long instant, Locale locale) {
471 checkLimits(instant, null);
472 return getWrappedField().getAsShortText(instant, locale);
473 }
474
475 public long add(long instant, int amount) {
476 checkLimits(instant, null);
477 long result = getWrappedField().add(instant, amount);
478 checkLimits(result, "resulting");
479 return result;
480 }
481
482 public long add(long instant, long amount) {
483 checkLimits(instant, null);
484 long result = getWrappedField().add(instant, amount);
485 checkLimits(result, "resulting");
486 return result;
487 }
488
489 public long addWrapField(long instant, int amount) {
490 checkLimits(instant, null);
491 long result = getWrappedField().addWrapField(instant, amount);
492 checkLimits(result, "resulting");
493 return result;
494 }
495
496 public int getDifference(long minuendInstant, long subtrahendInstant) {
497 checkLimits(minuendInstant, "minuend");
498 checkLimits(subtrahendInstant, "subtrahend");
499 return getWrappedField().getDifference(minuendInstant, subtrahendInstant);
500 }
501
502 public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
503 checkLimits(minuendInstant, "minuend");
504 checkLimits(subtrahendInstant, "subtrahend");
505 return getWrappedField().getDifferenceAsLong(minuendInstant, subtrahendInstant);
506 }
507
508 public long set(long instant, int value) {
509 checkLimits(instant, null);
510 long result = getWrappedField().set(instant, value);
511 checkLimits(result, "resulting");
512 return result;
513 }
514
515 public long set(long instant, String text, Locale locale) {
516 checkLimits(instant, null);
517 long result = getWrappedField().set(instant, text, locale);
518 checkLimits(result, "resulting");
519 return result;
520 }
521
522 public final DurationField getDurationField() {
523 return iDurationField;
524 }
525
526 public final DurationField getRangeDurationField() {
527 return iRangeDurationField;
528 }
529
530 public boolean isLeap(long instant) {
531 checkLimits(instant, null);
532 return getWrappedField().isLeap(instant);
533 }
534
535 public int getLeapAmount(long instant) {
536 checkLimits(instant, null);
537 return getWrappedField().getLeapAmount(instant);
538 }
539
540 public final DurationField getLeapDurationField() {
541 return iLeapDurationField;
542 }
543
544 public long roundFloor(long instant) {
545 checkLimits(instant, null);
546 long result = getWrappedField().roundFloor(instant);
547 checkLimits(result, "resulting");
548 return result;
549 }
550
551 public long roundCeiling(long instant) {
552 checkLimits(instant, null);
553 long result = getWrappedField().roundCeiling(instant);
554 checkLimits(result, "resulting");
555 return result;
556 }
557
558 public long roundHalfFloor(long instant) {
559 checkLimits(instant, null);
560 long result = getWrappedField().roundHalfFloor(instant);
561 checkLimits(result, "resulting");
562 return result;
563 }
564
565 public long roundHalfCeiling(long instant) {
566 checkLimits(instant, null);
567 long result = getWrappedField().roundHalfCeiling(instant);
568 checkLimits(result, "resulting");
569 return result;
570 }
571
572 public long roundHalfEven(long instant) {
573 checkLimits(instant, null);
574 long result = getWrappedField().roundHalfEven(instant);
575 checkLimits(result, "resulting");
576 return result;
577 }
578
579 public long remainder(long instant) {
580 checkLimits(instant, null);
581 long result = getWrappedField().remainder(instant);
582 checkLimits(result, "resulting");
583 return result;
584 }
585
586 public int getMinimumValue(long instant) {
587 checkLimits(instant, null);
588 return getWrappedField().getMinimumValue(instant);
589 }
590
591 public int getMaximumValue(long instant) {
592 checkLimits(instant, null);
593 return getWrappedField().getMaximumValue(instant);
594 }
595
596 public int getMaximumTextLength(Locale locale) {
597 return getWrappedField().getMaximumTextLength(locale);
598 }
599
600 public int getMaximumShortTextLength(Locale locale) {
601 return getWrappedField().getMaximumShortTextLength(locale);
602 }
603
604 }
605
606 }