001: /*
002: *
003: * @(#)DateFormat.java 1.46 06/10/10
004: *
005: * Portions Copyright 2000-2006 Sun Microsystems, Inc. All Rights
006: * Reserved. Use is subject to license terms.
007: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
008: *
009: * This program is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU General Public License version
011: * 2 only, as published by the Free Software Foundation.
012: *
013: * This program is distributed in the hope that it will be useful, but
014: * WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: * General Public License version 2 for more details (a copy is
017: * included at /legal/license.txt).
018: *
019: * You should have received a copy of the GNU General Public License
020: * version 2 along with this work; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022: * 02110-1301 USA
023: *
024: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
025: * Clara, CA 95054 or visit www.sun.com if you need additional
026: * information or have any questions.
027: */
028:
029: /*
030: * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
031: * (C) Copyright IBM Corp. 1996 - All Rights Reserved
032: *
033: * The original version of this source code and documentation is copyrighted
034: * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
035: * materials are provided under terms of a License Agreement between Taligent
036: * and Sun. This technology is protected by multiple US and International
037: * patents. This notice and attribution to Taligent may not be removed.
038: * Taligent is a registered trademark of Taligent, Inc.
039: *
040: */
041:
042: package java.text;
043:
044: import java.io.InvalidObjectException;
045: import java.util.HashMap;
046: import java.util.Locale;
047: import java.util.Map;
048: import java.util.ResourceBundle;
049: import java.util.MissingResourceException;
050: import java.util.TimeZone;
051: import java.util.Calendar;
052: import java.util.GregorianCalendar;
053: import java.util.Date;
054: import sun.text.resources.LocaleData;
055:
056: /**
057: * DateFormat is an abstract class for date/time formatting subclasses which
058: * formats and parses dates or time in a language-independent manner.
059: * The date/time formatting subclass, such as SimpleDateFormat, allows for
060: * formatting (i.e., date -> text), parsing (text -> date), and
061: * normalization. The date is represented as a <code>Date</code> object or
062: * as the milliseconds since January 1, 1970, 00:00:00 GMT.
063: *
064: * <p>DateFormat provides many class methods for obtaining default date/time
065: * formatters based on the default or a given locale and a number of formatting
066: * styles. The formatting styles include FULL, LONG, MEDIUM, and SHORT. More
067: * detail and examples of using these styles are provided in the method
068: * descriptions.
069: *
070: * <p>DateFormat helps you to format and parse dates for any locale.
071: * Your code can be completely independent of the locale conventions for
072: * months, days of the week, or even the calendar format: lunar vs. solar.
073: *
074: * <p>To format a date for the current Locale, use one of the
075: * static factory methods:
076: * <pre>
077: * myString = DateFormat.getDateInstance().format(myDate);
078: * </pre>
079: * <p>If you are formatting multiple dates, it is
080: * more efficient to get the format and use it multiple times so that
081: * the system doesn't have to fetch the information about the local
082: * language and country conventions multiple times.
083: * <pre>
084: * DateFormat df = DateFormat.getDateInstance();
085: * for (int i = 0; i < a.length; ++i) {
086: * output.println(df.format(myDate[i]) + "; ");
087: * }
088: * </pre>
089: * <p>To format a date for a different Locale, specify it in the
090: * call to getDateInstance().
091: * <pre>
092: * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
093: * </pre>
094: * <p>You can use a DateFormat to parse also.
095: * <pre>
096: * myDate = df.parse(myString);
097: * </pre>
098: * <p>Use getDateInstance to get the normal date format for that country.
099: * There are other static factory methods available.
100: * Use getTimeInstance to get the time format for that country.
101: * Use getDateTimeInstance to get a date and time format. You can pass in
102: * different options to these factory methods to control the length of the
103: * result; from SHORT to MEDIUM to LONG to FULL. The exact result depends
104: * on the locale, but generally:
105: * <ul><li>SHORT is completely numeric, such as 12.13.52 or 3:30pm
106: * <li>MEDIUM is longer, such as Jan 12, 1952
107: * <li>LONG is longer, such as January 12, 1952 or 3:30:32pm
108: * <li>FULL is pretty completely specified, such as
109: * Tuesday, April 12, 1952 AD or 3:30:42pm PST.
110: * </ul>
111: *
112: * <p>You can also set the time zone on the format if you wish.
113: * If you want even more control over the format or parsing,
114: * (or want to give your users more control),
115: * you can try casting the DateFormat you get from the factory methods
116: * to a SimpleDateFormat. This will work for the majority
117: * of countries; just remember to put it in a try block in case you
118: * encounter an unusual one.
119: *
120: * <p>You can also use forms of the parse and format methods with
121: * ParsePosition and FieldPosition to
122: * allow you to
123: * <ul><li>progressively parse through pieces of a string.
124: * <li>align any particular field, or find out where it is for selection
125: * on the screen.
126: * </ul>
127: *
128: * <h4><a name="synchronization">Synchronization</a></h4>
129: *
130: * <p>
131: * Date formats are not synchronized.
132: * It is recommended to create separate format instances for each thread.
133: * If multiple threads access a format concurrently, it must be synchronized
134: * externally.
135: *
136: * @see Format
137: * @see NumberFormat
138: * @see SimpleDateFormat
139: * @see java.util.Calendar
140: * @see java.util.GregorianCalendar
141: * @see java.util.TimeZone
142: * @version 1.46, 10/10/06
143: * @author Mark Davis, Chen-Lieh Huang, Alan Liu
144: */
145: public abstract class DateFormat extends Format {
146:
147: /**
148: * The calendar that <code>DateFormat</code> uses to produce the time field
149: * values needed to implement date and time formatting. Subclasses should
150: * initialize this to a calendar appropriate for the locale associated with
151: * this <code>DateFormat</code>.
152: * @serial
153: */
154: protected Calendar calendar;
155:
156: /**
157: * The number formatter that <code>DateFormat</code> uses to format numbers
158: * in dates and times. Subclasses should initialize this to a number format
159: * appropriate for the locale associated with this <code>DateFormat</code>.
160: * @serial
161: */
162: protected NumberFormat numberFormat;
163:
164: /**
165: * Useful constant for ERA field alignment.
166: * Used in FieldPosition of date/time formatting.
167: */
168: public final static int ERA_FIELD = 0;
169: /**
170: * Useful constant for YEAR field alignment.
171: * Used in FieldPosition of date/time formatting.
172: */
173: public final static int YEAR_FIELD = 1;
174: /**
175: * Useful constant for MONTH field alignment.
176: * Used in FieldPosition of date/time formatting.
177: */
178: public final static int MONTH_FIELD = 2;
179: /**
180: * Useful constant for DATE field alignment.
181: * Used in FieldPosition of date/time formatting.
182: */
183: public final static int DATE_FIELD = 3;
184: /**
185: * Useful constant for one-based HOUR_OF_DAY field alignment.
186: * Used in FieldPosition of date/time formatting.
187: * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
188: * For example, 23:59 + 01:00 results in 24:59.
189: */
190: public final static int HOUR_OF_DAY1_FIELD = 4;
191: /**
192: * Useful constant for zero-based HOUR_OF_DAY field alignment.
193: * Used in FieldPosition of date/time formatting.
194: * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
195: * For example, 23:59 + 01:00 results in 00:59.
196: */
197: public final static int HOUR_OF_DAY0_FIELD = 5;
198: /**
199: * Useful constant for MINUTE field alignment.
200: * Used in FieldPosition of date/time formatting.
201: */
202: public final static int MINUTE_FIELD = 6;
203: /**
204: * Useful constant for SECOND field alignment.
205: * Used in FieldPosition of date/time formatting.
206: */
207: public final static int SECOND_FIELD = 7;
208: /**
209: * Useful constant for MILLISECOND field alignment.
210: * Used in FieldPosition of date/time formatting.
211: */
212: public final static int MILLISECOND_FIELD = 8;
213: /**
214: * Useful constant for DAY_OF_WEEK field alignment.
215: * Used in FieldPosition of date/time formatting.
216: */
217: public final static int DAY_OF_WEEK_FIELD = 9;
218: /**
219: * Useful constant for DAY_OF_YEAR field alignment.
220: * Used in FieldPosition of date/time formatting.
221: */
222: public final static int DAY_OF_YEAR_FIELD = 10;
223: /**
224: * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
225: * Used in FieldPosition of date/time formatting.
226: */
227: public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
228: /**
229: * Useful constant for WEEK_OF_YEAR field alignment.
230: * Used in FieldPosition of date/time formatting.
231: */
232: public final static int WEEK_OF_YEAR_FIELD = 12;
233: /**
234: * Useful constant for WEEK_OF_MONTH field alignment.
235: * Used in FieldPosition of date/time formatting.
236: */
237: public final static int WEEK_OF_MONTH_FIELD = 13;
238: /**
239: * Useful constant for AM_PM field alignment.
240: * Used in FieldPosition of date/time formatting.
241: */
242: public final static int AM_PM_FIELD = 14;
243: /**
244: * Useful constant for one-based HOUR field alignment.
245: * Used in FieldPosition of date/time formatting.
246: * HOUR1_FIELD is used for the one-based 12-hour clock.
247: * For example, 11:30 PM + 1 hour results in 12:30 AM.
248: */
249: public final static int HOUR1_FIELD = 15;
250: /**
251: * Useful constant for zero-based HOUR field alignment.
252: * Used in FieldPosition of date/time formatting.
253: * HOUR0_FIELD is used for the zero-based 12-hour clock.
254: * For example, 11:30 PM + 1 hour results in 00:30 AM.
255: */
256: public final static int HOUR0_FIELD = 16;
257: /**
258: * Useful constant for TIMEZONE field alignment.
259: * Used in FieldPosition of date/time formatting.
260: */
261: public final static int TIMEZONE_FIELD = 17;
262:
263: // Proclaim serial compatibility with 1.1 release
264: private static final long serialVersionUID = 7218322306649953788L;
265:
266: /**
267: * Overrides Format.
268: * Formats a time object into a time string. Examples of time objects
269: * are a time value expressed in milliseconds and a Date object.
270: * @param obj must be a Number or a Date.
271: * @param toAppendTo the string buffer for the returning time string.
272: * @return the formatted time string.
273: * @param fieldPosition keeps track of the position of the field
274: * within the returned string.
275: * On input: an alignment field,
276: * if desired. On output: the offsets of the alignment field. For
277: * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
278: * if the given fieldPosition is DateFormat.YEAR_FIELD, the
279: * begin index and end index of fieldPosition will be set to
280: * 0 and 4, respectively.
281: * Notice that if the same time field appears
282: * more than once in a pattern, the fieldPosition will be set for the first
283: * occurrence of that time field. For instance, formatting a Date to
284: * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
285: * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
286: * the begin index and end index of fieldPosition will be set to
287: * 5 and 8, respectively, for the first occurrence of the timezone
288: * pattern character 'z'.
289: * @see java.text.Format
290: */
291: public final StringBuffer format(Object obj,
292: StringBuffer toAppendTo, FieldPosition fieldPosition) {
293: if (obj instanceof Date)
294: return format((Date) obj, toAppendTo, fieldPosition);
295: else if (obj instanceof Number)
296: return format(new Date(((Number) obj).longValue()),
297: toAppendTo, fieldPosition);
298: else
299: throw new IllegalArgumentException(
300: "Cannot format given Object as a Date");
301: }
302:
303: /**
304: * Formats a Date into a date/time string.
305: * @param date a Date to be formatted into a date/time string.
306: * @param toAppendTo the string buffer for the returning date/time string.
307: * @param fieldPosition keeps track of the position of the field
308: * within the returned string.
309: * On input: an alignment field,
310: * if desired. On output: the offsets of the alignment field. For
311: * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
312: * if the given fieldPosition is DateFormat.YEAR_FIELD, the
313: * begin index and end index of fieldPosition will be set to
314: * 0 and 4, respectively.
315: * Notice that if the same time field appears
316: * more than once in a pattern, the fieldPosition will be set for the first
317: * occurrence of that time field. For instance, formatting a Date to
318: * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
319: * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
320: * the begin index and end index of fieldPosition will be set to
321: * 5 and 8, respectively, for the first occurrence of the timezone
322: * pattern character 'z'.
323: * @return the formatted date/time string.
324: */
325: public abstract StringBuffer format(Date date,
326: StringBuffer toAppendTo, FieldPosition fieldPosition);
327:
328: /**
329: * Formats a Date into a date/time string.
330: * @param date the time value to be formatted into a time string.
331: * @return the formatted time string.
332: */
333: public final String format(Date date) {
334: return format(date, new StringBuffer(),
335: DontCareFieldPosition.INSTANCE).toString();
336: }
337:
338: /**
339: * Parses text from the beginning of the given string to produce a date.
340: * The method may not use the entire text of the given string.
341: * <p>
342: * See the {@link #parse(String, ParsePosition)} method for more information
343: * on date parsing.
344: *
345: * @param source A <code>String</code> whose beginning should be parsed.
346: * @return A <code>Date</code> parsed from the string.
347: * @exception ParseException if the beginning of the specified string
348: * cannot be parsed.
349: */
350: public Date parse(String source) throws ParseException {
351: ParsePosition pos = new ParsePosition(0);
352: Date result = parse(source, pos);
353: if (pos.index == 0)
354: throw new ParseException("Unparseable date: \"" + source
355: + "\"", pos.errorIndex);
356: return result;
357: }
358:
359: /**
360: * Parse a date/time string according to the given parse position. For
361: * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
362: * that is equivalent to Date(837039928046).
363: *
364: * <p> By default, parsing is lenient: If the input is not in the form used
365: * by this object's format method but can still be parsed as a date, then
366: * the parse succeeds. Clients may insist on strict adherence to the
367: * format by calling setLenient(false).
368: *
369: * @see java.text.DateFormat#setLenient(boolean)
370: *
371: * @param source The date/time string to be parsed
372: *
373: * @param pos On input, the position at which to start parsing; on
374: * output, the position at which parsing terminated, or the
375: * start position if the parse failed.
376: *
377: * @return A Date, or null if the input could not be parsed
378: */
379: public abstract Date parse(String source, ParsePosition pos);
380:
381: /**
382: * Parses text from a string to produce a <code>Date</code>.
383: * <p>
384: * The method attempts to parse text starting at the index given by
385: * <code>pos</code>.
386: * If parsing succeeds, then the index of <code>pos</code> is updated
387: * to the index after the last character used (parsing does not necessarily
388: * use all characters up to the end of the string), and the parsed
389: * date is returned. The updated <code>pos</code> can be used to
390: * indicate the starting point for the next call to this method.
391: * If an error occurs, then the index of <code>pos</code> is not
392: * changed, the error index of <code>pos</code> is set to the index of
393: * the character where the error occurred, and null is returned.
394: * <p>
395: * See the {@link #parse(String, ParsePosition)} method for more information
396: * on date parsing.
397: *
398: * @param source A <code>String</code>, part of which should be parsed.
399: * @param pos A <code>ParsePosition</code> object with index and error
400: * index information as described above.
401: * @return A <code>Date</code> parsed from the string. In case of
402: * error, returns null.
403: * @exception NullPointerException if <code>pos</code> is null.
404: */
405: public Object parseObject(String source, ParsePosition pos) {
406: return parse(source, pos);
407: }
408:
409: /**
410: * Constant for full style pattern.
411: */
412: public static final int FULL = 0;
413: /**
414: * Constant for long style pattern.
415: */
416: public static final int LONG = 1;
417: /**
418: * Constant for medium style pattern.
419: */
420: public static final int MEDIUM = 2;
421: /**
422: * Constant for short style pattern.
423: */
424: public static final int SHORT = 3;
425: /**
426: * Constant for default style pattern. Its value is MEDIUM.
427: */
428: public static final int DEFAULT = MEDIUM;
429:
430: /**
431: * Gets the time formatter with the default formatting style
432: * for the default locale.
433: * @return a time formatter.
434: */
435: public final static DateFormat getTimeInstance() {
436: return get(DEFAULT, 0, 1, Locale.getDefault());
437: }
438:
439: /**
440: * Gets the time formatter with the given formatting style
441: * for the default locale.
442: * @param style the given formatting style. For example,
443: * SHORT for "h:mm a" in the US locale.
444: * @return a time formatter.
445: */
446: public final static DateFormat getTimeInstance(int style) {
447: return get(style, 0, 1, Locale.getDefault());
448: }
449:
450: /**
451: * Gets the time formatter with the given formatting style
452: * for the given locale.
453: * @param style the given formatting style. For example,
454: * SHORT for "h:mm a" in the US locale.
455: * @param aLocale the given locale.
456: * @return a time formatter.
457: */
458: public final static DateFormat getTimeInstance(int style,
459: Locale aLocale) {
460: return get(style, 0, 1, aLocale);
461: }
462:
463: /**
464: * Gets the date formatter with the default formatting style
465: * for the default locale.
466: * @return a date formatter.
467: */
468: public final static DateFormat getDateInstance() {
469: return get(0, DEFAULT, 2, Locale.getDefault());
470: }
471:
472: /**
473: * Gets the date formatter with the given formatting style
474: * for the default locale.
475: * @param style the given formatting style. For example,
476: * SHORT for "M/d/yy" in the US locale.
477: * @return a date formatter.
478: */
479: public final static DateFormat getDateInstance(int style) {
480: return get(0, style, 2, Locale.getDefault());
481: }
482:
483: /**
484: * Gets the date formatter with the given formatting style
485: * for the given locale.
486: * @param style the given formatting style. For example,
487: * SHORT for "M/d/yy" in the US locale.
488: * @param aLocale the given locale.
489: * @return a date formatter.
490: */
491: public final static DateFormat getDateInstance(int style,
492: Locale aLocale) {
493: return get(0, style, 2, aLocale);
494: }
495:
496: /**
497: * Gets the date/time formatter with the default formatting style
498: * for the default locale.
499: * @return a date/time formatter.
500: */
501: public final static DateFormat getDateTimeInstance() {
502: return get(DEFAULT, DEFAULT, 3, Locale.getDefault());
503: }
504:
505: /**
506: * Gets the date/time formatter with the given date and time
507: * formatting styles for the default locale.
508: * @param dateStyle the given date formatting style. For example,
509: * SHORT for "M/d/yy" in the US locale.
510: * @param timeStyle the given time formatting style. For example,
511: * SHORT for "h:mm a" in the US locale.
512: * @return a date/time formatter.
513: */
514: public final static DateFormat getDateTimeInstance(int dateStyle,
515: int timeStyle) {
516: return get(timeStyle, dateStyle, 3, Locale.getDefault());
517: }
518:
519: /**
520: * Gets the date/time formatter with the given formatting styles
521: * for the given locale.
522: * @param dateStyle the given date formatting style.
523: * @param timeStyle the given time formatting style.
524: * @param aLocale the given locale.
525: * @return a date/time formatter.
526: */
527: public final static DateFormat getDateTimeInstance(int dateStyle,
528: int timeStyle, Locale aLocale) {
529: return get(timeStyle, dateStyle, 3, aLocale);
530: }
531:
532: /**
533: * Get a default date/time formatter that uses the SHORT style for both the
534: * date and the time.
535: */
536: public final static DateFormat getInstance() {
537: return getDateTimeInstance(SHORT, SHORT);
538: }
539:
540: /**
541: * Gets the set of locales for which DateFormats are installed.
542: * @return the set of locales for which DateFormats are installed.
543: */
544: public static Locale[] getAvailableLocales() {
545: return LocaleData.getAvailableLocales("DateTimePatterns");
546: }
547:
548: /**
549: * Set the calendar to be used by this date format. Initially, the default
550: * calendar for the specified or default locale is used.
551: * @param newCalendar the new Calendar to be used by the date format
552: */
553: public void setCalendar(Calendar newCalendar) {
554: this .calendar = newCalendar;
555: }
556:
557: /**
558: * Gets the calendar associated with this date/time formatter.
559: * @return the calendar associated with this date/time formatter.
560: */
561: public Calendar getCalendar() {
562: return calendar;
563: }
564:
565: /**
566: * Allows you to set the number formatter.
567: * @param newNumberFormat the given new NumberFormat.
568: */
569: public void setNumberFormat(NumberFormat newNumberFormat) {
570: this .numberFormat = newNumberFormat;
571: }
572:
573: /**
574: * Gets the number formatter which this date/time formatter uses to
575: * format and parse a time.
576: * @return the number formatter which this date/time formatter uses.
577: */
578: public NumberFormat getNumberFormat() {
579: return numberFormat;
580: }
581:
582: /**
583: * Sets the time zone for the calendar of this DateFormat object.
584: * @param zone the given new time zone.
585: */
586: public void setTimeZone(TimeZone zone) {
587: calendar.setTimeZone(zone);
588: }
589:
590: /**
591: * Gets the time zone.
592: * @return the time zone associated with the calendar of DateFormat.
593: */
594: public TimeZone getTimeZone() {
595: return calendar.getTimeZone();
596: }
597:
598: /**
599: * Specify whether or not date/time parsing is to be lenient. With
600: * lenient parsing, the parser may use heuristics to interpret inputs that
601: * do not precisely match this object's format. With strict parsing,
602: * inputs must match this object's format.
603: * @param lenient when true, parsing is lenient
604: * @see java.util.Calendar#setLenient
605: */
606: public void setLenient(boolean lenient) {
607: calendar.setLenient(lenient);
608: }
609:
610: /**
611: * Tell whether date/time parsing is to be lenient.
612: */
613: public boolean isLenient() {
614: return calendar.isLenient();
615: }
616:
617: /**
618: * Overrides hashCode
619: */
620: public int hashCode() {
621: return numberFormat.hashCode();
622: // just enough fields for a reasonable distribution
623: }
624:
625: /**
626: * Overrides equals
627: */
628: public boolean equals(Object obj) {
629: if (this == obj)
630: return true;
631: if (obj == null || getClass() != obj.getClass())
632: return false;
633: DateFormat other = (DateFormat) obj;
634: return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
635: calendar.getFirstDayOfWeek() == other.calendar
636: .getFirstDayOfWeek()
637: && calendar.getMinimalDaysInFirstWeek() == other.calendar
638: .getMinimalDaysInFirstWeek()
639: && calendar.isLenient() == other.calendar.isLenient()
640: && calendar.getTimeZone().equals(
641: other.calendar.getTimeZone()) && numberFormat
642: .equals(other.numberFormat));
643: }
644:
645: /**
646: * Overrides Cloneable
647: */
648: public Object clone() {
649: DateFormat other = (DateFormat) super .clone();
650: other.calendar = (Calendar) calendar.clone();
651: other.numberFormat = (NumberFormat) numberFormat.clone();
652: return other;
653: }
654:
655: /**
656: * Creates a DateFormat with the given time and/or date style in the given
657: * locale.
658: * @param timeStyle a value from 0 to 3 indicating the time format,
659: * ignored if flags is 2
660: * @param dateStyle a value from 0 to 3 indicating the time format,
661: * ignored if flags is 1
662: * @param flags either 1 for a time format, 2 for a date format,
663: * or 3 for a date/time format
664: * @param loc the locale for the format
665: */
666: private static DateFormat get(int timeStyle, int dateStyle,
667: int flags, Locale loc) {
668: if ((flags & 1) != 0) {
669: if (timeStyle < 0 || timeStyle > 3) {
670: throw new IllegalArgumentException(
671: "Illegal time style " + timeStyle);
672: }
673: } else {
674: timeStyle = -1;
675: }
676: if ((flags & 2) != 0) {
677: if (dateStyle < 0 || dateStyle > 3) {
678: throw new IllegalArgumentException(
679: "Illegal date style " + dateStyle);
680: }
681: } else {
682: dateStyle = -1;
683: }
684: try {
685: return new SimpleDateFormat(timeStyle, dateStyle, loc);
686:
687: } catch (MissingResourceException e) {
688: return new SimpleDateFormat("M/d/yy h:mm a");
689: }
690: }
691:
692: /**
693: * Create a new date format.
694: */
695: protected DateFormat() {
696: }
697:
698: /**
699: * Defines constants that are used as attribute keys in the
700: * <code>AttributedCharacterIterator</code> returned
701: * from <code>DateFormat.formatToCharacterIterator</code> and as
702: * field identifiers in <code>FieldPosition</code>.
703: * <p>
704: * The class also provides two methods to map
705: * between its constants and the corresponding Calendar constants.
706: *
707: * @since 1.4
708: * @see java.util.Calendar
709: */
710: public static class Field extends Format.Field {
711: // table of all instances in this class, used by readResolve
712: private static final Map instanceMap = new HashMap(18);
713: // Maps from Calendar constant (such as Calendar.ERA) to Field
714: // constant (such as Field.ERA).
715: private static final Field[] calendarToFieldMapping = new Field[Calendar.FIELD_COUNT];
716:
717: /** Calendar field. */
718: private int calendarField;
719:
720: /**
721: * Returns the <code>Field</code> constant that corresponds to
722: * the <code>Calendar</code> constant <code>calendarField</code>.
723: * If there is no direct mapping between the <code>Calendar</code>
724: * constant and a <code>Field</code>, null is returned.
725: *
726: * @throws IllegalArgumentException if <code>calendarField</code> is
727: * not the value of a <code>Calendar</code> field constant.
728: * @param calendarField Calendar field constant
729: * @return Field instance representing calendarField.
730: * @see java.util.Calendar
731: */
732: public static Field ofCalendarField(int calendarField) {
733: if (calendarField < 0
734: || calendarField >= calendarToFieldMapping.length) {
735: throw new IllegalArgumentException(
736: "Unknown Calendar constant " + calendarField);
737: }
738: return calendarToFieldMapping[calendarField];
739: }
740:
741: /**
742: * Creates a Field with the specified name.
743: * calendarField is used to identify the <code>Calendar</code>
744: * field this attribute represents. Use -1 if this field does
745: * not have a corresponding <code>Calendar</code> value.
746: *
747: * @param name Name of the attribute
748: * @param calendarField Calendar constant
749: */
750: protected Field(String name, int calendarField) {
751: super (name);
752: this .calendarField = calendarField;
753: if (this .getClass() == DateFormat.Field.class) {
754: instanceMap.put(name, this );
755: if (calendarField >= 0) {
756: // assert(calendarField < Calendar.FIELD_COUNT);
757: calendarToFieldMapping[calendarField] = this ;
758: }
759: }
760: }
761:
762: /**
763: * Returns the <code>Calendar</code> field associated with this
764: * attribute. For example, if this represents the hours field of
765: * a <code>Calendar</code>, this would return
766: * <code>Calendar.HOUR</code>. If there is no corresponding
767: * <code>Calendar</code> constant, this will return -1.
768: *
769: * @return Calendar constant for this field
770: * @see java.util.Calendar
771: */
772: public int getCalendarField() {
773: return calendarField;
774: }
775:
776: /**
777: * Resolves instances being deserialized to the predefined constants.
778: *
779: * @throws InvalidObjectException if the constant could not be
780: * resolved.
781: * @return resolved DateFormat.Field constant
782: */
783: protected Object readResolve() throws InvalidObjectException {
784: if (this .getClass() != DateFormat.Field.class) {
785: throw new InvalidObjectException(
786: "subclass didn't correctly implement readResolve");
787: }
788:
789: Object instance = instanceMap.get(getName());
790: if (instance != null) {
791: return instance;
792: } else {
793: throw new InvalidObjectException(
794: "unknown attribute name");
795: }
796: }
797:
798: //
799: // The constants
800: //
801:
802: /**
803: * Constant identifying the era field.
804: */
805: public final static Field ERA = new Field("era", Calendar.ERA);
806:
807: /**
808: * Constant identifying the year field.
809: */
810: public final static Field YEAR = new Field("year",
811: Calendar.YEAR);
812:
813: /**
814: * Constant identifying the month field.
815: */
816: public final static Field MONTH = new Field("month",
817: Calendar.MONTH);
818:
819: /**
820: * Constant identifying the day of month field.
821: */
822: public final static Field DAY_OF_MONTH = new Field(
823: "day of month", Calendar.DAY_OF_MONTH);
824:
825: /**
826: * Constant identifying the hour of day field, where the legal values
827: * are 1 to 24.
828: */
829: public final static Field HOUR_OF_DAY1 = new Field(
830: "hour of day 1", -1);
831:
832: /**
833: * Constant identifying the hour of day field, where the legal values
834: * are 0 to 23.
835: */
836: public final static Field HOUR_OF_DAY0 = new Field(
837: "hour of day", Calendar.HOUR_OF_DAY);
838:
839: /**
840: * Constant identifying the minute field.
841: */
842: public final static Field MINUTE = new Field("minute",
843: Calendar.MINUTE);
844:
845: /**
846: * Constant identifying the second field.
847: */
848: public final static Field SECOND = new Field("second",
849: Calendar.SECOND);
850:
851: /**
852: * Constant identifying the millisecond field.
853: */
854: public final static Field MILLISECOND = new Field(
855: "millisecond", Calendar.MILLISECOND);
856:
857: /**
858: * Constant identifying the day of week field.
859: */
860: public final static Field DAY_OF_WEEK = new Field(
861: "day of week", Calendar.DAY_OF_WEEK);
862:
863: /**
864: * Constant identifying the day of year field.
865: */
866: public final static Field DAY_OF_YEAR = new Field(
867: "day of year", Calendar.DAY_OF_YEAR);
868:
869: /**
870: * Constant identifying the day of week field.
871: */
872: public final static Field DAY_OF_WEEK_IN_MONTH = new Field(
873: "day of week in month", Calendar.DAY_OF_WEEK_IN_MONTH);
874:
875: /**
876: * Constant identifying the week of year field.
877: */
878: public final static Field WEEK_OF_YEAR = new Field(
879: "week of year", Calendar.WEEK_OF_YEAR);
880:
881: /**
882: * Constant identifying the week of month field.
883: */
884: public final static Field WEEK_OF_MONTH = new Field(
885: "week of month", Calendar.WEEK_OF_MONTH);
886:
887: /**
888: * Constant identifying the time of day indicator
889: * (e.g. "a.m." or "p.m.") field.
890: */
891: public final static Field AM_PM = new Field("am pm",
892: Calendar.AM_PM);
893:
894: /**
895: * Constant identifying the hour field, where the legal values are
896: * 1 to 12.
897: */
898: public final static Field HOUR1 = new Field("hour 1", -1);
899:
900: /**
901: * Constant identifying the hour field, where the legal values are
902: * 0 to 11.
903: */
904: public final static Field HOUR0 = new Field("hour",
905: Calendar.HOUR);
906:
907: /**
908: * Constant identifying the time zone field.
909: */
910: public final static Field TIME_ZONE = new Field("time zone", -1);
911: }
912: }
|