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 duration field, such as years or minutes, in a chronology-neutral way.
022 * <p>
023 * A duration field type defines the type of the field, such as hours.
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 * <p>
028 * Instances of <code>DurationFieldType</code> are singletons.
029 * They can be compared using <code>==</code>.
030 * <p>
031 * If required, you can create your own field, for example a quarters.
032 * You must create a subclass of <code>DurationFieldType</code> that defines the field type.
033 * This class returns the actual calculation engine from {@link #getField(Chronology)}.
034 *
035 * @author Stephen Colebourne
036 * @author Brian S O'Neill
037 * @since 1.0
038 */
039public abstract class DurationFieldType implements Serializable {
040
041    /** Serialization version */
042    private static final long serialVersionUID = 8765135187319L;
043
044    // Ordinals for standard field types.
045    static final byte
046        ERAS = 1,
047        CENTURIES = 2,
048        WEEKYEARS = 3,
049        YEARS = 4,
050        MONTHS = 5,
051        WEEKS = 6,
052        DAYS = 7,
053        HALFDAYS = 8,
054        HOURS = 9,
055        MINUTES = 10,
056        SECONDS = 11,
057        MILLIS = 12;
058
059    /** The eras field type. */
060    static final DurationFieldType ERAS_TYPE = new StandardDurationFieldType("eras", ERAS);
061    /** The centuries field type. */
062    static final DurationFieldType CENTURIES_TYPE = new StandardDurationFieldType("centuries", CENTURIES);
063    /** The weekyears field type. */
064    static final DurationFieldType WEEKYEARS_TYPE = new StandardDurationFieldType("weekyears", WEEKYEARS);
065    /** The years field type. */
066    static final DurationFieldType YEARS_TYPE = new StandardDurationFieldType("years", YEARS);
067    /** The months field type. */
068    static final DurationFieldType MONTHS_TYPE = new StandardDurationFieldType("months", MONTHS);
069    /** The weeks field type. */
070    static final DurationFieldType WEEKS_TYPE = new StandardDurationFieldType("weeks", WEEKS);
071    /** The days field type. */
072    static final DurationFieldType DAYS_TYPE = new StandardDurationFieldType("days", DAYS);
073    /** The halfdays field type. */
074    static final DurationFieldType HALFDAYS_TYPE = new StandardDurationFieldType("halfdays", HALFDAYS);
075    /** The hours field type. */
076    static final DurationFieldType HOURS_TYPE = new StandardDurationFieldType("hours", HOURS);
077    /** The minutes field type. */
078    static final DurationFieldType MINUTES_TYPE = new StandardDurationFieldType("minutes", MINUTES);
079    /** The seconds field type. */
080    static final DurationFieldType SECONDS_TYPE = new StandardDurationFieldType("seconds", SECONDS);
081    /** The millis field type. */
082    static final DurationFieldType MILLIS_TYPE = new StandardDurationFieldType("millis", MILLIS);
083
084    /** The name of the field type. */
085    private final String iName;
086
087    //-----------------------------------------------------------------------
088    /**
089     * Constructor.
090     * 
091     * @param name  the name to use, which by convention, are plural.
092     */
093    protected DurationFieldType(String name) {
094        super();
095        iName = name;
096    }
097
098    //-----------------------------------------------------------------------
099    /**
100     * Get the millis field type.
101     * 
102     * @return the DateTimeFieldType constant
103     */
104    public static DurationFieldType millis() {
105        return MILLIS_TYPE;
106    }
107
108    /**
109     * Get the seconds field type.
110     * 
111     * @return the DateTimeFieldType constant
112     */
113    public static DurationFieldType seconds() {
114        return SECONDS_TYPE;
115    }
116
117    /**
118     * Get the minutes field type.
119     * 
120     * @return the DateTimeFieldType constant
121     */
122    public static DurationFieldType minutes() {
123        return MINUTES_TYPE;
124    }
125
126    /**
127     * Get the hours field type.
128     * 
129     * @return the DateTimeFieldType constant
130     */
131    public static DurationFieldType hours() {
132        return HOURS_TYPE;
133    }
134
135    /**
136     * Get the halfdays field type.
137     * 
138     * @return the DateTimeFieldType constant
139     */
140    public static DurationFieldType halfdays() {
141        return HALFDAYS_TYPE;
142    }
143
144    //-----------------------------------------------------------------------
145    /**
146     * Get the days field type.
147     * 
148     * @return the DateTimeFieldType constant
149     */
150    public static DurationFieldType days() {
151        return DAYS_TYPE;
152    }
153
154    /**
155     * Get the weeks field type.
156     * 
157     * @return the DateTimeFieldType constant
158     */
159    public static DurationFieldType weeks() {
160        return WEEKS_TYPE;
161    }
162
163    /**
164     * Get the weekyears field type.
165     * 
166     * @return the DateTimeFieldType constant
167     */
168    public static DurationFieldType weekyears() {
169        return WEEKYEARS_TYPE;
170    }
171
172    /**
173     * Get the months field type.
174     * 
175     * @return the DateTimeFieldType constant
176     */
177    public static DurationFieldType months() {
178        return MONTHS_TYPE;
179    }
180
181    /**
182     * Get the years field type.
183     * 
184     * @return the DateTimeFieldType constant
185     */
186    public static DurationFieldType years() {
187        return YEARS_TYPE;
188    }
189
190    /**
191     * Get the centuries field type.
192     * 
193     * @return the DateTimeFieldType constant
194     */
195    public static DurationFieldType centuries() {
196        return CENTURIES_TYPE;
197    }
198
199    /**
200     * Get the eras field type.
201     * 
202     * @return the DateTimeFieldType constant
203     */
204    public static DurationFieldType eras() {
205        return ERAS_TYPE;
206    }
207
208    //-----------------------------------------------------------------------
209    /**
210     * Get the name of the field.
211     * By convention, names are plural.
212     * 
213     * @return field name
214     */
215    public String getName() {
216        return iName;
217    }
218
219    /**
220     * Gets a suitable field for this type from the given Chronology.
221     *
222     * @param chronology  the chronology to use, null means ISOChronology in default zone
223     * @return a suitable field
224     */
225    public abstract DurationField getField(Chronology chronology);
226
227    /**
228     * Checks whether this field supported in the given Chronology.
229     *
230     * @param chronology  the chronology to use, null means ISOChronology in default zone
231     * @return true if supported
232     */
233    public boolean isSupported(Chronology chronology) {
234        return getField(chronology).isSupported();
235    }
236
237    /**
238     * Get a suitable debug string.
239     * 
240     * @return debug string
241     */
242    public String toString() {
243        return getName();
244    }
245
246    private static class StandardDurationFieldType extends DurationFieldType {
247        /** Serialization version */
248        private static final long serialVersionUID = 31156755687123L;
249
250        /** The ordinal of the standard field type, for switch statements */
251        private final byte iOrdinal;
252
253        /**
254         * Constructor.
255         * 
256         * @param name  the name to use
257         */
258        StandardDurationFieldType(String name, byte ordinal) {
259            super(name);
260            iOrdinal = ordinal;
261        }
262
263        public DurationField getField(Chronology chronology) {
264            chronology = DateTimeUtils.getChronology(chronology);
265            
266            switch (iOrdinal) {
267                case ERAS:
268                    return chronology.eras();
269                case CENTURIES:
270                    return chronology.centuries();
271                case WEEKYEARS:
272                    return chronology.weekyears();
273                case YEARS:
274                    return chronology.years();
275                case MONTHS:
276                    return chronology.months();
277                case WEEKS:
278                    return chronology.weeks();
279                case DAYS:
280                    return chronology.days();
281                case HALFDAYS:
282                    return chronology.halfdays();
283                case HOURS:
284                    return chronology.hours();
285                case MINUTES:
286                    return chronology.minutes();
287                case SECONDS:
288                    return chronology.seconds();
289                case MILLIS:
290                    return chronology.millis();
291                default:
292                    // Shouldn't happen.
293                    throw new InternalError();
294            }
295        }
296
297        /**
298         * Ensure a singleton is returned.
299         * 
300         * @return the singleton type
301         */
302        private Object readResolve() {
303            switch (iOrdinal) {
304                case ERAS:
305                    return ERAS_TYPE;
306                case CENTURIES:
307                    return CENTURIES_TYPE;
308                case WEEKYEARS:
309                    return WEEKYEARS_TYPE;
310                case YEARS:
311                    return YEARS_TYPE;
312                case MONTHS:
313                    return MONTHS_TYPE;
314                case WEEKS:
315                    return WEEKS_TYPE;
316                case DAYS:
317                    return DAYS_TYPE;
318                case HALFDAYS:
319                    return HALFDAYS_TYPE;
320                case HOURS:
321                    return HOURS_TYPE;
322                case MINUTES:
323                    return MINUTES_TYPE;
324                case SECONDS:
325                    return SECONDS_TYPE;
326                case MILLIS:
327                    return MILLIS_TYPE;
328                default:
329                    // Shouldn't happen.
330                    return this;
331            }
332        }
333
334    }
335}