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;
017    
018    import 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     */
039    public 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            /** @inheritdoc */
264            @Override
265            public boolean equals(Object obj) {
266                if (this == obj) {
267                    return true;
268                }
269                if (obj instanceof StandardDurationFieldType) {
270                    return iOrdinal == ((StandardDurationFieldType) obj).iOrdinal;
271                }
272                return false;
273            }
274    
275            /** @inheritdoc */
276            @Override
277            public int hashCode() {
278                return (1 << iOrdinal);
279            }
280    
281            public DurationField getField(Chronology chronology) {
282                chronology = DateTimeUtils.getChronology(chronology);
283                
284                switch (iOrdinal) {
285                    case ERAS:
286                        return chronology.eras();
287                    case CENTURIES:
288                        return chronology.centuries();
289                    case WEEKYEARS:
290                        return chronology.weekyears();
291                    case YEARS:
292                        return chronology.years();
293                    case MONTHS:
294                        return chronology.months();
295                    case WEEKS:
296                        return chronology.weeks();
297                    case DAYS:
298                        return chronology.days();
299                    case HALFDAYS:
300                        return chronology.halfdays();
301                    case HOURS:
302                        return chronology.hours();
303                    case MINUTES:
304                        return chronology.minutes();
305                    case SECONDS:
306                        return chronology.seconds();
307                    case MILLIS:
308                        return chronology.millis();
309                    default:
310                        // Shouldn't happen.
311                        throw new InternalError();
312                }
313            }
314    
315            /**
316             * Ensure a singleton is returned.
317             * 
318             * @return the singleton type
319             */
320            private Object readResolve() {
321                switch (iOrdinal) {
322                    case ERAS:
323                        return ERAS_TYPE;
324                    case CENTURIES:
325                        return CENTURIES_TYPE;
326                    case WEEKYEARS:
327                        return WEEKYEARS_TYPE;
328                    case YEARS:
329                        return YEARS_TYPE;
330                    case MONTHS:
331                        return MONTHS_TYPE;
332                    case WEEKS:
333                        return WEEKS_TYPE;
334                    case DAYS:
335                        return DAYS_TYPE;
336                    case HALFDAYS:
337                        return HALFDAYS_TYPE;
338                    case HOURS:
339                        return HOURS_TYPE;
340                    case MINUTES:
341                        return MINUTES_TYPE;
342                    case SECONDS:
343                        return SECONDS_TYPE;
344                    case MILLIS:
345                        return MILLIS_TYPE;
346                    default:
347                        // Shouldn't happen.
348                        return this;
349                }
350            }
351        }
352    }