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