001 /*
002 * Copyright 2001-2005 Stephen Colebourne
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.joda.time.chrono;
017
018 import java.io.Serializable;
019
020 import org.joda.time.Chronology;
021 import org.joda.time.DateTimeField;
022 import org.joda.time.DateTimeFieldType;
023 import org.joda.time.DateTimeZone;
024 import org.joda.time.DurationField;
025 import org.joda.time.DurationFieldType;
026 import org.joda.time.IllegalFieldValueException;
027 import org.joda.time.ReadablePartial;
028 import org.joda.time.ReadablePeriod;
029 import org.joda.time.field.FieldUtils;
030 import org.joda.time.field.UnsupportedDateTimeField;
031 import org.joda.time.field.UnsupportedDurationField;
032
033 /**
034 * BaseChronology provides a skeleton implementation for chronology
035 * classes. Many utility methods are defined, but all fields are unsupported.
036 * <p>
037 * BaseChronology is thread-safe and immutable, and all subclasses must be
038 * as well.
039 *
040 * @author Brian S O'Neill
041 * @since 1.0
042 */
043 public abstract class BaseChronology
044 extends Chronology
045 implements Serializable {
046
047 /** Serialization version. */
048 private static final long serialVersionUID = -7310865996721419676L;
049
050 /**
051 * Restricted constructor.
052 */
053 protected BaseChronology() {
054 super();
055 }
056
057 /**
058 * Returns the DateTimeZone that this Chronology operates in, or null if
059 * unspecified.
060 *
061 * @return DateTimeZone null if unspecified
062 */
063 public abstract DateTimeZone getZone();
064
065 /**
066 * Returns an instance of this Chronology that operates in the UTC time
067 * zone. Chronologies that do not operate in a time zone or are already
068 * UTC must return themself.
069 *
070 * @return a version of this chronology that ignores time zones
071 */
072 public abstract Chronology withUTC();
073
074 /**
075 * Returns an instance of this Chronology that operates in any time zone.
076 *
077 * @return a version of this chronology with a specific time zone
078 * @param zone to use, or default if null
079 * @see org.joda.time.chrono.ZonedChronology
080 */
081 public abstract Chronology withZone(DateTimeZone zone);
082
083 /**
084 * Returns a datetime millisecond instant, formed from the given year,
085 * month, day, and millisecond values. The set of given values must refer
086 * to a valid datetime, or else an IllegalArgumentException is thrown.
087 * <p>
088 * The default implementation calls upon separate DateTimeFields to
089 * determine the result. Subclasses are encouraged to provide a more
090 * efficient implementation.
091 *
092 * @param year year to use
093 * @param monthOfYear month to use
094 * @param dayOfMonth day of month to use
095 * @param millisOfDay millisecond to use
096 * @return millisecond instant from 1970-01-01T00:00:00Z
097 */
098 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
099 int millisOfDay)
100 throws IllegalArgumentException
101 {
102 long instant = year().set(0, year);
103 instant = monthOfYear().set(instant, monthOfYear);
104 instant = dayOfMonth().set(instant, dayOfMonth);
105 return millisOfDay().set(instant, millisOfDay);
106 }
107
108 /**
109 * Returns a datetime millisecond instant, formed from the given year,
110 * month, day, hour, minute, second, and millisecond values. The set of
111 * given values must refer to a valid datetime, or else an
112 * IllegalArgumentException is thrown.
113 * <p>
114 * The default implementation calls upon separate DateTimeFields to
115 * determine the result. Subclasses are encouraged to provide a more
116 * efficient implementation.
117 *
118 * @param year year to use
119 * @param monthOfYear month to use
120 * @param dayOfMonth day of month to use
121 * @param hourOfDay hour to use
122 * @param minuteOfHour minute to use
123 * @param secondOfMinute second to use
124 * @param millisOfSecond millisecond to use
125 * @return millisecond instant from 1970-01-01T00:00:00Z
126 */
127 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
128 int hourOfDay, int minuteOfHour,
129 int secondOfMinute, int millisOfSecond)
130 throws IllegalArgumentException
131 {
132 long instant = year().set(0, year);
133 instant = monthOfYear().set(instant, monthOfYear);
134 instant = dayOfMonth().set(instant, dayOfMonth);
135 instant = hourOfDay().set(instant, hourOfDay);
136 instant = minuteOfHour().set(instant, minuteOfHour);
137 instant = secondOfMinute().set(instant, secondOfMinute);
138 return millisOfSecond().set(instant, millisOfSecond);
139 }
140
141 /**
142 * Returns a datetime millisecond instant, from from the given instant,
143 * hour, minute, second, and millisecond values. The set of given values
144 * must refer to a valid datetime, or else an IllegalArgumentException is
145 * thrown.
146 * <p>
147 * The default implementation calls upon separate DateTimeFields to
148 * determine the result. Subclasses are encouraged to provide a more
149 * efficient implementation.
150 *
151 * @param instant instant to start from
152 * @param hourOfDay hour to use
153 * @param minuteOfHour minute to use
154 * @param secondOfMinute second to use
155 * @param millisOfSecond millisecond to use
156 * @return millisecond instant from 1970-01-01T00:00:00Z
157 */
158 public long getDateTimeMillis(long instant,
159 int hourOfDay, int minuteOfHour,
160 int secondOfMinute, int millisOfSecond)
161 throws IllegalArgumentException
162 {
163 instant = hourOfDay().set(instant, hourOfDay);
164 instant = minuteOfHour().set(instant, minuteOfHour);
165 instant = secondOfMinute().set(instant, secondOfMinute);
166 return millisOfSecond().set(instant, millisOfSecond);
167 }
168
169 //-----------------------------------------------------------------------
170 /**
171 * Validates whether the fields stored in a partial instant are valid.
172 * <p>
173 * This implementation uses {@link DateTimeField#getMinimumValue(ReadablePartial, int[])}
174 * and {@link DateTimeField#getMaximumValue(ReadablePartial, int[])}.
175 *
176 * @param partial the partial instant to validate
177 * @param values the values to validate, not null unless the partial is empty
178 * @throws IllegalArgumentException if the instant is invalid
179 */
180 public void validate(ReadablePartial partial, int[] values) {
181 // check values in standard range, catching really stupid cases like -1
182 // this means that the second check will not hit trouble
183 int size = partial.size();
184 for (int i = 0; i < size; i++) {
185 int value = values[i];
186 DateTimeField field = partial.getField(i);
187 if (value < field.getMinimumValue()) {
188 throw new IllegalFieldValueException
189 (field.getType(), Integer.valueOf(value),
190 Integer.valueOf(field.getMinimumValue()), null);
191 }
192 if (value > field.getMaximumValue()) {
193 throw new IllegalFieldValueException
194 (field.getType(), Integer.valueOf(value),
195 null, Integer.valueOf(field.getMaximumValue()));
196 }
197 }
198 // check values in specific range, catching really odd cases like 30th Feb
199 for (int i = 0; i < size; i++) {
200 int value = values[i];
201 DateTimeField field = partial.getField(i);
202 if (value < field.getMinimumValue(partial, values)) {
203 throw new IllegalFieldValueException
204 (field.getType(), Integer.valueOf(value),
205 Integer.valueOf(field.getMinimumValue(partial, values)), null);
206 }
207 if (value > field.getMaximumValue(partial, values)) {
208 throw new IllegalFieldValueException
209 (field.getType(), Integer.valueOf(value),
210 null, Integer.valueOf(field.getMaximumValue(partial, values)));
211 }
212 }
213 }
214
215 /**
216 * Gets the values of a partial from an instant.
217 *
218 * @param partial the partial instant to use
219 * @param instant the instant to query
220 * @return the values of the partial extracted from the instant
221 */
222 public int[] get(ReadablePartial partial, long instant) {
223 int size = partial.size();
224 int[] values = new int[size];
225 for (int i = 0; i < size; i++) {
226 values[i] = partial.getFieldType(i).getField(this).get(instant);
227 }
228 return values;
229 }
230
231 /**
232 * Sets the partial into the instant.
233 *
234 * @param partial the partial instant to use
235 * @param instant the instant to update
236 * @return the updated instant
237 */
238 public long set(ReadablePartial partial, long instant) {
239 for (int i = 0, isize = partial.size(); i < isize; i++) {
240 instant = partial.getFieldType(i).getField(this).set(instant, partial.getValue(i));
241 }
242 return instant;
243 }
244
245 //-----------------------------------------------------------------------
246 /**
247 * Gets the values of a period from an interval.
248 *
249 * @param period the period instant to use
250 * @param startInstant the start instant of an interval to query
251 * @param endInstant the start instant of an interval to query
252 * @return the values of the period extracted from the interval
253 */
254 public int[] get(ReadablePeriod period, long startInstant, long endInstant) {
255 int size = period.size();
256 int[] values = new int[size];
257 if (startInstant != endInstant) {
258 for (int i = 0; i < size; i++) {
259 DurationField field = period.getFieldType(i).getField(this);
260 int value = field.getDifference(endInstant, startInstant);
261 startInstant = field.add(startInstant, value);
262 values[i] = value;
263 }
264 }
265 return values;
266 }
267
268 /**
269 * Gets the values of a period from an interval.
270 *
271 * @param period the period instant to use
272 * @param duration the duration to query
273 * @return the values of the period extracted from the duration
274 */
275 public int[] get(ReadablePeriod period, long duration) {
276 int size = period.size();
277 int[] values = new int[size];
278 if (duration != 0) {
279 long current = 0;
280 for (int i = 0; i < size; i++) {
281 DurationField field = period.getFieldType(i).getField(this);
282 if (field.isPrecise()) {
283 int value = field.getDifference(duration, current);
284 current = field.add(current, value);
285 values[i] = value;
286 }
287 }
288 }
289 return values;
290 }
291
292 /**
293 * Adds the period to the instant, specifying the number of times to add.
294 *
295 * @param period the period to add, null means add nothing
296 * @param instant the instant to add to
297 * @param scalar the number of times to add
298 * @return the updated instant
299 */
300 public long add(ReadablePeriod period, long instant, int scalar) {
301 if (scalar != 0 && period != null) {
302 for (int i = 0, isize = period.size(); i < isize; i++) {
303 long value = period.getValue(i); // use long to allow for multiplication (fits OK)
304 if (value != 0) {
305 instant = period.getFieldType(i).getField(this).add(instant, value * scalar);
306 }
307 }
308 }
309 return instant;
310 }
311
312 //-----------------------------------------------------------------------
313 /**
314 * Adds the duration to the instant, specifying the number of times to add.
315 *
316 * @param instant the instant to add to
317 * @param duration the duration to add
318 * @param scalar the number of times to add
319 * @return the updated instant
320 */
321 public long add(long instant, long duration, int scalar) {
322 if (duration == 0 || scalar == 0) {
323 return instant;
324 }
325 long add = FieldUtils.safeMultiply(duration, scalar);
326 return FieldUtils.safeAdd(instant, add);
327 }
328
329 // Millis
330 //-----------------------------------------------------------------------
331 /**
332 * Get the millis duration field for this chronology.
333 *
334 * @return DurationField or UnsupportedDurationField if unsupported
335 */
336 public DurationField millis() {
337 return UnsupportedDurationField.getInstance(DurationFieldType.millis());
338 }
339
340 /**
341 * Get the millis of second field for this chronology.
342 *
343 * @return DateTimeField or UnsupportedDateTimeField if unsupported
344 */
345 public DateTimeField millisOfSecond() {
346 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.millisOfSecond(), millis());
347 }
348
349 /**
350 * Get the millis of day field for this chronology.
351 *
352 * @return DateTimeField or UnsupportedDateTimeField if unsupported
353 */
354 public DateTimeField millisOfDay() {
355 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.millisOfDay(), millis());
356 }
357
358 // Second
359 //-----------------------------------------------------------------------
360 /**
361 * Get the seconds duration field for this chronology.
362 *
363 * @return DurationField or UnsupportedDurationField if unsupported
364 */
365 public DurationField seconds() {
366 return UnsupportedDurationField.getInstance(DurationFieldType.seconds());
367 }
368
369 /**
370 * Get the second of minute field for this chronology.
371 *
372 * @return DateTimeField or UnsupportedDateTimeField if unsupported
373 */
374 public DateTimeField secondOfMinute() {
375 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.secondOfMinute(), seconds());
376 }
377
378 /**
379 * Get the second of day field for this chronology.
380 *
381 * @return DateTimeField or UnsupportedDateTimeField if unsupported
382 */
383 public DateTimeField secondOfDay() {
384 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.secondOfDay(), seconds());
385 }
386
387 // Minute
388 //-----------------------------------------------------------------------
389 /**
390 * Get the minutes duration field for this chronology.
391 *
392 * @return DurationField or UnsupportedDurationField if unsupported
393 */
394 public DurationField minutes() {
395 return UnsupportedDurationField.getInstance(DurationFieldType.minutes());
396 }
397
398 /**
399 * Get the minute of hour field for this chronology.
400 *
401 * @return DateTimeField or UnsupportedDateTimeField if unsupported
402 */
403 public DateTimeField minuteOfHour() {
404 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.minuteOfHour(), minutes());
405 }
406
407 /**
408 * Get the minute of day field for this chronology.
409 *
410 * @return DateTimeField or UnsupportedDateTimeField if unsupported
411 */
412 public DateTimeField minuteOfDay() {
413 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.minuteOfDay(), minutes());
414 }
415
416 // Hour
417 //-----------------------------------------------------------------------
418 /**
419 * Get the hours duration field for this chronology.
420 *
421 * @return DurationField or UnsupportedDurationField if unsupported
422 */
423 public DurationField hours() {
424 return UnsupportedDurationField.getInstance(DurationFieldType.hours());
425 }
426
427 /**
428 * Get the hour of day (0-23) field for this chronology.
429 *
430 * @return DateTimeField or UnsupportedDateTimeField if unsupported
431 */
432 public DateTimeField hourOfDay() {
433 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.hourOfDay(), hours());
434 }
435
436 /**
437 * Get the hour of day (offset to 1-24) field for this chronology.
438 *
439 * @return DateTimeField or UnsupportedDateTimeField if unsupported
440 */
441 public DateTimeField clockhourOfDay() {
442 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.clockhourOfDay(), hours());
443 }
444
445 // Halfday
446 //-----------------------------------------------------------------------
447 /**
448 * Get the halfdays duration field for this chronology.
449 *
450 * @return DurationField or UnsupportedDurationField if unsupported
451 */
452 public DurationField halfdays() {
453 return UnsupportedDurationField.getInstance(DurationFieldType.halfdays());
454 }
455
456 /**
457 * Get the hour of am/pm (0-11) field for this chronology.
458 *
459 * @return DateTimeField or UnsupportedDateTimeField if unsupported
460 */
461 public DateTimeField hourOfHalfday() {
462 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.hourOfHalfday(), hours());
463 }
464
465 /**
466 * Get the hour of am/pm (offset to 1-12) field for this chronology.
467 *
468 * @return DateTimeField or UnsupportedDateTimeField if unsupported
469 */
470 public DateTimeField clockhourOfHalfday() {
471 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.clockhourOfHalfday(), hours());
472 }
473
474 /**
475 * Get the AM(0) PM(1) field for this chronology.
476 *
477 * @return DateTimeField or UnsupportedDateTimeField if unsupported
478 */
479 public DateTimeField halfdayOfDay() {
480 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.halfdayOfDay(), halfdays());
481 }
482
483 // Day
484 //-----------------------------------------------------------------------
485 /**
486 * Get the days duration field for this chronology.
487 *
488 * @return DurationField or UnsupportedDurationField if unsupported
489 */
490 public DurationField days() {
491 return UnsupportedDurationField.getInstance(DurationFieldType.days());
492 }
493
494 /**
495 * Get the day of week field for this chronology.
496 *
497 * <p>DayOfWeek values are defined in
498 * {@link org.joda.time.DateTimeConstants DateTimeConstants}.
499 * They use the ISO definitions, where 1 is Monday and 7 is Sunday.
500 *
501 * @return DateTimeField or UnsupportedDateTimeField if unsupported
502 */
503 public DateTimeField dayOfWeek() {
504 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.dayOfWeek(), days());
505 }
506
507 /**
508 * Get the day of month field for this chronology.
509 *
510 * @return DateTimeField or UnsupportedDateTimeField if unsupported
511 */
512 public DateTimeField dayOfMonth() {
513 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.dayOfMonth(), days());
514 }
515
516 /**
517 * Get the day of year field for this chronology.
518 *
519 * @return DateTimeField or UnsupportedDateTimeField if unsupported
520 */
521 public DateTimeField dayOfYear() {
522 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.dayOfYear(), days());
523 }
524
525 // Week
526 //-----------------------------------------------------------------------
527 /**
528 * Get the weeks duration field for this chronology.
529 *
530 * @return DurationField or UnsupportedDurationField if unsupported
531 */
532 public DurationField weeks() {
533 return UnsupportedDurationField.getInstance(DurationFieldType.weeks());
534 }
535
536 /**
537 * Get the week of a week based year field for this chronology.
538 *
539 * @return DateTimeField or UnsupportedDateTimeField if unsupported
540 */
541 public DateTimeField weekOfWeekyear() {
542 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.weekOfWeekyear(), weeks());
543 }
544
545 // Weekyear
546 //-----------------------------------------------------------------------
547 /**
548 * Get the weekyears duration field for this chronology.
549 *
550 * @return DurationField or UnsupportedDurationField if unsupported
551 */
552 public DurationField weekyears() {
553 return UnsupportedDurationField.getInstance(DurationFieldType.weekyears());
554 }
555
556 /**
557 * Get the year of a week based year field for this chronology.
558 *
559 * @return DateTimeField or UnsupportedDateTimeField if unsupported
560 */
561 public DateTimeField weekyear() {
562 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.weekyear(), weekyears());
563 }
564
565 /**
566 * Get the year of a week based year in a century field for this chronology.
567 *
568 * @return DateTimeField or UnsupportedDateTimeField if unsupported
569 */
570 public DateTimeField weekyearOfCentury() {
571 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.weekyearOfCentury(), weekyears());
572 }
573
574 // Month
575 //-----------------------------------------------------------------------
576 /**
577 * Get the months duration field for this chronology.
578 *
579 * @return DurationField or UnsupportedDurationField if unsupported
580 */
581 public DurationField months() {
582 return UnsupportedDurationField.getInstance(DurationFieldType.months());
583 }
584
585 /**
586 * Get the month of year field for this chronology.
587 *
588 * @return DateTimeField or UnsupportedDateTimeField if unsupported
589 */
590 public DateTimeField monthOfYear() {
591 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.monthOfYear(), months());
592 }
593
594 // Year
595 //-----------------------------------------------------------------------
596 /**
597 * Get the years duration field for this chronology.
598 *
599 * @return DurationField or UnsupportedDurationField if unsupported
600 */
601 public DurationField years() {
602 return UnsupportedDurationField.getInstance(DurationFieldType.years());
603 }
604
605 /**
606 * Get the year field for this chronology.
607 *
608 * @return DateTimeField or UnsupportedDateTimeField if unsupported
609 */
610 public DateTimeField year() {
611 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.year(), years());
612 }
613
614 /**
615 * Get the year of era field for this chronology.
616 *
617 * @return DateTimeField or UnsupportedDateTimeField if unsupported
618 */
619 public DateTimeField yearOfEra() {
620 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.yearOfEra(), years());
621 }
622
623 /**
624 * Get the year of century field for this chronology.
625 *
626 * @return DateTimeField or UnsupportedDateTimeField if unsupported
627 */
628 public DateTimeField yearOfCentury() {
629 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.yearOfCentury(), years());
630 }
631
632 // Century
633 //-----------------------------------------------------------------------
634 /**
635 * Get the centuries duration field for this chronology.
636 *
637 * @return DurationField or UnsupportedDurationField if unsupported
638 */
639 public DurationField centuries() {
640 return UnsupportedDurationField.getInstance(DurationFieldType.centuries());
641 }
642
643 /**
644 * Get the century of era field for this chronology.
645 *
646 * @return DateTimeField or UnsupportedDateTimeField if unsupported
647 */
648 public DateTimeField centuryOfEra() {
649 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.centuryOfEra(), centuries());
650 }
651
652 // Era
653 //-----------------------------------------------------------------------
654 /**
655 * Get the eras duration field for this chronology.
656 *
657 * @return DurationField or UnsupportedDurationField if unsupported
658 */
659 public DurationField eras() {
660 return UnsupportedDurationField.getInstance(DurationFieldType.eras());
661 }
662
663 /**
664 * Get the era field for this chronology.
665 *
666 * @return DateTimeField or UnsupportedDateTimeField if unsupported
667 */
668 public DateTimeField era() {
669 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.era(), eras());
670 }
671
672 //-----------------------------------------------------------------------
673 /**
674 * Gets a debugging toString.
675 *
676 * @return a debugging string
677 */
678 public abstract String toString();
679
680 }