1 /*
2  *  Copyright 2001-2005 Stephen Colebourne
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */

16 package org.joda.time;
17
18 import java.io.Serializable;
19
20 /**
21  * Identifies a duration field, such as years or minutes, in a chronology-neutral way.
22  * <p>
23  * A duration field type defines the type of the field, such as hours.
24  * If does not directly enable any calculations, however it does provide a
25  * {@link #getField(Chronology)} method that returns the actual calculation engine
26  * for a particular chronology.
27  * <p>
28  * Instances of <code>DurationFieldType</code> are singletons.
29  * They can be compared using <code>==</code>.
30  * <p>
31  * If required, you can create your own field, for example a quarters.
32  * You must create a subclass of <code>DurationFieldType</code> that defines the field type.
33  * This class returns the actual calculation engine from {@link #getField(Chronology)}.
34  *
35  * @author Stephen Colebourne
36  * @author Brian S O'Neill
37  * @since 1.0
38  */

39 public abstract class DurationFieldType implements Serializable {
40
41     /** Serialization version */
42     private static final long serialVersionUID = 8765135187319L;
43
44     // Ordinals for standard field types.
45     static final byte
46         ERAS = 1,
47         CENTURIES = 2,
48         WEEKYEARS = 3,
49         YEARS = 4,
50         MONTHS = 5,
51         WEEKS = 6,
52         DAYS = 7,
53         HALFDAYS = 8,
54         HOURS = 9,
55         MINUTES = 10,
56         SECONDS = 11,
57         MILLIS = 12;
58
59     /** The eras field type. */
60     static final DurationFieldType ERAS_TYPE = new StandardDurationFieldType("eras", ERAS);
61     /** The centuries field type. */
62     static final DurationFieldType CENTURIES_TYPE = new StandardDurationFieldType("centuries", CENTURIES);
63     /** The weekyears field type. */
64     static final DurationFieldType WEEKYEARS_TYPE = new StandardDurationFieldType("weekyears", WEEKYEARS);
65     /** The years field type. */
66     static final DurationFieldType YEARS_TYPE = new StandardDurationFieldType("years", YEARS);
67     /** The months field type. */
68     static final DurationFieldType MONTHS_TYPE = new StandardDurationFieldType("months", MONTHS);
69     /** The weeks field type. */
70     static final DurationFieldType WEEKS_TYPE = new StandardDurationFieldType("weeks", WEEKS);
71     /** The days field type. */
72     static final DurationFieldType DAYS_TYPE = new StandardDurationFieldType("days", DAYS);
73     /** The halfdays field type. */
74     static final DurationFieldType HALFDAYS_TYPE = new StandardDurationFieldType("halfdays", HALFDAYS);
75     /** The hours field type. */
76     static final DurationFieldType HOURS_TYPE = new StandardDurationFieldType("hours", HOURS);
77     /** The minutes field type. */
78     static final DurationFieldType MINUTES_TYPE = new StandardDurationFieldType("minutes", MINUTES);
79     /** The seconds field type. */
80     static final DurationFieldType SECONDS_TYPE = new StandardDurationFieldType("seconds", SECONDS);
81     /** The millis field type. */
82     static final DurationFieldType MILLIS_TYPE = new StandardDurationFieldType("millis", MILLIS);
83
84     /** The name of the field type. */
85     private final String iName;
86
87     //-----------------------------------------------------------------------
88     /**
89      * Constructor.
90      * 
91      * @param name  the name to use, which by convention, are plural.
92      */

93     protected DurationFieldType(String name) {
94         super();
95         iName = name;
96     }
97
98     //-----------------------------------------------------------------------
99     /**
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 }
353