1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package java.text;
19 
20 import java.io.InvalidObjectException;
21 import java.util.Calendar;
22 import java.util.Date;
23 import java.util.Hashtable;
24 import java.util.Locale;
25 import java.util.TimeZone;
26 import libcore.icu.ICU;
27 import libcore.icu.LocaleData;
28 
29 /**
30  * Formats or parses dates and times.
31  *
32  * <p>This class provides factories for obtaining instances configured for a specific locale.
33  * The most common subclass is {@link SimpleDateFormat}.
34  *
35  * <h4>Sample Code</h4>
36  * <p>This code:
37  * <pre>
38  * DateFormat[] formats = new DateFormat[] {
39  *   DateFormat.getDateInstance(),
40  *   DateFormat.getDateTimeInstance(),
41  *   DateFormat.getTimeInstance(),
42  * };
43  * for (DateFormat df : formats) {
44  *   System.out.println(df.format(new Date(0)));
45  *   df.setTimeZone(TimeZone.getTimeZone("UTC"));
46  *   System.out.println(df.format(new Date(0)));
47  * }
48  * </pre>
49  *
50  * <p>Produces this output when run on an {@code en_US} device in the America/Los_Angeles time zone:
51  * <pre>
52  * Dec 31, 1969
53  * Jan 1, 1970
54  * Dec 31, 1969 4:00:00 PM
55  * Jan 1, 1970 12:00:00 AM
56  * 4:00:00 PM
57  * 12:00:00 AM
58  * </pre>
59  * And will produce similarly appropriate localized human-readable output on any user's system.
60  * Notice how the same point in time when formatted can appear to be a different time when rendered
61  * for a different time zone. This is one reason why formatting should be left until the data will
62  * only be presented to a human. Machines should interchange "Unix time" integers.
63  */
64 public abstract class DateFormat extends Format {
65 
66     private static final long serialVersionUID = 7218322306649953788L;
67 
68     /**
69      * A tri-state boolean. If we're running stand-alone this will be null.
70      * If we're running in an app, the frameworks will have told us the user preference.
71      * @hide
72      */
73     public static Boolean is24Hour;
74 
75     /**
76      * The calendar that this {@code DateFormat} uses to format a number
77      * representing a date.
78      */
79     protected Calendar calendar;
80 
81     /**
82      * The number format used to format a number.
83      */
84     protected NumberFormat numberFormat;
85 
86     /**
87      * The format style constant defining the default format style. The default
88      * is MEDIUM.
89      */
90     public static final int DEFAULT = 2;
91 
92     /**
93      * The format style constant defining the full style.
94      */
95     public static final int FULL = 0;
96 
97     /**
98      * The format style constant defining the long style.
99      */
100     public static final int LONG = 1;
101 
102     /**
103      * The format style constant defining the medium style.
104      */
105     public static final int MEDIUM = 2;
106 
107     /**
108      * The format style constant defining the short style.
109      */
110     public static final int SHORT = 3;
111 
112     /**
113      * The {@code FieldPosition} selector for 'G' field alignment, corresponds
114      * to the {@link Calendar#ERA} field.
115      */
116     public static final int ERA_FIELD = 0;
117 
118     /**
119      * The {@code FieldPosition} selector for 'y' field alignment, corresponds
120      * to the {@link Calendar#YEAR} field.
121      */
122     public static final int YEAR_FIELD = 1;
123 
124     /**
125      * The {@code FieldPosition} selector for 'M' field alignment, corresponds
126      * to the {@link Calendar#MONTH} field.
127      */
128     public static final int MONTH_FIELD = 2;
129 
130     /**
131      * The {@code FieldPosition} selector for 'd' field alignment, corresponds
132      * to the {@link Calendar#DATE} field.
133      */
134     public static final int DATE_FIELD = 3;
135 
136     /**
137      * The {@code FieldPosition} selector for 'k' field alignment, corresponds
138      * to the {@link Calendar#HOUR_OF_DAY} field. {@code HOUR_OF_DAY1_FIELD} is
139      * used for the one-based 24-hour clock. For example, 23:59 + 01:00 results
140      * in 24:59.
141      */
142     public static final int HOUR_OF_DAY1_FIELD = 4;
143 
144     /**
145      * The {@code FieldPosition} selector for 'H' field alignment, corresponds
146      * to the {@link Calendar#HOUR_OF_DAY} field. {@code HOUR_OF_DAY0_FIELD} is
147      * used for the zero-based 24-hour clock. For example, 23:59 + 01:00 results
148      * in 00:59.
149      */
150     public static final int HOUR_OF_DAY0_FIELD = 5;
151 
152     /**
153      * FieldPosition selector for 'm' field alignment, corresponds to the
154      * {@link Calendar#MINUTE} field.
155      */
156     public static final int MINUTE_FIELD = 6;
157 
158     /**
159      * FieldPosition selector for 's' field alignment, corresponds to the
160      * {@link Calendar#SECOND} field.
161      */
162     public static final int SECOND_FIELD = 7;
163 
164     /**
165      * FieldPosition selector for 'S' field alignment, corresponds to the
166      * {@link Calendar#MILLISECOND} field.
167      */
168     public static final int MILLISECOND_FIELD = 8;
169 
170     /**
171      * FieldPosition selector for 'E' field alignment, corresponds to the
172      * {@link Calendar#DAY_OF_WEEK} field.
173      */
174     public static final int DAY_OF_WEEK_FIELD = 9;
175 
176     /**
177      * FieldPosition selector for 'D' field alignment, corresponds to the
178      * {@link Calendar#DAY_OF_YEAR} field.
179      */
180     public static final int DAY_OF_YEAR_FIELD = 10;
181 
182     /**
183      * FieldPosition selector for 'F' field alignment, corresponds to the
184      * {@link Calendar#DAY_OF_WEEK_IN_MONTH} field.
185      */
186     public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
187 
188     /**
189      * FieldPosition selector for 'w' field alignment, corresponds to the
190      * {@link Calendar#WEEK_OF_YEAR} field.
191      */
192     public static final int WEEK_OF_YEAR_FIELD = 12;
193 
194     /**
195      * FieldPosition selector for 'W' field alignment, corresponds to the
196      * {@link Calendar#WEEK_OF_MONTH} field.
197      */
198     public static final int WEEK_OF_MONTH_FIELD = 13;
199 
200     /**
201      * FieldPosition selector for 'a' field alignment, corresponds to the
202      * {@link Calendar#AM_PM} field.
203      */
204     public static final int AM_PM_FIELD = 14;
205 
206     /**
207      * FieldPosition selector for 'h' field alignment, corresponding to the
208      * {@link Calendar#HOUR} field.
209      */
210     public static final int HOUR1_FIELD = 15;
211 
212     /**
213      * The {@code FieldPosition} selector for 'K' field alignment, corresponding to the
214      * {@link Calendar#HOUR} field.
215      */
216     public static final int HOUR0_FIELD = 16;
217 
218     /**
219      * The {@code FieldPosition} selector for 'z' field alignment, corresponds
220      * to the {@link Calendar#ZONE_OFFSET} and {@link Calendar#DST_OFFSET}
221      * fields.
222      */
223     public static final int TIMEZONE_FIELD = 17;
224 
225     /**
226      * Constructs a new instance of {@code DateFormat}.
227      */
DateFormat()228     protected DateFormat() {
229     }
230 
231     /**
232      * Returns a new instance of {@code DateFormat} with the same properties.
233      */
234     @Override
clone()235     public Object clone() {
236         DateFormat clone = (DateFormat) super.clone();
237         clone.calendar = (Calendar) calendar.clone();
238         clone.numberFormat = (NumberFormat) numberFormat.clone();
239         return clone;
240     }
241 
242     /**
243      * Compares this date format with the specified object and indicates if they
244      * are equal.
245      *
246      * @param object
247      *            the object to compare with this date format.
248      * @return {@code true} if {@code object} is a {@code DateFormat} object and
249      *         it has the same properties as this date format; {@code false}
250      *         otherwise.
251      * @see #hashCode
252      */
253     @Override
equals(Object object)254     public boolean equals(Object object) {
255         if (this == object) {
256             return true;
257         }
258         if (!(object instanceof DateFormat)) {
259             return false;
260         }
261         DateFormat dateFormat = (DateFormat) object;
262         return numberFormat.equals(dateFormat.numberFormat)
263                 && calendar.getTimeZone().equals(
264                         dateFormat.calendar.getTimeZone())
265                 && calendar.getFirstDayOfWeek() == dateFormat.calendar
266                         .getFirstDayOfWeek()
267                 && calendar.getMinimalDaysInFirstWeek() == dateFormat.calendar
268                         .getMinimalDaysInFirstWeek()
269                 && calendar.isLenient() == dateFormat.calendar.isLenient();
270     }
271 
272     /**
273      * Formats the specified object as a string using the pattern of this date
274      * format and appends the string to the specified string buffer.
275      * <p>
276      * If the {@code field} member of {@code field} contains a value specifying
277      * a format field, then its {@code beginIndex} and {@code endIndex} members
278      * will be updated with the position of the first occurrence of this field
279      * in the formatted text.
280      *
281      * @param object
282      *            the source object to format, must be a {@code Date} or a
283      *            {@code Number}. If {@code object} is a number then a date is
284      *            constructed using the {@code longValue()} of the number.
285      * @param buffer
286      *            the target string buffer to append the formatted date/time to.
287      * @param field
288      *            on input: an optional alignment field; on output: the offsets
289      *            of the alignment field in the formatted text.
290      * @return the string buffer.
291      * @throws IllegalArgumentException
292      *            if {@code object} is neither a {@code Date} nor a
293      *            {@code Number} instance.
294      */
295     @Override
format(Object object, StringBuffer buffer, FieldPosition field)296     public final StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) {
297         if (object instanceof Date) {
298             return format((Date) object, buffer, field);
299         }
300         if (object instanceof Number) {
301             return format(new Date(((Number) object).longValue()), buffer, field);
302         }
303         throw new IllegalArgumentException("Bad class: " + object.getClass());
304     }
305 
306     /**
307      * Formats the specified date using the rules of this date format.
308      *
309      * @param date
310      *            the date to format.
311      * @return the formatted string.
312      */
format(Date date)313     public final String format(Date date) {
314         return format(date, new StringBuffer(), new FieldPosition(0)).toString();
315     }
316 
317     /**
318      * Formats the specified date as a string using the pattern of this date
319      * format and appends the string to the specified string buffer.
320      * <p>
321      * If the {@code field} member of {@code field} contains a value specifying
322      * a format field, then its {@code beginIndex} and {@code endIndex} members
323      * will be updated with the position of the first occurrence of this field
324      * in the formatted text.
325      *
326      * @param date
327      *            the date to format.
328      * @param buffer
329      *            the target string buffer to append the formatted date/time to.
330      * @param field
331      *            on input: an optional alignment field; on output: the offsets
332      *            of the alignment field in the formatted text.
333      * @return the string buffer.
334      */
format(Date date, StringBuffer buffer, FieldPosition field)335     public abstract StringBuffer format(Date date, StringBuffer buffer, FieldPosition field);
336 
337     /**
338      * Returns an array of locales for which custom {@code DateFormat} instances
339      * are available.
340      * <p>Note that Android does not support user-supplied locale service providers.
341      */
getAvailableLocales()342     public static Locale[] getAvailableLocales() {
343         return ICU.getAvailableDateFormatLocales();
344     }
345 
346     /**
347      * Returns the calendar used by this {@code DateFormat}.
348      *
349      * @return the calendar used by this date format.
350      */
getCalendar()351     public Calendar getCalendar() {
352         return calendar;
353     }
354 
355     /**
356      * Returns a {@code DateFormat} instance for formatting and parsing dates in
357      * the DEFAULT style for the default locale.
358      *
359      * @return the {@code DateFormat} instance for the default style and locale.
360      */
getDateInstance()361     public static final DateFormat getDateInstance() {
362         return getDateInstance(DEFAULT);
363     }
364 
365     /**
366      * Returns a {@code DateFormat} instance for formatting and parsing dates in
367      * the specified style for the user's default locale.
368      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
369      * @param style
370      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
371      * @return the {@code DateFormat} instance for {@code style} and the default
372      *         locale.
373      * @throws IllegalArgumentException
374      *             if {@code style} is not one of SHORT, MEDIUM, LONG, FULL, or
375      *             DEFAULT.
376      */
getDateInstance(int style)377     public static final DateFormat getDateInstance(int style) {
378         checkDateStyle(style);
379         return getDateInstance(style, Locale.getDefault());
380     }
381 
382     /**
383      * Returns a {@code DateFormat} instance for formatting and parsing dates in
384      * the specified style for the specified locale.
385      *
386      * @param style
387      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
388      * @param locale
389      *            the locale.
390      * @throws IllegalArgumentException
391      *             if {@code style} is not one of SHORT, MEDIUM, LONG, FULL, or
392      *             DEFAULT.
393      * @return the {@code DateFormat} instance for {@code style} and
394      *         {@code locale}.
395      */
getDateInstance(int style, Locale locale)396     public static final DateFormat getDateInstance(int style, Locale locale) {
397         checkDateStyle(style);
398         if (locale == null) {
399             throw new NullPointerException("locale == null");
400         }
401         return new SimpleDateFormat(LocaleData.get(locale).getDateFormat(style), locale);
402     }
403 
404     /**
405      * Returns a {@code DateFormat} instance for formatting and parsing dates
406      * and time values in the DEFAULT style for the default locale.
407      *
408      * @return the {@code DateFormat} instance for the default style and locale.
409      */
getDateTimeInstance()410     public static final DateFormat getDateTimeInstance() {
411         return getDateTimeInstance(DEFAULT, DEFAULT);
412     }
413 
414     /**
415      * Returns a {@code DateFormat} instance for formatting and parsing of both
416      * dates and time values in the manner appropriate for the user's default locale.
417      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
418      * @param dateStyle
419      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
420      * @param timeStyle
421      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
422      * @return the {@code DateFormat} instance for {@code dateStyle},
423      *         {@code timeStyle} and the default locale.
424      * @throws IllegalArgumentException
425      *             if {@code dateStyle} or {@code timeStyle} is not one of
426      *             SHORT, MEDIUM, LONG, FULL, or DEFAULT.
427      */
getDateTimeInstance(int dateStyle, int timeStyle)428     public static final DateFormat getDateTimeInstance(int dateStyle, int timeStyle) {
429         checkTimeStyle(timeStyle);
430         checkDateStyle(dateStyle);
431         return getDateTimeInstance(dateStyle, timeStyle, Locale.getDefault());
432     }
433 
434     /**
435      * Returns a {@code DateFormat} instance for formatting and parsing dates
436      * and time values in the specified styles for the specified locale.
437      *
438      * @param dateStyle
439      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
440      * @param timeStyle
441      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
442      * @param locale
443      *            the locale.
444      * @return the {@code DateFormat} instance for {@code dateStyle},
445      *         {@code timeStyle} and {@code locale}.
446      * @throws IllegalArgumentException
447      *             if {@code dateStyle} or {@code timeStyle} is not one of
448      *             SHORT, MEDIUM, LONG, FULL, or DEFAULT.
449      */
getDateTimeInstance(int dateStyle, int timeStyle, Locale locale)450     public static final DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) {
451         checkTimeStyle(timeStyle);
452         checkDateStyle(dateStyle);
453         if (locale == null) {
454             throw new NullPointerException("locale == null");
455         }
456         LocaleData localeData = LocaleData.get(locale);
457         String pattern = localeData.getDateFormat(dateStyle) + " " + localeData.getTimeFormat(timeStyle);
458         return new SimpleDateFormat(pattern, locale);
459     }
460 
461     /**
462      * Returns a {@code DateFormat} instance for formatting and parsing dates
463      * and times in the SHORT style for the default locale.
464      *
465      * @return the {@code DateFormat} instance for the SHORT style and default
466      *         locale.
467      */
getInstance()468     public static final DateFormat getInstance() {
469         return getDateTimeInstance(SHORT, SHORT);
470     }
471 
472     /**
473      * @hide for internal use only.
474      */
set24HourTimePref(boolean is24Hour)475     public static final void set24HourTimePref(boolean is24Hour) {
476         DateFormat.is24Hour = is24Hour;
477     }
478 
479     /**
480      * Returns the {@code NumberFormat} used by this {@code DateFormat}.
481      *
482      * @return the {@code NumberFormat} used by this date format.
483      */
getNumberFormat()484     public NumberFormat getNumberFormat() {
485         return numberFormat;
486     }
487 
488     /**
489      * Returns a {@code DateFormat} instance for formatting and parsing time
490      * values in the DEFAULT style for the default locale.
491      *
492      * @return the {@code DateFormat} instance for the default style and locale.
493      */
getTimeInstance()494     public static final DateFormat getTimeInstance() {
495         return getTimeInstance(DEFAULT);
496     }
497 
498     /**
499      * Returns a {@code DateFormat} instance for formatting and parsing time
500      * values in the specified style for the user's default locale.
501      * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
502      * @param style
503      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
504      * @return the {@code DateFormat} instance for {@code style} and the default
505      *         locale.
506      * @throws IllegalArgumentException
507      *             if {@code style} is not one of SHORT, MEDIUM, LONG, FULL, or
508      *             DEFAULT.
509      */
getTimeInstance(int style)510     public static final DateFormat getTimeInstance(int style) {
511         checkTimeStyle(style);
512         return getTimeInstance(style, Locale.getDefault());
513     }
514 
515     /**
516      * Returns a {@code DateFormat} instance for formatting and parsing time
517      * values in the specified style for the specified locale.
518      *
519      * @param style
520      *            one of SHORT, MEDIUM, LONG, FULL, or DEFAULT.
521      * @param locale
522      *            the locale.
523      * @throws IllegalArgumentException
524      *             if {@code style} is not one of SHORT, MEDIUM, LONG, FULL, or
525      *             DEFAULT.
526      * @return the {@code DateFormat} instance for {@code style} and
527      *         {@code locale}.
528      */
getTimeInstance(int style, Locale locale)529     public static final DateFormat getTimeInstance(int style, Locale locale) {
530         checkTimeStyle(style);
531         if (locale == null) {
532             throw new NullPointerException("locale == null");
533         }
534 
535         return new SimpleDateFormat(LocaleData.get(locale).getTimeFormat(style), locale);
536     }
537 
538     /**
539      * Returns the time zone of this date format's calendar.
540      *
541      * @return the time zone of the calendar used by this date format.
542      */
getTimeZone()543     public TimeZone getTimeZone() {
544         return calendar.getTimeZone();
545     }
546 
547     @Override
hashCode()548     public int hashCode() {
549         return calendar.getFirstDayOfWeek()
550                 + calendar.getMinimalDaysInFirstWeek()
551                 + calendar.getTimeZone().hashCode()
552                 + (calendar.isLenient() ? 1231 : 1237)
553                 + numberFormat.hashCode();
554     }
555 
556     /**
557      * Indicates whether the calendar used by this date format is lenient.
558      *
559      * @return {@code true} if the calendar is lenient; {@code false} otherwise.
560      */
isLenient()561     public boolean isLenient() {
562         return calendar.isLenient();
563     }
564 
565     /**
566      * Parses a date from the specified string using the rules of this date
567      * format.
568      *
569      * @param string
570      *            the string to parse.
571      * @return the {@code Date} resulting from the parsing.
572      * @throws ParseException
573      *         if an error occurs during parsing.
574      */
parse(String string)575     public Date parse(String string) throws ParseException {
576         ParsePosition position = new ParsePosition(0);
577         Date date = parse(string, position);
578         if (position.getIndex() == 0) {
579             throw new ParseException("Unparseable date: \"" + string + "\"",
580                     position.getErrorIndex());
581         }
582         return date;
583     }
584 
585     /**
586      * Parses a date from the specified string starting at the index specified
587      * by {@code position}. If the string is successfully parsed then the index
588      * of the {@code ParsePosition} is updated to the index following the parsed
589      * text. On error, the index is unchanged and the error index of {@code
590      * ParsePosition} is set to the index where the error occurred.
591      * <p>
592      * By default, parsing is lenient: If the input is not in the form used by
593      * this object's format method but can still be parsed as a date, then the
594      * parse succeeds. Clients may insist on strict adherence to the format by
595      * calling {@code setLenient(false)}.
596      *
597      * @param string
598      *            the string to parse.
599      * @param position
600      *            input/output parameter, specifies the start index in {@code
601      *            string} from where to start parsing. If parsing is successful,
602      *            it is updated with the index following the parsed text; on
603      *            error, the index is unchanged and the error index is set to
604      *            the index where the error occurred.
605      * @return the date resulting from the parse, or {@code null} if there is an
606      *         error.
607      */
parse(String string, ParsePosition position)608     public abstract Date parse(String string, ParsePosition position);
609 
610     /**
611      * Parses a date from the specified string starting at the index specified
612      * by {@code position}. If the string is successfully parsed then the index
613      * of the {@code ParsePosition} is updated to the index following the parsed
614      * text. On error, the index is unchanged and the error index of
615      * {@code ParsePosition} is set to the index where the error occurred.
616      * <p>
617      * By default, parsing is lenient: If the input is not in the form used by
618      * this object's format method but can still be parsed as a date, then the
619      * parse succeeds. Clients may insist on strict adherence to the format by
620      * calling {@code setLenient(false)}.
621      *
622      * @param string
623      *            the string to parse.
624      * @param position
625      *            input/output parameter, specifies the start index in
626      *            {@code string} from where to start parsing. If parsing is
627      *            successful, it is updated with the index following the parsed
628      *            text; on error, the index is unchanged and the error index
629      *            is set to the index where the error occurred.
630      * @return the date resulting from the parsing, or {@code null} if there is
631      *         an error.
632      */
633     @Override
parseObject(String string, ParsePosition position)634     public Object parseObject(String string, ParsePosition position) {
635         return parse(string, position);
636     }
637 
638     /**
639      * Sets the calendar used by this date format.
640      *
641      * @param cal
642      *            the new calendar.
643      */
setCalendar(Calendar cal)644     public void setCalendar(Calendar cal) {
645         calendar = cal;
646     }
647 
648     /**
649      * Specifies whether or not date/time parsing shall be lenient. With lenient
650      * parsing, the parser may use heuristics to interpret inputs that do not
651      * precisely match this object's format. With strict parsing, inputs must
652      * match this object's format.
653      *
654      * @param value
655      *            {@code true} to set the calendar to be lenient, {@code false}
656      *            otherwise.
657      */
setLenient(boolean value)658     public void setLenient(boolean value) {
659         calendar.setLenient(value);
660     }
661 
662     /**
663      * Sets the {@code NumberFormat} used by this date format.
664      *
665      * @param format
666      *            the new number format.
667      */
setNumberFormat(NumberFormat format)668     public void setNumberFormat(NumberFormat format) {
669         numberFormat = format;
670     }
671 
672     /**
673      * Sets the time zone of the calendar used by this date format.
674      *
675      * @param timezone
676      *            the new time zone.
677      */
setTimeZone(TimeZone timezone)678     public void setTimeZone(TimeZone timezone) {
679         calendar.setTimeZone(timezone);
680     }
681 
682     /**
683      * The instances of this inner class are used as attribute keys and values
684      * in {@code AttributedCharacterIterator} that the
685      * {@link SimpleDateFormat#formatToCharacterIterator(Object)} method returns.
686      * <p>
687      * There is no public constructor in this class, the only instances are the
688      * constants defined here.
689      */
690     public static class Field extends Format.Field {
691 
692         private static final long serialVersionUID = 7441350119349544720L;
693 
694         private static Hashtable<Integer, Field> table = new Hashtable<Integer, Field>();
695 
696         /**
697          * Marks the era part of a date.
698          */
699         public static final Field ERA = new Field("era", Calendar.ERA);
700 
701         /**
702          * Marks the year part of a date.
703          */
704         public static final Field YEAR = new Field("year", Calendar.YEAR);
705 
706         /**
707          * Marks the month part of a date.
708          */
709         public static final Field MONTH = new Field("month", Calendar.MONTH);
710 
711         /**
712          * Marks the hour of the day part of a date (0-11).
713          */
714         public static final Field HOUR_OF_DAY0 = new Field("hour of day", Calendar.HOUR_OF_DAY);
715 
716         /**
717          * Marks the hour of the day part of a date (1-12).
718          */
719         public static final Field HOUR_OF_DAY1 = new Field("hour of day 1", -1);
720 
721         /**
722          * Marks the minute part of a time.
723          */
724         public static final Field MINUTE = new Field("minute", Calendar.MINUTE);
725 
726         /**
727          * Marks the second part of a time.
728          */
729         public static final Field SECOND = new Field("second", Calendar.SECOND);
730 
731         /**
732          * Marks the millisecond part of a time.
733          */
734         public static final Field MILLISECOND = new Field("millisecond", Calendar.MILLISECOND);
735 
736         /**
737          * Marks the day of the week part of a date.
738          */
739         public static final Field DAY_OF_WEEK = new Field("day of week", Calendar.DAY_OF_WEEK);
740 
741         /**
742          * Marks the day of the month part of a date.
743          */
744         public static final Field DAY_OF_MONTH = new Field("day of month", Calendar.DAY_OF_MONTH);
745 
746         /**
747          * Marks the day of the year part of a date.
748          */
749         public static final Field DAY_OF_YEAR = new Field("day of year", Calendar.DAY_OF_YEAR);
750 
751         /**
752          * Marks the day of the week in the month part of a date.
753          */
754         public static final Field DAY_OF_WEEK_IN_MONTH = new Field("day of week in month",
755                 Calendar.DAY_OF_WEEK_IN_MONTH);
756 
757         /**
758          * Marks the week of the year part of a date.
759          */
760         public static final Field WEEK_OF_YEAR = new Field("week of year",
761                 Calendar.WEEK_OF_YEAR);
762 
763         /**
764          * Marks the week of the month part of a date.
765          */
766         public static final Field WEEK_OF_MONTH = new Field("week of month",
767                 Calendar.WEEK_OF_MONTH);
768 
769         /**
770          * Marks the time indicator part of a date.
771          */
772         public static final Field AM_PM = new Field("am pm", Calendar.AM_PM);
773 
774         /**
775          * Marks the hour part of a date (0-11).
776          */
777         public static final Field HOUR0 = new Field("hour", Calendar.HOUR);
778 
779         /**
780          * Marks the hour part of a date (1-12).
781          */
782         public static final Field HOUR1 = new Field("hour 1", -1);
783 
784         /**
785          * Marks the time zone part of a date.
786          */
787         public static final Field TIME_ZONE = new Field("time zone", -1);
788 
789         /**
790          * The calendar field that this field represents.
791          */
792         private int calendarField = -1;
793 
794         /**
795          * Constructs a new instance of {@code DateFormat.Field} with the given
796          * fieldName and calendar field.
797          *
798          * @param fieldName
799          *            the field name.
800          * @param calendarField
801          *            the calendar field type of the field.
802          */
Field(String fieldName, int calendarField)803         protected Field(String fieldName, int calendarField) {
804             super(fieldName);
805             this.calendarField = calendarField;
806             if (calendarField != -1 && table.get(Integer.valueOf(calendarField)) == null) {
807                 table.put(Integer.valueOf(calendarField), this);
808             }
809         }
810 
811         /**
812          * Returns the Calendar field that this field represents.
813          *
814          * @return the calendar field.
815          */
getCalendarField()816         public int getCalendarField() {
817             return calendarField;
818         }
819 
820         /**
821          * Returns the {@code DateFormat.Field} instance for the given calendar
822          * field.
823          *
824          * @param calendarField
825          *            a calendar field constant.
826          * @return the {@code DateFormat.Field} corresponding to
827          *         {@code calendarField}.
828          * @throws IllegalArgumentException
829          *             if {@code calendarField} is negative or greater than the
830          *             field count of {@code Calendar}.
831          */
ofCalendarField(int calendarField)832         public static Field ofCalendarField(int calendarField) {
833             if (calendarField < 0 || calendarField >= Calendar.FIELD_COUNT) {
834                 throw new IllegalArgumentException("Field out of range: " + calendarField);
835             }
836             return table.get(Integer.valueOf(calendarField));
837         }
838     }
839 
checkDateStyle(int style)840     private static void checkDateStyle(int style) {
841         if (!(style == SHORT || style == MEDIUM || style == LONG
842                 || style == FULL || style == DEFAULT)) {
843             throw new IllegalArgumentException("Illegal date style: " + style);
844         }
845     }
846 
checkTimeStyle(int style)847     private static void checkTimeStyle(int style) {
848         if (!(style == SHORT || style == MEDIUM || style == LONG
849                 || style == FULL || style == DEFAULT)) {
850             throw new IllegalArgumentException("Illegal time style: " + style);
851         }
852     }
853 }
854