1 /*
2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /*
27 * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28 * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29 *
30 * The original version of this source code and documentation is copyrighted
31 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32 * materials are provided under terms of a License Agreement between Taligent
33 * and Sun. This technology is protected by multiple US and International
34 * patents. This notice and attribution to Taligent may not be removed.
35 * Taligent is a registered trademark of Taligent, Inc.
36 *
37 */
38
39 package java.text;
40
41 import java.io.InvalidObjectException;
42 import java.text.spi.DateFormatProvider;
43 import java.util.Calendar;
44 import java.util.Date;
45 import java.util.GregorianCalendar;
46 import java.util.HashMap;
47 import java.util.Locale;
48 import java.util.Map;
49 import java.util.MissingResourceException;
50 import java.util.ResourceBundle;
51 import java.util.TimeZone;
52 import java.util.spi.LocaleServiceProvider;
53 import sun.util.locale.provider.LocaleProviderAdapter;
54 import sun.util.locale.provider.LocaleServiceProviderPool;
55
56 /**
57 * {@code DateFormat} is an abstract class for date/time formatting subclasses which
58 * formats and parses dates or time in a language-independent manner.
59 * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
60 * formatting (i.e., date → text), parsing (text → date), and
61 * normalization. The date is represented as a <code>Date</code> object or
62 * as the milliseconds since January 1, 1970, 00:00:00 GMT.
63 *
64 * <p>{@code DateFormat} provides many class methods for obtaining default date/time
65 * formatters based on the default or a given locale and a number of formatting
66 * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
67 * detail and examples of using these styles are provided in the method
68 * descriptions.
69 *
70 * <p>{@code DateFormat} helps you to format and parse dates for any locale.
71 * Your code can be completely independent of the locale conventions for
72 * months, days of the week, or even the calendar format: lunar vs. solar.
73 *
74 * <p>To format a date for the current Locale, use one of the
75 * static factory methods:
76 * <blockquote>
77 * <pre>{@code
78 * myString = DateFormat.getDateInstance().format(myDate);
79 * }</pre>
80 * </blockquote>
81 * <p>If you are formatting multiple dates, it is
82 * more efficient to get the format and use it multiple times so that
83 * the system doesn't have to fetch the information about the local
84 * language and country conventions multiple times.
85 * <blockquote>
86 * <pre>{@code
87 * DateFormat df = DateFormat.getDateInstance();
88 * for (int i = 0; i < myDate.length; ++i) {
89 * output.println(df.format(myDate[i]) + "; ");
90 * }
91 * }</pre>
92 * </blockquote>
93 * <p>To format a date for a different Locale, specify it in the
94 * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
95 * <blockquote>
96 * <pre>{@code
97 * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
98 * }</pre>
99 * </blockquote>
100 *
101 * <p>If the specified locale contains "ca" (calendar), "rg" (region override),
102 * and/or "tz" (timezone) <a href="../util/Locale.html#def_locale_extension">Unicode
103 * extensions</a>, the calendar, the country and/or the time zone for formatting
104 * are overridden. If both "ca" and "rg" are specified, the calendar from the "ca"
105 * extension supersedes the implicit one from the "rg" extension.
106 *
107 * <p>You can use a DateFormat to parse also.
108 * <blockquote>
109 * <pre>{@code
110 * myDate = df.parse(myString);
111 * }</pre>
112 * </blockquote>
113 * <p>Use {@code getDateInstance} to get the normal date format for that country.
114 * There are other static factory methods available.
115 * Use {@code getTimeInstance} to get the time format for that country.
116 * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
117 * different options to these factory methods to control the length of the
118 * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
119 * on the locale, but generally:
120 * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
121 * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
122 * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
123 * <li>{@link #FULL} is pretty completely specified, such as
124 * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
125 * </ul>
126 *
127 * <p>You can also set the time zone on the format if you wish.
128 * If you want even more control over the format or parsing,
129 * (or want to give your users more control),
130 * you can try casting the {@code DateFormat} you get from the factory methods
131 * to a {@link SimpleDateFormat}. This will work for the majority
132 * of countries; just remember to put it in a {@code try} block in case you
133 * encounter an unusual one.
134 *
135 * <p>You can also use forms of the parse and format methods with
136 * {@link ParsePosition} and {@link FieldPosition} to
137 * allow you to
138 * <ul><li>progressively parse through pieces of a string.
139 * <li>align any particular field, or find out where it is for selection
140 * on the screen.
141 * </ul>
142 *
143 * <h3><a id="synchronization">Synchronization</a></h3>
144 *
145 * <p>
146 * Date formats are not synchronized.
147 * It is recommended to create separate format instances for each thread.
148 * If multiple threads access a format concurrently, it must be synchronized
149 * externally.
150 *
151 * @implSpec
152 * <ul><li>The {@link #format(Date, StringBuffer, FieldPosition)} and
153 * {@link #parse(String, ParsePosition)} methods may throw
154 * {@code NullPointerException}, if any of their parameter is {@code null}.
155 * The subclass may provide its own implementation and specification about
156 * {@code NullPointerException}.</li>
157 * <li>The {@link #setCalendar(Calendar)}, {@link
158 * #setNumberFormat(NumberFormat)} and {@link #setTimeZone(TimeZone)} methods
159 * do not throw {@code NullPointerException} when their parameter is
160 * {@code null}, but any subsequent operations on the same instance may throw
161 * {@code NullPointerException}.</li>
162 * <li>The {@link #getCalendar()}, {@link #getNumberFormat()} and
163 * {@link getTimeZone()} methods may return {@code null}, if the respective
164 * values of this instance is set to {@code null} through the corresponding
165 * setter methods. For Example: {@link #getTimeZone()} may return {@code null},
166 * if the {@code TimeZone} value of this instance is set as
167 * {@link #setTimeZone(java.util.TimeZone) setTimeZone(null)}.</li>
168 * </ul>
169 *
170 * @see Format
171 * @see NumberFormat
172 * @see SimpleDateFormat
173 * @see java.util.Calendar
174 * @see java.util.GregorianCalendar
175 * @see java.util.TimeZone
176 * @author Mark Davis, Chen-Lieh Huang, Alan Liu
177 * @since 1.1
178 */
179 public abstract class DateFormat extends Format {
180
181 /**
182 * The {@link Calendar} instance used for calculating the date-time fields
183 * and the instant of time. This field is used for both formatting and
184 * parsing.
185 *
186 * <p>Subclasses should initialize this field to a {@link Calendar}
187 * appropriate for the {@link Locale} associated with this
188 * <code>DateFormat</code>.
189 * @serial
190 */
191 protected Calendar calendar;
192
193 /**
194 * The number formatter that <code>DateFormat</code> uses to format numbers
195 * in dates and times. Subclasses should initialize this to a number format
196 * appropriate for the locale associated with this <code>DateFormat</code>.
197 * @serial
198 */
199 protected NumberFormat numberFormat;
200
201 /**
202 * Useful constant for ERA field alignment.
203 * Used in FieldPosition of date/time formatting.
204 */
205 public static final int ERA_FIELD = 0;
206 /**
207 * Useful constant for YEAR field alignment.
208 * Used in FieldPosition of date/time formatting.
209 */
210 public static final int YEAR_FIELD = 1;
211 /**
212 * Useful constant for MONTH field alignment.
213 * Used in FieldPosition of date/time formatting.
214 */
215 public static final int MONTH_FIELD = 2;
216 /**
217 * Useful constant for DATE field alignment.
218 * Used in FieldPosition of date/time formatting.
219 */
220 public static final int DATE_FIELD = 3;
221 /**
222 * Useful constant for one-based HOUR_OF_DAY field alignment.
223 * Used in FieldPosition of date/time formatting.
224 * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
225 * For example, 23:59 + 01:00 results in 24:59.
226 */
227 public static final int HOUR_OF_DAY1_FIELD = 4;
228 /**
229 * Useful constant for zero-based HOUR_OF_DAY field alignment.
230 * Used in FieldPosition of date/time formatting.
231 * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
232 * For example, 23:59 + 01:00 results in 00:59.
233 */
234 public static final int HOUR_OF_DAY0_FIELD = 5;
235 /**
236 * Useful constant for MINUTE field alignment.
237 * Used in FieldPosition of date/time formatting.
238 */
239 public static final int MINUTE_FIELD = 6;
240 /**
241 * Useful constant for SECOND field alignment.
242 * Used in FieldPosition of date/time formatting.
243 */
244 public static final int SECOND_FIELD = 7;
245 /**
246 * Useful constant for MILLISECOND field alignment.
247 * Used in FieldPosition of date/time formatting.
248 */
249 public static final int MILLISECOND_FIELD = 8;
250 /**
251 * Useful constant for DAY_OF_WEEK field alignment.
252 * Used in FieldPosition of date/time formatting.
253 */
254 public static final int DAY_OF_WEEK_FIELD = 9;
255 /**
256 * Useful constant for DAY_OF_YEAR field alignment.
257 * Used in FieldPosition of date/time formatting.
258 */
259 public static final int DAY_OF_YEAR_FIELD = 10;
260 /**
261 * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
262 * Used in FieldPosition of date/time formatting.
263 */
264 public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
265 /**
266 * Useful constant for WEEK_OF_YEAR field alignment.
267 * Used in FieldPosition of date/time formatting.
268 */
269 public static final int WEEK_OF_YEAR_FIELD = 12;
270 /**
271 * Useful constant for WEEK_OF_MONTH field alignment.
272 * Used in FieldPosition of date/time formatting.
273 */
274 public static final int WEEK_OF_MONTH_FIELD = 13;
275 /**
276 * Useful constant for AM_PM field alignment.
277 * Used in FieldPosition of date/time formatting.
278 */
279 public static final int AM_PM_FIELD = 14;
280 /**
281 * Useful constant for one-based HOUR field alignment.
282 * Used in FieldPosition of date/time formatting.
283 * HOUR1_FIELD is used for the one-based 12-hour clock.
284 * For example, 11:30 PM + 1 hour results in 12:30 AM.
285 */
286 public static final int HOUR1_FIELD = 15;
287 /**
288 * Useful constant for zero-based HOUR field alignment.
289 * Used in FieldPosition of date/time formatting.
290 * HOUR0_FIELD is used for the zero-based 12-hour clock.
291 * For example, 11:30 PM + 1 hour results in 00:30 AM.
292 */
293 public static final int HOUR0_FIELD = 16;
294 /**
295 * Useful constant for TIMEZONE field alignment.
296 * Used in FieldPosition of date/time formatting.
297 */
298 public static final int TIMEZONE_FIELD = 17;
299
300 // Proclaim serial compatibility with 1.1 FCS
301 private static final long serialVersionUID = 7218322306649953788L;
302
303 /**
304 * Formats the given {@code Object} into a date-time string. The formatted
305 * string is appended to the given {@code StringBuffer}.
306 *
307 * @param obj Must be a {@code Date} or a {@code Number} representing a
308 * millisecond offset from the <a href="../util/Calendar.html#Epoch">Epoch</a>.
309 * @param toAppendTo The string buffer for the returning date-time string.
310 * @param fieldPosition keeps track on the position of the field within
311 * the returned string. For example, given a date-time text
312 * {@code "1996.07.10 AD at 15:08:56 PDT"}, if the given {@code fieldPosition}
313 * is {@link DateFormat#YEAR_FIELD}, the begin index and end index of
314 * {@code fieldPosition} will be set to 0 and 4, respectively.
315 * Notice that if the same date-time field appears more than once in a
316 * pattern, the {@code fieldPosition} will be set for the first occurrence
317 * of that date-time field. For instance, formatting a {@code Date} to the
318 * date-time string {@code "1 PM PDT (Pacific Daylight Time)"} using the
319 * pattern {@code "h a z (zzzz)"} and the alignment field
320 * {@link DateFormat#TIMEZONE_FIELD}, the begin index and end index of
321 * {@code fieldPosition} will be set to 5 and 8, respectively, for the
322 * first occurrence of the timezone pattern character {@code 'z'}.
323 * @return the string buffer passed in as {@code toAppendTo},
324 * with formatted text appended.
325 * @exception IllegalArgumentException if the {@code Format} cannot format
326 * the given {@code obj}.
327 * @see java.text.Format
328 */
329 public final StringBuffer format(Object obj, StringBuffer toAppendTo,
330 FieldPosition fieldPosition)
331 {
332 if (obj instanceof Date)
333 return format( (Date)obj, toAppendTo, fieldPosition );
334 else if (obj instanceof Number)
335 return format( new Date(((Number)obj).longValue()),
336 toAppendTo, fieldPosition );
337 else
338 throw new IllegalArgumentException("Cannot format given Object as a Date");
339 }
340
341 /**
342 * Formats a {@link Date} into a date-time string. The formatted
343 * string is appended to the given {@code StringBuffer}.
344 *
345 * @param date a Date to be formatted into a date-time string.
346 * @param toAppendTo the string buffer for the returning date-time string.
347 * @param fieldPosition keeps track on the position of the field within
348 * the returned string. For example, given a date-time text
349 * {@code "1996.07.10 AD at 15:08:56 PDT"}, if the given {@code fieldPosition}
350 * is {@link DateFormat#YEAR_FIELD}, the begin index and end index of
351 * {@code fieldPosition} will be set to 0 and 4, respectively.
352 * Notice that if the same date-time field appears more than once in a
353 * pattern, the {@code fieldPosition} will be set for the first occurrence
354 * of that date-time field. For instance, formatting a {@code Date} to the
355 * date-time string {@code "1 PM PDT (Pacific Daylight Time)"} using the
356 * pattern {@code "h a z (zzzz)"} and the alignment field
357 * {@link DateFormat#TIMEZONE_FIELD}, the begin index and end index of
358 * {@code fieldPosition} will be set to 5 and 8, respectively, for the
359 * first occurrence of the timezone pattern character {@code 'z'}.
360 * @return the string buffer passed in as {@code toAppendTo}, with formatted
361 * text appended.
362 */
363 public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
364 FieldPosition fieldPosition);
365
366 /**
367 * Formats a {@link Date} into a date-time string.
368 *
369 * @param date the time value to be formatted into a date-time string.
370 * @return the formatted date-time string.
371 */
372 public final String format(Date date)
373 {
374 return format(date, new StringBuffer(),
375 DontCareFieldPosition.INSTANCE).toString();
376 }
377
378 /**
379 * Parses text from the beginning of the given string to produce a date.
380 * The method may not use the entire text of the given string.
381 * <p>
382 * See the {@link #parse(String, ParsePosition)} method for more information
383 * on date parsing.
384 *
385 * @param source A <code>String</code> whose beginning should be parsed.
386 * @return A <code>Date</code> parsed from the string.
387 * @exception ParseException if the beginning of the specified string
388 * cannot be parsed.
389 */
390 public Date parse(String source) throws ParseException
391 {
392 ParsePosition pos = new ParsePosition(0);
393 Date result = parse(source, pos);
394 if (pos.index == 0)
395 throw new ParseException("Unparseable date: \"" + source + "\"" ,
396 pos.errorIndex);
397 return result;
398 }
399
400 /**
401 * Parse a date/time string according to the given parse position. For
402 * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
403 * that is equivalent to {@code Date(837039900000L)}.
404 *
405 * <p> By default, parsing is lenient: If the input is not in the form used
406 * by this object's format method but can still be parsed as a date, then
407 * the parse succeeds. Clients may insist on strict adherence to the
408 * format by calling {@link #setLenient(boolean) setLenient(false)}.
409 *
410 * <p>This parsing operation uses the {@link #calendar} to produce
411 * a {@code Date}. As a result, the {@code calendar}'s date-time
412 * fields and the {@code TimeZone} value may have been
413 * overwritten, depending on subclass implementations. Any {@code
414 * TimeZone} value that has previously been set by a call to
415 * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
416 * to be restored for further operations.
417 *
418 * @param source The date/time string to be parsed
419 *
420 * @param pos On input, the position at which to start parsing; on
421 * output, the position at which parsing terminated, or the
422 * start position if the parse failed.
423 *
424 * @return A {@code Date}, or {@code null} if the input could not be parsed
425 */
426 public abstract Date parse(String source, ParsePosition pos);
427
428 /**
429 * Parses text from a string to produce a <code>Date</code>.
430 * <p>
431 * The method attempts to parse text starting at the index given by
432 * <code>pos</code>.
433 * If parsing succeeds, then the index of <code>pos</code> is updated
434 * to the index after the last character used (parsing does not necessarily
435 * use all characters up to the end of the string), and the parsed
436 * date is returned. The updated <code>pos</code> can be used to
437 * indicate the starting point for the next call to this method.
438 * If an error occurs, then the index of <code>pos</code> is not
439 * changed, the error index of <code>pos</code> is set to the index of
440 * the character where the error occurred, and null is returned.
441 * <p>
442 * See the {@link #parse(String, ParsePosition)} method for more information
443 * on date parsing.
444 *
445 * @param source A <code>String</code>, part of which should be parsed.
446 * @param pos A <code>ParsePosition</code> object with index and error
447 * index information as described above.
448 * @return A <code>Date</code> parsed from the string. In case of
449 * error, returns null.
450 * @throws NullPointerException if {@code source} or {@code pos} is null.
451 */
452 public Object parseObject(String source, ParsePosition pos) {
453 return parse(source, pos);
454 }
455
456 /**
457 * Constant for full style pattern.
458 */
459 public static final int FULL = 0;
460 /**
461 * Constant for long style pattern.
462 */
463 public static final int LONG = 1;
464 /**
465 * Constant for medium style pattern.
466 */
467 public static final int MEDIUM = 2;
468 /**
469 * Constant for short style pattern.
470 */
471 public static final int SHORT = 3;
472 /**
473 * Constant for default style pattern. Its value is MEDIUM.
474 */
475 public static final int DEFAULT = MEDIUM;
476
477 /**
478 * Gets the time formatter with the default formatting style
479 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
480 * <p>This is equivalent to calling
481 * {@link #getTimeInstance(int, Locale) getTimeInstance(DEFAULT,
482 * Locale.getDefault(Locale.Category.FORMAT))}.
483 * @see java.util.Locale#getDefault(java.util.Locale.Category)
484 * @see java.util.Locale.Category#FORMAT
485 * @return a time formatter.
486 */
487 public static final DateFormat getTimeInstance()
488 {
489 return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
490 }
491
492 /**
493 * Gets the time formatter with the given formatting style
494 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
495 * <p>This is equivalent to calling
496 * {@link #getTimeInstance(int, Locale) getTimeInstance(style,
497 * Locale.getDefault(Locale.Category.FORMAT))}.
498 * @see java.util.Locale#getDefault(java.util.Locale.Category)
499 * @see java.util.Locale.Category#FORMAT
500 * @param style the given formatting style. For example,
501 * SHORT for "h:mm a" in the US locale.
502 * @return a time formatter.
503 */
504 public static final DateFormat getTimeInstance(int style)
505 {
506 return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
507 }
508
509 /**
510 * Gets the time formatter with the given formatting style
511 * for the given locale.
512 * @param style the given formatting style. For example,
513 * SHORT for "h:mm a" in the US locale.
514 * @param aLocale the given locale.
515 * @return a time formatter.
516 */
517 public static final DateFormat getTimeInstance(int style,
518 Locale aLocale)
519 {
520 return get(style, 0, 1, aLocale);
521 }
522
523 /**
524 * Gets the date formatter with the default formatting style
525 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
526 * <p>This is equivalent to calling
527 * {@link #getDateInstance(int, Locale) getDateInstance(DEFAULT,
528 * Locale.getDefault(Locale.Category.FORMAT))}.
529 * @see java.util.Locale#getDefault(java.util.Locale.Category)
530 * @see java.util.Locale.Category#FORMAT
531 * @return a date formatter.
532 */
533 public static final DateFormat getDateInstance()
534 {
535 return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
536 }
537
538 /**
539 * Gets the date formatter with the given formatting style
540 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
541 * <p>This is equivalent to calling
542 * {@link #getDateInstance(int, Locale) getDateInstance(style,
543 * Locale.getDefault(Locale.Category.FORMAT))}.
544 * @see java.util.Locale#getDefault(java.util.Locale.Category)
545 * @see java.util.Locale.Category#FORMAT
546 * @param style the given formatting style. For example,
547 * SHORT for "M/d/yy" in the US locale.
548 * @return a date formatter.
549 */
550 public static final DateFormat getDateInstance(int style)
551 {
552 return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
553 }
554
555 /**
556 * Gets the date formatter with the given formatting style
557 * for the given locale.
558 * @param style the given formatting style. For example,
559 * SHORT for "M/d/yy" in the US locale.
560 * @param aLocale the given locale.
561 * @return a date formatter.
562 */
563 public static final DateFormat getDateInstance(int style,
564 Locale aLocale)
565 {
566 return get(0, style, 2, aLocale);
567 }
568
569 /**
570 * Gets the date/time formatter with the default formatting style
571 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
572 * <p>This is equivalent to calling
573 * {@link #getDateTimeInstance(int, int, Locale) getDateTimeInstance(DEFAULT,
574 * DEFAULT, Locale.getDefault(Locale.Category.FORMAT))}.
575 * @see java.util.Locale#getDefault(java.util.Locale.Category)
576 * @see java.util.Locale.Category#FORMAT
577 * @return a date/time formatter.
578 */
579 public static final DateFormat getDateTimeInstance()
580 {
581 return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
582 }
583
584 /**
585 * Gets the date/time formatter with the given date and time
586 * formatting styles for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
587 * <p>This is equivalent to calling
588 * {@link #getDateTimeInstance(int, int, Locale) getDateTimeInstance(dateStyle,
589 * timeStyle, Locale.getDefault(Locale.Category.FORMAT))}.
590 * @see java.util.Locale#getDefault(java.util.Locale.Category)
591 * @see java.util.Locale.Category#FORMAT
592 * @param dateStyle the given date formatting style. For example,
593 * SHORT for "M/d/yy" in the US locale.
594 * @param timeStyle the given time formatting style. For example,
595 * SHORT for "h:mm a" in the US locale.
596 * @return a date/time formatter.
597 */
598 public static final DateFormat getDateTimeInstance(int dateStyle,
599 int timeStyle)
600 {
601 return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
602 }
603
604 /**
605 * Gets the date/time formatter with the given formatting styles
606 * for the given locale.
607 * @param dateStyle the given date formatting style.
608 * @param timeStyle the given time formatting style.
609 * @param aLocale the given locale.
610 * @return a date/time formatter.
611 */
612 public static final DateFormat
613 getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
614 {
615 return get(timeStyle, dateStyle, 3, aLocale);
616 }
617
618 /**
619 * Get a default date/time formatter that uses the SHORT style for both the
620 * date and the time.
621 *
622 * @return a date/time formatter
623 */
624 public static final DateFormat getInstance() {
625 return getDateTimeInstance(SHORT, SHORT);
626 }
627
628 /**
629 * Returns an array of all locales for which the
630 * <code>get*Instance</code> methods of this class can return
631 * localized instances.
632 * The returned array represents the union of locales supported by the Java
633 * runtime and by installed
634 * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
635 * It must contain at least a <code>Locale</code> instance equal to
636 * {@link java.util.Locale#US Locale.US}.
637 *
638 * @return An array of locales for which localized
639 * <code>DateFormat</code> instances are available.
640 */
641 public static Locale[] getAvailableLocales()
642 {
643 LocaleServiceProviderPool pool =
644 LocaleServiceProviderPool.getPool(DateFormatProvider.class);
645 return pool.getAvailableLocales();
646 }
647
648 /**
649 * Set the calendar to be used by this date format. Initially, the default
650 * calendar for the specified or default locale is used.
651 *
652 * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
653 * #isLenient() leniency} values that have previously been set are
654 * overwritten by {@code newCalendar}'s values.
655 *
656 * @param newCalendar the new {@code Calendar} to be used by the date format
657 */
658 public void setCalendar(Calendar newCalendar)
659 {
660 this.calendar = newCalendar;
661 }
662
663 /**
664 * Gets the calendar associated with this date/time formatter.
665 *
666 * @return the calendar associated with this date/time formatter.
667 */
668 public Calendar getCalendar()
669 {
670 return calendar;
671 }
672
673 /**
674 * Allows you to set the number formatter.
675 * @param newNumberFormat the given new NumberFormat.
676 */
677 public void setNumberFormat(NumberFormat newNumberFormat)
678 {
679 this.numberFormat = newNumberFormat;
680 }
681
682 /**
683 * Gets the number formatter which this date/time formatter uses to
684 * format and parse a time.
685 * @return the number formatter which this date/time formatter uses.
686 */
687 public NumberFormat getNumberFormat()
688 {
689 return numberFormat;
690 }
691
692 /**
693 * Sets the time zone for the calendar of this {@code DateFormat} object.
694 * This method is equivalent to the following call.
695 * <blockquote><pre>{@code
696 * getCalendar().setTimeZone(zone)
697 * }</pre></blockquote>
698 *
699 * <p>The {@code TimeZone} set by this method is overwritten by a
700 * {@link #setCalendar(java.util.Calendar) setCalendar} call.
701 *
702 * <p>The {@code TimeZone} set by this method may be overwritten as
703 * a result of a call to the parse method.
704 *
705 * @param zone the given new time zone.
706 */
707 public void setTimeZone(TimeZone zone)
708 {
709 calendar.setTimeZone(zone);
710 }
711
712 /**
713 * Gets the time zone.
714 * This method is equivalent to the following call.
715 * <blockquote><pre>{@code
716 * getCalendar().getTimeZone()
717 * }</pre></blockquote>
718 *
719 * @return the time zone associated with the calendar of DateFormat.
720 */
721 public TimeZone getTimeZone()
722 {
723 return calendar.getTimeZone();
724 }
725
726 /**
727 * Specify whether or not date/time parsing is to be lenient. With
728 * lenient parsing, the parser may use heuristics to interpret inputs that
729 * do not precisely match this object's format. With strict parsing,
730 * inputs must match this object's format.
731 *
732 * <p>This method is equivalent to the following call.
733 * <blockquote><pre>{@code
734 * getCalendar().setLenient(lenient)
735 * }</pre></blockquote>
736 *
737 * <p>This leniency value is overwritten by a call to {@link
738 * #setCalendar(java.util.Calendar) setCalendar()}.
739 *
740 * @param lenient when {@code true}, parsing is lenient
741 * @see java.util.Calendar#setLenient(boolean)
742 */
743 public void setLenient(boolean lenient)
744 {
745 calendar.setLenient(lenient);
746 }
747
748 /**
749 * Tell whether date/time parsing is to be lenient.
750 * This method is equivalent to the following call.
751 * <blockquote><pre>{@code
752 * getCalendar().isLenient()
753 * }</pre></blockquote>
754 *
755 * @return {@code true} if the {@link #calendar} is lenient;
756 * {@code false} otherwise.
757 * @see java.util.Calendar#isLenient()
758 */
759 public boolean isLenient()
760 {
761 return calendar.isLenient();
762 }
763
764 /**
765 * Overrides hashCode
766 */
767 public int hashCode() {
768 return numberFormat.hashCode();
769 // just enough fields for a reasonable distribution
770 }
771
772 /**
773 * Overrides equals
774 */
775 public boolean equals(Object obj) {
776 if (this == obj) return true;
777 if (obj == null || getClass() != obj.getClass()) return false;
778 DateFormat other = (DateFormat) obj;
779 return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
780 calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
781 calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
782 calendar.isLenient() == other.calendar.isLenient() &&
783 calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
784 numberFormat.equals(other.numberFormat));
785 }
786
787 /**
788 * Overrides Cloneable
789 */
790 public Object clone()
791 {
792 DateFormat other = (DateFormat) super.clone();
793 other.calendar = (Calendar) calendar.clone();
794 other.numberFormat = (NumberFormat) numberFormat.clone();
795 return other;
796 }
797
798 /**
799 * Creates a DateFormat with the given time and/or date style in the given
800 * locale.
801 * @param timeStyle a value from 0 to 3 indicating the time format,
802 * ignored if flags is 2
803 * @param dateStyle a value from 0 to 3 indicating the time format,
804 * ignored if flags is 1
805 * @param flags either 1 for a time format, 2 for a date format,
806 * or 3 for a date/time format
807 * @param loc the locale for the format
808 */
809 private static DateFormat get(int timeStyle, int dateStyle,
810 int flags, Locale loc) {
811 if ((flags & 1) != 0) {
812 if (timeStyle < 0 || timeStyle > 3) {
813 throw new IllegalArgumentException("Illegal time style " + timeStyle);
814 }
815 } else {
816 timeStyle = -1;
817 }
818 if ((flags & 2) != 0) {
819 if (dateStyle < 0 || dateStyle > 3) {
820 throw new IllegalArgumentException("Illegal date style " + dateStyle);
821 }
822 } else {
823 dateStyle = -1;
824 }
825
826 LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, loc);
827 DateFormat dateFormat = get(adapter, timeStyle, dateStyle, loc);
828 if (dateFormat == null) {
829 dateFormat = get(LocaleProviderAdapter.forJRE(), timeStyle, dateStyle, loc);
830 }
831 return dateFormat;
832 }
833
834 private static DateFormat get(LocaleProviderAdapter adapter, int timeStyle, int dateStyle, Locale loc) {
835 DateFormatProvider provider = adapter.getDateFormatProvider();
836 DateFormat dateFormat;
837 if (timeStyle == -1) {
838 dateFormat = provider.getDateInstance(dateStyle, loc);
839 } else {
840 if (dateStyle == -1) {
841 dateFormat = provider.getTimeInstance(timeStyle, loc);
842 } else {
843 dateFormat = provider.getDateTimeInstance(dateStyle, timeStyle, loc);
844 }
845 }
846 return dateFormat;
847 }
848
849 /**
850 * Create a new date format.
851 */
852 protected DateFormat() {}
853
854 /**
855 * Defines constants that are used as attribute keys in the
856 * <code>AttributedCharacterIterator</code> returned
857 * from <code>DateFormat.formatToCharacterIterator</code> and as
858 * field identifiers in <code>FieldPosition</code>.
859 * <p>
860 * The class also provides two methods to map
861 * between its constants and the corresponding Calendar constants.
862 *
863 * @since 1.4
864 * @see java.util.Calendar
865 */
866 public static class Field extends Format.Field {
867
868 // Proclaim serial compatibility with 1.4 FCS
869 private static final long serialVersionUID = 7441350119349544720L;
870
871 // table of all instances in this class, used by readResolve
872 private static final Map<String, Field> instanceMap = new HashMap<>(18);
873 // Maps from Calendar constant (such as Calendar.ERA) to Field
874 // constant (such as Field.ERA).
875 private static final Field[] calendarToFieldMapping =
876 new Field[Calendar.FIELD_COUNT];
877
878 /** Calendar field. */
879 private int calendarField;
880
881 /**
882 * Returns the <code>Field</code> constant that corresponds to
883 * the <code>Calendar</code> constant <code>calendarField</code>.
884 * If there is no direct mapping between the <code>Calendar</code>
885 * constant and a <code>Field</code>, null is returned.
886 *
887 * @throws IllegalArgumentException if <code>calendarField</code> is
888 * not the value of a <code>Calendar</code> field constant.
889 * @param calendarField Calendar field constant
890 * @return Field instance representing calendarField.
891 * @see java.util.Calendar
892 */
893 public static Field ofCalendarField(int calendarField) {
894 if (calendarField < 0 || calendarField >=
895 calendarToFieldMapping.length) {
896 throw new IllegalArgumentException("Unknown Calendar constant "
897 + calendarField);
898 }
899 return calendarToFieldMapping[calendarField];
900 }
901
902 /**
903 * Creates a <code>Field</code>.
904 *
905 * @param name the name of the <code>Field</code>
906 * @param calendarField the <code>Calendar</code> constant this
907 * <code>Field</code> corresponds to; any value, even one
908 * outside the range of legal <code>Calendar</code> values may
909 * be used, but <code>-1</code> should be used for values
910 * that don't correspond to legal <code>Calendar</code> values
911 */
912 protected Field(String name, int calendarField) {
913 super(name);
914 this.calendarField = calendarField;
915 if (this.getClass() == DateFormat.Field.class) {
916 instanceMap.put(name, this);
917 if (calendarField >= 0) {
918 // assert(calendarField < Calendar.FIELD_COUNT);
919 calendarToFieldMapping[calendarField] = this;
920 }
921 }
922 }
923
924 /**
925 * Returns the <code>Calendar</code> field associated with this
926 * attribute. For example, if this represents the hours field of
927 * a <code>Calendar</code>, this would return
928 * <code>Calendar.HOUR</code>. If there is no corresponding
929 * <code>Calendar</code> constant, this will return -1.
930 *
931 * @return Calendar constant for this field
932 * @see java.util.Calendar
933 */
934 public int getCalendarField() {
935 return calendarField;
936 }
937
938 /**
939 * Resolves instances being deserialized to the predefined constants.
940 *
941 * @throws InvalidObjectException if the constant could not be
942 * resolved.
943 * @return resolved DateFormat.Field constant
944 */
945 @Override
946 protected Object readResolve() throws InvalidObjectException {
947 if (this.getClass() != DateFormat.Field.class) {
948 throw new InvalidObjectException("subclass didn't correctly implement readResolve");
949 }
950
951 Object instance = instanceMap.get(getName());
952 if (instance != null) {
953 return instance;
954 } else {
955 throw new InvalidObjectException("unknown attribute name");
956 }
957 }
958
959 //
960 // The constants
961 //
962
963 /**
964 * Constant identifying the era field.
965 */
966 public static final Field ERA = new Field("era", Calendar.ERA);
967
968 /**
969 * Constant identifying the year field.
970 */
971 public static final Field YEAR = new Field("year", Calendar.YEAR);
972
973 /**
974 * Constant identifying the month field.
975 */
976 public static final Field MONTH = new Field("month", Calendar.MONTH);
977
978 /**
979 * Constant identifying the day of month field.
980 */
981 public static final Field DAY_OF_MONTH = new
982 Field("day of month", Calendar.DAY_OF_MONTH);
983
984 /**
985 * Constant identifying the hour of day field, where the legal values
986 * are 1 to 24.
987 */
988 public static final Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
989
990 /**
991 * Constant identifying the hour of day field, where the legal values
992 * are 0 to 23.
993 */
994 public static final Field HOUR_OF_DAY0 = new
995 Field("hour of day", Calendar.HOUR_OF_DAY);
996
997 /**
998 * Constant identifying the minute field.
999 */
1000 public static final Field MINUTE =new Field("minute", Calendar.MINUTE);
1001
1002 /**
1003 * Constant identifying the second field.
1004 */
1005 public static final Field SECOND =new Field("second", Calendar.SECOND);
1006
1007 /**
1008 * Constant identifying the millisecond field.
1009 */
1010 public static final Field MILLISECOND = new
1011 Field("millisecond", Calendar.MILLISECOND);
1012
1013 /**
1014 * Constant identifying the day of week field.
1015 */
1016 public static final Field DAY_OF_WEEK = new
1017 Field("day of week", Calendar.DAY_OF_WEEK);
1018
1019 /**
1020 * Constant identifying the day of year field.
1021 */
1022 public static final Field DAY_OF_YEAR = new
1023 Field("day of year", Calendar.DAY_OF_YEAR);
1024
1025 /**
1026 * Constant identifying the day of week field.
1027 */
1028 public static final Field DAY_OF_WEEK_IN_MONTH =
1029 new Field("day of week in month",
1030 Calendar.DAY_OF_WEEK_IN_MONTH);
1031
1032 /**
1033 * Constant identifying the week of year field.
1034 */
1035 public static final Field WEEK_OF_YEAR = new
1036 Field("week of year", Calendar.WEEK_OF_YEAR);
1037
1038 /**
1039 * Constant identifying the week of month field.
1040 */
1041 public static final Field WEEK_OF_MONTH = new
1042 Field("week of month", Calendar.WEEK_OF_MONTH);
1043
1044 /**
1045 * Constant identifying the time of day indicator
1046 * (e.g. "a.m." or "p.m.") field.
1047 */
1048 public static final Field AM_PM = new
1049 Field("am pm", Calendar.AM_PM);
1050
1051 /**
1052 * Constant identifying the hour field, where the legal values are
1053 * 1 to 12.
1054 */
1055 public static final Field HOUR1 = new Field("hour 1", -1);
1056
1057 /**
1058 * Constant identifying the hour field, where the legal values are
1059 * 0 to 11.
1060 */
1061 public static final Field HOUR0 = new
1062 Field("hour", Calendar.HOUR);
1063
1064 /**
1065 * Constant identifying the time zone field.
1066 */
1067 public static final Field TIME_ZONE = new Field("time zone", -1);
1068 }
1069 }
1070