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 */
016package org.joda.time;
017
018import java.io.Serializable;
019
020/**
021 * Identifies a field, such as year or minuteOfHour, in a chronology-neutral way.
022 * <p>
023 * A field type defines the type of the field, such as hourOfDay.
024 * If does not directly enable any calculations, however it does provide a
025 * {@link #getField(Chronology)} method that returns the actual calculation engine
026 * for a particular chronology.
027 * It also provides access to the related {@link DurationFieldType}s.
028 * <p>
029 * Instances of <code>DateTimeFieldType</code> are singletons.
030 * They can be compared using <code>==</code>.
031 * <p>
032 * If required, you can create your own field, for example a quarterOfYear.
033 * You must create a subclass of <code>DateTimeFieldType</code> that defines the field type.
034 * This class returns the actual calculation engine from {@link #getField(Chronology)}.
035 *
036 * @author Stephen Colebourne
037 * @author Brian S O'Neill
038 * @since 1.0
039 */
040public abstract class DateTimeFieldType implements Serializable {
041
042    /** Serialization version */
043    private static final long serialVersionUID = -42615285973990L;
044
045    /** Ordinal values for standard field types. */
046    static final byte
047        ERA = 1,
048        YEAR_OF_ERA = 2,
049        CENTURY_OF_ERA = 3,
050        YEAR_OF_CENTURY = 4,
051        YEAR = 5,
052        DAY_OF_YEAR = 6,
053        MONTH_OF_YEAR = 7,
054        DAY_OF_MONTH = 8,
055        WEEKYEAR_OF_CENTURY = 9,
056        WEEKYEAR = 10,
057        WEEK_OF_WEEKYEAR = 11,
058        DAY_OF_WEEK = 12,
059        HALFDAY_OF_DAY = 13,
060        HOUR_OF_HALFDAY = 14,
061        CLOCKHOUR_OF_HALFDAY = 15,
062        CLOCKHOUR_OF_DAY = 16,
063        HOUR_OF_DAY = 17,
064        MINUTE_OF_DAY = 18,
065        MINUTE_OF_HOUR = 19,
066        SECOND_OF_DAY = 20,
067        SECOND_OF_MINUTE = 21,
068        MILLIS_OF_DAY = 22,
069        MILLIS_OF_SECOND = 23;
070
071    /** The era field type. */
072    private static final DateTimeFieldType ERA_TYPE = new StandardDateTimeFieldType(
073        "era", ERA, DurationFieldType.eras(), null);
074    /** The yearOfEra field type. */
075    private static final DateTimeFieldType YEAR_OF_ERA_TYPE = new StandardDateTimeFieldType(
076        "yearOfEra", YEAR_OF_ERA, DurationFieldType.years(), DurationFieldType.eras());
077    /** The centuryOfEra field type. */
078    private static final DateTimeFieldType CENTURY_OF_ERA_TYPE = new StandardDateTimeFieldType(
079        "centuryOfEra", CENTURY_OF_ERA, DurationFieldType.centuries(), DurationFieldType.eras());
080    /** The yearOfCentury field type. */
081    private static final DateTimeFieldType YEAR_OF_CENTURY_TYPE = new StandardDateTimeFieldType(
082        "yearOfCentury", YEAR_OF_CENTURY, DurationFieldType.years(), DurationFieldType.centuries());
083    /** The year field type. */
084    private static final DateTimeFieldType YEAR_TYPE = new StandardDateTimeFieldType(
085        "year", YEAR, DurationFieldType.years(), null);
086    /** The dayOfYear field type. */
087    private static final DateTimeFieldType DAY_OF_YEAR_TYPE = new StandardDateTimeFieldType(
088        "dayOfYear", DAY_OF_YEAR, DurationFieldType.days(), DurationFieldType.years());
089    /** The monthOfYear field type. */
090    private static final DateTimeFieldType MONTH_OF_YEAR_TYPE = new StandardDateTimeFieldType(
091        "monthOfYear", MONTH_OF_YEAR, DurationFieldType.months(), DurationFieldType.years());
092    /** The dayOfMonth field type. */
093    private static final DateTimeFieldType DAY_OF_MONTH_TYPE = new StandardDateTimeFieldType(
094        "dayOfMonth", DAY_OF_MONTH, DurationFieldType.days(), DurationFieldType.months());
095    /** The weekyearOfCentury field type. */
096    private static final DateTimeFieldType WEEKYEAR_OF_CENTURY_TYPE = new StandardDateTimeFieldType(
097        "weekyearOfCentury", WEEKYEAR_OF_CENTURY, DurationFieldType.weekyears(), DurationFieldType.centuries());
098    /** The weekyear field type. */
099    private static final DateTimeFieldType WEEKYEAR_TYPE = new StandardDateTimeFieldType(
100        "weekyear", WEEKYEAR, DurationFieldType.weekyears(), null);
101    /** The weekOfWeekyear field type. */
102    private static final DateTimeFieldType WEEK_OF_WEEKYEAR_TYPE = new StandardDateTimeFieldType(
103        "weekOfWeekyear", WEEK_OF_WEEKYEAR, DurationFieldType.weeks(), DurationFieldType.weekyears());
104    /** The dayOfWeek field type. */
105    private static final DateTimeFieldType DAY_OF_WEEK_TYPE = new StandardDateTimeFieldType(
106        "dayOfWeek", DAY_OF_WEEK, DurationFieldType.days(), DurationFieldType.weeks());
107
108    /** The halfday field type. */
109    private static final DateTimeFieldType HALFDAY_OF_DAY_TYPE = new StandardDateTimeFieldType(
110        "halfdayOfDay", HALFDAY_OF_DAY, DurationFieldType.halfdays(), DurationFieldType.days());
111    /** The hourOfHalfday field type. */
112    private static final DateTimeFieldType HOUR_OF_HALFDAY_TYPE = new StandardDateTimeFieldType(
113        "hourOfHalfday", HOUR_OF_HALFDAY, DurationFieldType.hours(), DurationFieldType.halfdays());
114    /** The clockhourOfHalfday field type. */
115    private static final DateTimeFieldType CLOCKHOUR_OF_HALFDAY_TYPE = new StandardDateTimeFieldType(
116        "clockhourOfHalfday", CLOCKHOUR_OF_HALFDAY, DurationFieldType.hours(), DurationFieldType.halfdays());
117    /** The clockhourOfDay field type. */
118    private static final DateTimeFieldType CLOCKHOUR_OF_DAY_TYPE = new StandardDateTimeFieldType(
119        "clockhourOfDay", CLOCKHOUR_OF_DAY, DurationFieldType.hours(), DurationFieldType.days());
120    /** The hourOfDay field type. */
121    private static final DateTimeFieldType HOUR_OF_DAY_TYPE = new StandardDateTimeFieldType(
122        "hourOfDay", HOUR_OF_DAY, DurationFieldType.hours(), DurationFieldType.days());
123    /** The minuteOfDay field type. */
124    private static final DateTimeFieldType MINUTE_OF_DAY_TYPE = new StandardDateTimeFieldType(
125        "minuteOfDay", MINUTE_OF_DAY, DurationFieldType.minutes(), DurationFieldType.days());
126    /** The minuteOfHour field type. */
127    private static final DateTimeFieldType MINUTE_OF_HOUR_TYPE = new StandardDateTimeFieldType(
128        "minuteOfHour", MINUTE_OF_HOUR, DurationFieldType.minutes(), DurationFieldType.hours());
129    /** The secondOfDay field type. */
130    private static final DateTimeFieldType SECOND_OF_DAY_TYPE = new StandardDateTimeFieldType(
131        "secondOfDay", SECOND_OF_DAY, DurationFieldType.seconds(), DurationFieldType.days());
132    /** The secondOfMinute field type. */
133    private static final DateTimeFieldType SECOND_OF_MINUTE_TYPE = new StandardDateTimeFieldType(
134        "secondOfMinute", SECOND_OF_MINUTE, DurationFieldType.seconds(), DurationFieldType.minutes());
135    /** The millisOfDay field type. */
136    private static final DateTimeFieldType MILLIS_OF_DAY_TYPE = new StandardDateTimeFieldType(
137        "millisOfDay", MILLIS_OF_DAY, DurationFieldType.millis(), DurationFieldType.days());
138    /** The millisOfSecond field type. */
139    private static final DateTimeFieldType MILLIS_OF_SECOND_TYPE = new StandardDateTimeFieldType(
140        "millisOfSecond", MILLIS_OF_SECOND, DurationFieldType.millis(), DurationFieldType.seconds());
141
142    /** The name of the field. */
143    private final String iName;
144
145    //-----------------------------------------------------------------------
146    /**
147     * Constructor.
148     * 
149     * @param name  the name to use
150     */
151    protected DateTimeFieldType(String name) {
152        super();
153        iName = name;
154    }
155
156    //-----------------------------------------------------------------------
157    /**
158     * Get the millis of second field type.
159     * 
160     * @return the DateTimeFieldType constant
161     */
162    public static DateTimeFieldType millisOfSecond() {
163        return MILLIS_OF_SECOND_TYPE;
164    }
165
166    /**
167     * Get the millis of day field type.
168     * 
169     * @return the DateTimeFieldType constant
170     */
171    public static DateTimeFieldType millisOfDay() {
172        return MILLIS_OF_DAY_TYPE;
173    }
174
175    /**
176     * Get the second of minute field type.
177     * 
178     * @return the DateTimeFieldType constant
179     */
180    public static DateTimeFieldType secondOfMinute() {
181        return SECOND_OF_MINUTE_TYPE;
182    }
183
184    /**
185     * Get the second of day field type.
186     * 
187     * @return the DateTimeFieldType constant
188     */
189    public static DateTimeFieldType secondOfDay() {
190        return SECOND_OF_DAY_TYPE;
191    }
192
193    /**
194     * Get the minute of hour field type.
195     * 
196     * @return the DateTimeFieldType constant
197     */
198    public static DateTimeFieldType minuteOfHour() {
199        return MINUTE_OF_HOUR_TYPE;
200    }
201
202    /**
203     * Get the minute of day field type.
204     * 
205     * @return the DateTimeFieldType constant
206     */
207    public static DateTimeFieldType minuteOfDay() {
208        return MINUTE_OF_DAY_TYPE;
209    }
210
211    /**
212     * Get the hour of day (0-23) field type.
213     * 
214     * @return the DateTimeFieldType constant
215     */
216    public static DateTimeFieldType hourOfDay() {
217        return HOUR_OF_DAY_TYPE;
218    }
219
220    /**
221     * Get the hour of day (offset to 1-24) field type.
222     * 
223     * @return the DateTimeFieldType constant
224     */
225    public static DateTimeFieldType clockhourOfDay() {
226        return CLOCKHOUR_OF_DAY_TYPE;
227    }
228
229    /**
230     * Get the hour of am/pm (0-11) field type.
231     * 
232     * @return the DateTimeFieldType constant
233     */
234    public static DateTimeFieldType hourOfHalfday() {
235        return HOUR_OF_HALFDAY_TYPE;
236    }
237
238    /**
239     * Get the hour of am/pm (offset to 1-12) field type.
240     * 
241     * @return the DateTimeFieldType constant
242     */
243    public static DateTimeFieldType clockhourOfHalfday() {
244        return CLOCKHOUR_OF_HALFDAY_TYPE;
245    }
246
247    /**
248     * Get the AM(0) PM(1) field type.
249     * 
250     * @return the DateTimeFieldType constant
251     */
252    public static DateTimeFieldType halfdayOfDay() {
253        return HALFDAY_OF_DAY_TYPE;
254    }
255
256    //-----------------------------------------------------------------------
257    /**
258     * Get the day of week field type.
259     * 
260     * @return the DateTimeFieldType constant
261     */
262    public static DateTimeFieldType dayOfWeek() {
263        return DAY_OF_WEEK_TYPE;
264    }
265
266    /**
267     * Get the day of month field type.
268     * 
269     * @return the DateTimeFieldType constant
270     */
271    public static DateTimeFieldType dayOfMonth() {
272        return DAY_OF_MONTH_TYPE;
273    }
274
275    /**
276     * Get the day of year field type.
277     * 
278     * @return the DateTimeFieldType constant
279     */
280    public static DateTimeFieldType dayOfYear() {
281        return DAY_OF_YEAR_TYPE;
282    }
283
284    /**
285     * Get the week of a week based year field type.
286     * 
287     * @return the DateTimeFieldType constant
288     */
289    public static DateTimeFieldType weekOfWeekyear() {
290        return WEEK_OF_WEEKYEAR_TYPE;
291    }
292
293    /**
294     * Get the year of a week based year field type.
295     * 
296     * @return the DateTimeFieldType constant
297     */
298    public static DateTimeFieldType weekyear() {
299        return WEEKYEAR_TYPE;
300    }
301
302    /**
303     * Get the year of a week based year within a century field type.
304     * 
305     * @return the DateTimeFieldType constant
306     */
307    public static DateTimeFieldType weekyearOfCentury() {
308        return WEEKYEAR_OF_CENTURY_TYPE;
309    }
310
311    /**
312     * Get the month of year field type.
313     * 
314     * @return the DateTimeFieldType constant
315     */
316    public static DateTimeFieldType monthOfYear() {
317        return MONTH_OF_YEAR_TYPE;
318    }
319
320    /**
321     * Get the year field type.
322     * 
323     * @return the DateTimeFieldType constant
324     */
325    public static DateTimeFieldType year() {
326        return YEAR_TYPE;
327    }
328
329    /**
330     * Get the year of era field type.
331     * 
332     * @return the DateTimeFieldType constant
333     */
334    public static DateTimeFieldType yearOfEra() {
335        return YEAR_OF_ERA_TYPE;
336    }
337
338    /**
339     * Get the year of century field type.
340     * 
341     * @return the DateTimeFieldType constant
342     */
343    public static DateTimeFieldType yearOfCentury() {
344        return YEAR_OF_CENTURY_TYPE;
345    }
346
347    /**
348     * Get the century of era field type.
349     * 
350     * @return the DateTimeFieldType constant
351     */
352    public static DateTimeFieldType centuryOfEra() {
353        return CENTURY_OF_ERA_TYPE;
354    }
355
356    /**
357     * Get the era field type.
358     * 
359     * @return the DateTimeFieldType constant
360     */
361    public static DateTimeFieldType era() {
362        return ERA_TYPE;
363    }
364
365    //-----------------------------------------------------------------------
366    /**
367     * Get the name of the field.
368     * <p>
369     * By convention, names follow a pattern of "dddOfRrr", where "ddd" represents
370     * the (singular) duration unit field name and "Rrr" represents the (singular)
371     * duration range field name. If the range field is not applicable, then
372     * the name of the field is simply the (singular) duration field name.
373     * 
374     * @return field name
375     */
376    public String getName() {
377        return iName;
378    }
379
380    /**
381     * Get the duration unit of the field.
382     * 
383     * @return duration unit of the field, never null
384     */
385    public abstract DurationFieldType getDurationType();
386
387    /**
388     * Get the duration range of the field.
389     * 
390     * @return duration range of the field, null if unbounded
391     */
392    public abstract DurationFieldType getRangeDurationType();
393
394    /**
395     * Gets a suitable field for this type from the given Chronology.
396     *
397     * @param chronology  the chronology to use, null means ISOChronology in default zone
398     * @return a suitable field
399     */
400    public abstract DateTimeField getField(Chronology chronology);
401
402    /**
403     * Checks whether this field supported in the given Chronology.
404     *
405     * @param chronology  the chronology to use, null means ISOChronology in default zone
406     * @return true if supported
407     */
408    public boolean isSupported(Chronology chronology) {
409        return getField(chronology).isSupported();
410    }
411
412    /**
413     * Get a suitable debug string.
414     * 
415     * @return debug string
416     */
417    public String toString() {
418        return getName();
419    }
420
421    private static class StandardDateTimeFieldType extends DateTimeFieldType {
422        /** Serialization version */
423        private static final long serialVersionUID = -9937958251642L;
424
425        /** The ordinal of the standard field type, for switch statements */
426        private final byte iOrdinal;
427
428        /** The unit duration of the field. */
429        private final transient DurationFieldType iUnitType;
430        /** The range duration of the field. */
431        private final transient DurationFieldType iRangeType;
432
433        /**
434         * Constructor.
435         * 
436         * @param name  the name to use
437         * @param ordinal  the byte value for the oridinal index
438         * @param unitType  the unit duration type
439         * @param rangeType  the range duration type
440         */
441        StandardDateTimeFieldType(String name, byte ordinal,
442                                  DurationFieldType unitType, DurationFieldType rangeType) {
443            super(name);
444            iOrdinal = ordinal;
445            iUnitType = unitType;
446            iRangeType = rangeType;
447        }
448
449        /** @inheritdoc */
450        public DurationFieldType getDurationType() {
451            return iUnitType;
452        }
453
454        /** @inheritdoc */
455        public DurationFieldType getRangeDurationType() {
456            return iRangeType;
457        }
458
459        /** @inheritdoc */
460        public DateTimeField getField(Chronology chronology) {
461            chronology = DateTimeUtils.getChronology(chronology);
462
463            switch (iOrdinal) {
464                case ERA:
465                    return chronology.era();
466                case YEAR_OF_ERA:
467                    return chronology.yearOfEra();
468                case CENTURY_OF_ERA:
469                    return chronology.centuryOfEra();
470                case YEAR_OF_CENTURY:
471                    return chronology.yearOfCentury();
472                case YEAR:
473                    return chronology.year();
474                case DAY_OF_YEAR:
475                    return chronology.dayOfYear();
476                case MONTH_OF_YEAR:
477                    return chronology.monthOfYear();
478                case DAY_OF_MONTH:
479                    return chronology.dayOfMonth();
480                case WEEKYEAR_OF_CENTURY:
481                    return chronology.weekyearOfCentury();
482                case WEEKYEAR:
483                    return chronology.weekyear();
484                case WEEK_OF_WEEKYEAR:
485                    return chronology.weekOfWeekyear();
486                case DAY_OF_WEEK:
487                    return chronology.dayOfWeek();
488                case HALFDAY_OF_DAY:
489                    return chronology.halfdayOfDay();
490                case HOUR_OF_HALFDAY:
491                    return chronology.hourOfHalfday();
492                case CLOCKHOUR_OF_HALFDAY:
493                    return chronology.clockhourOfHalfday();
494                case CLOCKHOUR_OF_DAY:
495                    return chronology.clockhourOfDay();
496                case HOUR_OF_DAY:
497                    return chronology.hourOfDay();
498                case MINUTE_OF_DAY:
499                    return chronology.minuteOfDay();
500                case MINUTE_OF_HOUR:
501                    return chronology.minuteOfHour();
502                case SECOND_OF_DAY:
503                    return chronology.secondOfDay();
504                case SECOND_OF_MINUTE:
505                    return chronology.secondOfMinute();
506                case MILLIS_OF_DAY:
507                    return chronology.millisOfDay();
508                case MILLIS_OF_SECOND:
509                    return chronology.millisOfSecond();
510                default:
511                    // Shouldn't happen.
512                    throw new InternalError();
513            }
514        }
515
516        /**
517         * Ensure a singleton is returned.
518         * 
519         * @return the singleton type
520         */
521        private Object readResolve() {
522            switch (iOrdinal) {
523                case ERA:
524                    return ERA_TYPE;
525                case YEAR_OF_ERA:
526                    return YEAR_OF_ERA_TYPE;
527                case CENTURY_OF_ERA:
528                    return CENTURY_OF_ERA_TYPE;
529                case YEAR_OF_CENTURY:
530                    return YEAR_OF_CENTURY_TYPE;
531                case YEAR:
532                    return YEAR_TYPE;
533                case DAY_OF_YEAR:
534                    return DAY_OF_YEAR_TYPE;
535                case MONTH_OF_YEAR:
536                    return MONTH_OF_YEAR_TYPE;
537                case DAY_OF_MONTH:
538                    return DAY_OF_MONTH_TYPE;
539                case WEEKYEAR_OF_CENTURY:
540                    return WEEKYEAR_OF_CENTURY_TYPE;
541                case WEEKYEAR:
542                    return WEEKYEAR_TYPE;
543                case WEEK_OF_WEEKYEAR:
544                    return WEEK_OF_WEEKYEAR_TYPE;
545                case DAY_OF_WEEK:
546                    return DAY_OF_WEEK_TYPE;
547                case HALFDAY_OF_DAY:
548                    return HALFDAY_OF_DAY_TYPE;
549                case HOUR_OF_HALFDAY:
550                    return HOUR_OF_HALFDAY_TYPE;
551                case CLOCKHOUR_OF_HALFDAY:
552                    return CLOCKHOUR_OF_HALFDAY_TYPE;
553                case CLOCKHOUR_OF_DAY:
554                    return CLOCKHOUR_OF_DAY_TYPE;
555                case HOUR_OF_DAY:
556                    return HOUR_OF_DAY_TYPE;
557                case MINUTE_OF_DAY:
558                    return MINUTE_OF_DAY_TYPE;
559                case MINUTE_OF_HOUR:
560                    return MINUTE_OF_HOUR_TYPE;
561                case SECOND_OF_DAY:
562                    return SECOND_OF_DAY_TYPE;
563                case SECOND_OF_MINUTE:
564                    return SECOND_OF_MINUTE_TYPE;
565                case MILLIS_OF_DAY:
566                    return MILLIS_OF_DAY_TYPE;
567                case MILLIS_OF_SECOND:
568                    return MILLIS_OF_SECOND_TYPE;
569                default:
570                    // Shouldn't happen.
571                    return this;
572            }
573        }
574    }
575
576}