home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / text / DateFormat.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  23.0 KB  |  646 lines

  1. /*
  2.  * @(#)DateFormat.java    1.27 98/03/18
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.text;
  32. import java.util.Locale;
  33. import java.util.ResourceBundle;
  34. import java.util.MissingResourceException;
  35. import java.util.TimeZone;
  36. import java.util.Calendar;
  37. import java.util.GregorianCalendar;
  38. import java.util.Date;
  39. import java.text.resources.*;
  40.  
  41. /**
  42.  * DateFormat is an abstract class for date/time formatting subclasses which
  43.  * formats and parses dates or time in a language-independent manner.
  44.  * The date/time formatting subclass, such as SimpleDateFormat, allows for
  45.  * formatting (i.e., date -> text), parsing (text -> date), and
  46.  * normalization.  The date is represented as a <code>Date</code> object or
  47.  * as the milliseconds since January 1, 1970, 00:00:00 GMT.
  48.  *
  49.  * <p>DateFormat provides many class methods for obtaining default date/time
  50.  * formatters based on the default or a given loacle and a number of formatting
  51.  * styles. The formatting styles include FULL, LONG, MEDIUM, and SHORT. More
  52.  * detail and examples of using these styles are provided in the method
  53.  * descriptions.
  54.  *
  55.  * <p>DateFormat helps you to format and parse dates for any locale.
  56.  * Your code can be completely independent of the locale conventions for
  57.  * months, days of the week, or even the calendar format: lunar vs. solar.
  58.  *
  59.  * <p>To format a date for the current Locale, use one of the
  60.  * static factory methods:
  61.  * <pre>
  62.  *  myString = DateFormat.getDateInstance().format(myDate);
  63.  * </pre>
  64.  * <p>If you are formatting multiple numbers, it is
  65.  * more efficient to get the format and use it multiple times so that
  66.  * the system doesn't have to fetch the information about the local
  67.  * language and country conventions multiple times.
  68.  * <pre>
  69.  *  DateFormat df = DateFormat.getDateInstance();
  70.  *  for (int i = 0; i < a.length; ++i) {
  71.  *    output.println(df.format(myDate[i]) + "; ");
  72.  *  }
  73.  * </pre>
  74.  * <p>To format a number for a different Locale, specify it in the
  75.  * call to getDateInstance().
  76.  * <pre>
  77.  *  DateFormat df = DateFormat.getDateInstance(Locale.FRANCE);
  78.  * </pre>
  79.  * <p>You can use a DateFormat to parse also.
  80.  * <pre>
  81.  *  myDate = df.parse(myString);
  82.  * </pre>
  83.  * <p>Use getDate to get the normal date format for that country.
  84.  * There are other static factory methods available.
  85.  * Use getTime to get the time format for that country.
  86.  * Use getDateTime to get a date and time format. You can pass in different
  87.  * options to these factory methods to control the length of the
  88.  * result; from SHORT to MEDIUM to LONG to FULL. The exact result depends
  89.  * on the locale, but generally:
  90.  * <ul><li>SHORT is completely numeric, such as 12.13.52 or 3:30pm
  91.  * <li>MEDIUM is longer, such as Jan 12, 1952
  92.  * <li>LONG is longer, such as January 12, 1952 or 3:30:32pm
  93.  * <li>FULL is pretty completely specified, such as
  94.  * Tuesday, April 12, 1952 AD or 3:30:42pm PST.
  95.  * </ul>
  96.  *
  97.  * <p>You can also set the time zone on the format if you wish.
  98.  * If you want even more control over the format or parsing,
  99.  * (or want to give your users more control),
  100.  * you can try casting the DateFormat you get from the factory methods
  101.  * to a SimpleDateFormat. This will work for the majority
  102.  * of countries; just remember to put it in a try block in case you
  103.  * encounter an unusual one.
  104.  *
  105.  * <p>You can also use forms of the parse and format methods with
  106.  * ParsePosition and FieldPosition to
  107.  * allow you to
  108.  * <ul><li>pregressively parse through pieces of a string.
  109.  * <li>align any particular field, or find out where it is for selection
  110.  * on the screen.
  111.  * </ul>
  112.  *
  113.  * @see          Format
  114.  * @see          NumberFormat
  115.  * @see          SimpleDateFormat
  116.  * @see          java.util.Calendar
  117.  * @see          java.util.GregorianCalendar
  118.  * @see          java.util.TimeZone
  119.  * @version      1.27 03/18/98
  120.  * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
  121.  */
  122. public abstract class DateFormat extends Format {
  123.  
  124.     /**
  125.      * The calendar that DateFormat uses to produce the time field values
  126.      * needed to implement date/time formatting.  Subclasses should initialize
  127.      * this to the default calendar for the locale associated with this
  128.      * DateFormat.
  129.      */
  130.     protected Calendar calendar;
  131.  
  132.     /**
  133.      * The number formatter that DateFormat uses to format numbers in dates
  134.      * and times.  Subclasses should initialize this to the default number
  135.      * format for the locale associated with this DateFormat.
  136.      */
  137.     protected NumberFormat numberFormat;
  138.  
  139.     /**
  140.      * Useful constant for ERA field alignment.
  141.      * Used in FieldPosition of date/time formatting.
  142.      */
  143.     public final static int ERA_FIELD = 0;
  144.     /**
  145.      * Useful constant for YEAR field alignment.
  146.      * Used in FieldPosition of date/time formatting.
  147.      */
  148.     public final static int YEAR_FIELD = 1;
  149.     /**
  150.      * Useful constant for MONTH field alignment.
  151.      * Used in FieldPosition of date/time formatting.
  152.      */
  153.     public final static int MONTH_FIELD = 2;
  154.     /**
  155.      * Useful constant for DATE field alignment.
  156.      * Used in FieldPosition of date/time formatting.
  157.      */
  158.     public final static int DATE_FIELD = 3;
  159.     /**
  160.      * Useful constant for one-based HOUR_OF_DAY field alignment.
  161.      * Used in FieldPosition of date/time formatting.
  162.      * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
  163.      * For example, 23:59 + 01:00 results in 24:59.
  164.      */
  165.     public final static int HOUR_OF_DAY1_FIELD = 4;
  166.     /**
  167.      * Useful constant for zero-based HOUR_OF_DAY field alignment.
  168.      * Used in FieldPosition of date/time formatting.
  169.      * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
  170.      * For example, 23:59 + 01:00 results in 00:59.
  171.      */
  172.     public final static int HOUR_OF_DAY0_FIELD = 5;
  173.     /**
  174.      * Useful constant for MINUTE field alignment.
  175.      * Used in FieldPosition of date/time formatting.
  176.      */
  177.     public final static int MINUTE_FIELD = 6;
  178.     /**
  179.      * Useful constant for SECOND field alignment.
  180.      * Used in FieldPosition of date/time formatting.
  181.      */
  182.     public final static int SECOND_FIELD = 7;
  183.     /**
  184.      * Useful constant for MILLISECOND field alignment.
  185.      * Used in FieldPosition of date/time formatting.
  186.      */
  187.     public final static int MILLISECOND_FIELD = 8;
  188.     /**
  189.      * Useful constant for DAY_OF_WEEK field alignment.
  190.      * Used in FieldPosition of date/time formatting.
  191.      */
  192.     public final static int DAY_OF_WEEK_FIELD = 9;
  193.     /**
  194.      * Useful constant for DAY_OF_YEAR field alignment.
  195.      * Used in FieldPosition of date/time formatting.
  196.      */
  197.     public final static int DAY_OF_YEAR_FIELD = 10;
  198.     /**
  199.      * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
  200.      * Used in FieldPosition of date/time formatting.
  201.      */
  202.     public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
  203.     /**
  204.      * Useful constant for WEEK_OF_YEAR field alignment.
  205.      * Used in FieldPosition of date/time formatting.
  206.      */
  207.     public final static int WEEK_OF_YEAR_FIELD = 12;
  208.     /**
  209.      * Useful constant for WEEK_OF_MONTH field alignment.
  210.      * Used in FieldPosition of date/time formatting.
  211.      */
  212.     public final static int WEEK_OF_MONTH_FIELD = 13;
  213.     /**
  214.      * Useful constant for AM_PM field alignment.
  215.      * Used in FieldPosition of date/time formatting.
  216.      */
  217.     public final static int AM_PM_FIELD = 14;
  218.     /**
  219.      * Useful constant for one-based HOUR field alignment.
  220.      * Used in FieldPosition of date/time formatting.
  221.      * HOUR1_FIELD is used for the one-based 12-hour clock.
  222.      * For example, 11:30 PM + 1 hour results in 12:30 AM.
  223.      */
  224.     public final static int HOUR1_FIELD = 15;
  225.     /**
  226.      * Useful constant for zero-based HOUR field alignment.
  227.      * Used in FieldPosition of date/time formatting.
  228.      * HOUR0_FIELD is used for the zero-based 12-hour clock.
  229.      * For example, 11:30 PM + 1 hour results in 00:30 AM.
  230.      */
  231.     public final static int HOUR0_FIELD = 16;
  232.     /**
  233.      * Useful constant for TIMEZONE field alignment.
  234.      * Used in FieldPosition of date/time formatting.
  235.      */
  236.     public final static int TIMEZONE_FIELD = 17;
  237.  
  238.     // Proclaim serial compatibility with 1.1 FCS
  239.     private static final long serialVersionUID = 7218322306649953788L;
  240.  
  241.     /**
  242.      * Overrides Format.
  243.      * Formats a time object into a time string. Examples of time objects
  244.      * are a time value expressed in milliseconds and a Date object.
  245.      * @param obj must be a Number or a Date.
  246.      * @param toAppendTo the string buffer for the returning time string.
  247.      * @return the formatted time string.
  248.      * @param fieldPosition keeps track of the position of the field
  249.      * within the returned string.
  250.      * On input: an alignment field,
  251.      * if desired. On output: the offsets of the alignment field. For
  252.      * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  253.      * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  254.      * begin index and end index of fieldPosition will be set to
  255.      * 0 and 4, respectively.
  256.      * Notice that if the same time field appears
  257.      * more than once in a pattern, the fieldPosition will be set for the first
  258.      * occurence of that time field. For instance, formatting a Date to
  259.      * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  260.      * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  261.      * the begin index and end index of fieldPosition will be set to
  262.      * 5 and 8, respectively, for the first occurence of the timezone
  263.      * pattern character 'z'.
  264.      * @see java.text.Format
  265.      */
  266.     public final StringBuffer format(Object obj, StringBuffer toAppendTo,
  267.                                      FieldPosition fieldPosition)
  268.     {
  269.         if (obj instanceof Number)
  270.             return format( new Date(((Number)obj).longValue()),
  271.                           toAppendTo, fieldPosition );
  272.         else if (obj instanceof Date)
  273.             return format( (Date)obj, toAppendTo, fieldPosition );
  274.         else
  275.             throw new IllegalArgumentException("Cannot format given Object as a Date");
  276.     }
  277.  
  278.     /**
  279.      * Formats a Date into a date/time string.
  280.      * @param date a Date to be formatted into a date/time string.
  281.      * @param toAppendTo the string buffer for the returning date/time string.
  282.      * @param fieldPosition keeps track of the position of the field
  283.      * within the returned string.
  284.      * On input: an alignment field,
  285.      * if desired. On output: the offsets of the alignment field. For
  286.      * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  287.      * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  288.      * begin index and end index of fieldPosition will be set to
  289.      * 0 and 4, respectively.
  290.      * Notice that if the same time field appears
  291.      * more than once in a pattern, the fieldPosition will be set for the first
  292.      * occurence of that time field. For instance, formatting a Date to
  293.      * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  294.      * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  295.      * the begin index and end index of fieldPosition will be set to
  296.      * 5 and 8, respectively, for the first occurence of the timezone
  297.      * pattern character 'z'.
  298.      * @return the formatted date/time string.
  299.      */
  300.     public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
  301.                                         FieldPosition fieldPosition);
  302.  
  303.     /**
  304.      * Formats a Date into a date/time string.
  305.      * @param date the time value to be formatted into a time string.
  306.      * @return the formatted time string.
  307.      */
  308.     public final String format(Date date)
  309.     {
  310.         return format(date, new StringBuffer(),new FieldPosition(0)).toString();
  311.     }
  312.  
  313.     /**
  314.      * Parse a date/time string.
  315.      *
  316.      * @param text  The date/time string to be parsed
  317.      *
  318.      * @return      A Date, or null if the input could not be parsed
  319.      *
  320.      * @exception  ParseException  If the given string cannot be parsed as a date.
  321.      *
  322.      * @see #parse(String, ParsePosition)
  323.      */
  324.     public Date parse(String text) throws ParseException
  325.     {
  326.         ParsePosition pos = new ParsePosition(0);
  327.         Date result = parse(text, pos);
  328.         if (pos.index == 0)
  329.             throw new ParseException("Unparseable date: \"" + text + "\"" ,
  330.                 pos.errorIndex);
  331.         return result;
  332.     }
  333.  
  334.     /**
  335.      * Parse a date/time string according to the given parse position.  For
  336.      * example, a time text "07/10/96 4:5 PM, PDT" will be parsed into a Date
  337.      * that is equivalent to Date(837039928046).
  338.      *
  339.      * <p> By default, parsing is lenient: If the input is not in the form used
  340.      * by this object's format method but can still be parsed as a date, then
  341.      * the parse succeeds.  Clients may insist on strict adherence to the
  342.      * format by calling setLenient(false).
  343.      *
  344.      * @see java.text.DateFormat#setLenient(boolean)
  345.      *
  346.      * @param text  The date/time string to be parsed
  347.      *
  348.      * @param pos   On input, the position at which to start parsing; on
  349.      *              output, the position at which parsing terminated, or the
  350.      *              start position if the parse failed.
  351.      *
  352.      * @return      A Date, or null if the input could not be parsed
  353.      */
  354.     public abstract Date parse(String text, ParsePosition pos);
  355.  
  356.     /**
  357.      * Parse a date/time string into an Object.  This convenience method simply
  358.      * calls parse(String, ParsePosition).
  359.      *
  360.      * @see #parse(String, ParsePosition)
  361.      */
  362.     public Object parseObject (String source, ParsePosition pos)
  363.     {
  364.         return parse(source, pos);
  365.     }
  366.  
  367.     /**
  368.      * Constant for full style pattern.
  369.      */
  370.     public static final int FULL = 0;
  371.     /**
  372.      * Constant for long style pattern.
  373.      */
  374.     public static final int LONG = 1;
  375.     /**
  376.      * Constant for medium style pattern.
  377.      */
  378.     public static final int MEDIUM = 2;
  379.     /**
  380.      * Constant for short style pattern.
  381.      */
  382.     public static final int SHORT = 3;
  383.     /**
  384.      * Constant for default style pattern.
  385.      */
  386.     public static final int DEFAULT = MEDIUM;
  387.  
  388.     /**
  389.      * Gets the time formatter with the default formatting style
  390.      * for the default locale.
  391.      * @return a time formatter.
  392.      */
  393.     public final static DateFormat getTimeInstance()
  394.     {
  395.         return get(DEFAULT, -1, Locale.getDefault());
  396.     }
  397.  
  398.     /**
  399.      * Gets the time formatter with the given formatting style
  400.      * for the default locale.
  401.      * @param style the given formatting style. For example,
  402.      * SHORT for "h:mm a" in the US locale.
  403.      * @return a time formatter.
  404.      */
  405.     public final static DateFormat getTimeInstance(int style)
  406.     {
  407.         return get(style, -1, Locale.getDefault());
  408.     }
  409.  
  410.     /**
  411.      * Gets the time formatter with the given formatting style
  412.      * for the given locale.
  413.      * @param style the given formatting style. For example,
  414.      * SHORT for "h:mm a" in the US locale.
  415.      * @param aLocale the given locale.
  416.      * @return a time formatter.
  417.      */
  418.     public final static DateFormat getTimeInstance(int style,
  419.                                                  Locale aLocale)
  420.     {
  421.         return get(style, -1, aLocale);
  422.     }
  423.  
  424.     /**
  425.      * Gets the date formatter with the default formatting style
  426.      * for the default locale.
  427.      * @return a date formatter.
  428.      */
  429.     public final static DateFormat getDateInstance()
  430.     {
  431.         // +4 to set the correct index for getting data out of
  432.         // LocaleElements.
  433.         return get(-1, DEFAULT + 4, Locale.getDefault());
  434.     }
  435.  
  436.     /**
  437.      * Gets the date formatter with the given formatting style
  438.      * for the default locale.
  439.      * @param style the given formatting style. For example,
  440.      * SHORT for "M/d/yy" in the US locale.
  441.      * @return a date formatter.
  442.      */
  443.     public final static DateFormat getDateInstance(int style)
  444.     {
  445.         return get(-1, style + 4, Locale.getDefault());
  446.     }
  447.  
  448.     /**
  449.      * Gets the date formatter with the given formatting style
  450.      * for the given locale.
  451.      * @param style the given formatting style. For example,
  452.      * SHORT for "M/d/yy" in the US locale.
  453.      * @param aLocale the given locale.
  454.      * @return a date formatter.
  455.      */
  456.     public final static DateFormat getDateInstance(int style,
  457.                                                  Locale aLocale)
  458.     {
  459.         return get(-1, style + 4, aLocale);
  460.     }
  461.  
  462.     /**
  463.      * Gets the date/time formatter with the default formatting style
  464.      * for the default locale.
  465.      * @return a date/time formatter.
  466.      */
  467.     public final static DateFormat getDateTimeInstance()
  468.     {
  469.         return get(DEFAULT, DEFAULT + 4, Locale.getDefault());
  470.     }
  471.  
  472.     /**
  473.      * Gets the date/time formatter with the given date and time
  474.      * formatting styles for the default locale.
  475.      * @param dateStyle the given date formatting style. For example,
  476.      * SHORT for "M/d/yy" in the US locale.
  477.      * @param timeStyle the given time formatting style. For example,
  478.      * SHORT for "h:mm a" in the US locale.
  479.      * @return a date/time formatter.
  480.      */
  481.     public final static DateFormat getDateTimeInstance(int dateStyle,
  482.                                                        int timeStyle)
  483.     {
  484.         return get(timeStyle, dateStyle + 4, Locale.getDefault());
  485.     }
  486.  
  487.     /**
  488.      * Gets the date/time formatter with the given formatting styles
  489.      * for the given locale.
  490.      * @param dateStyle the given date formatting style.
  491.      * @param timeStyle the given time formatting style.
  492.      * @param aLocale the given locale.
  493.      * @return a date/time formatter.
  494.      */
  495.     public final static DateFormat
  496.         getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
  497.     {
  498.         return get(timeStyle, dateStyle + 4, aLocale);
  499.     }
  500.  
  501.     /**
  502.      * Get a default date/time formatter that uses the SHORT style for both the
  503.      * date and the time.
  504.      */
  505.     public final static DateFormat getInstance() {
  506.         return getDateTimeInstance(SHORT, SHORT);
  507.     }
  508.  
  509.     /**
  510.      * Gets the set of locales for which DateFormats are installed.
  511.      * @return the set of locales for which DateFormats are installed.
  512.      */
  513.     public static Locale[] getAvailableLocales()
  514.     {
  515.         return LocaleData.getAvailableLocales("DateTimePatterns");
  516.     }
  517.  
  518.     /**
  519.      * Set the calendar to be used by this date format.  Initially, the default
  520.      * calendar for the specified or default locale is used.
  521.      * @param newCalendar the new Calendar to be used by the date format
  522.      */
  523.     public void setCalendar(Calendar newCalendar)
  524.     {
  525.         this.calendar = newCalendar;
  526.     }
  527.  
  528.     /**
  529.      * Gets the calendar associated with this date/time formatter.
  530.      * @return the calendar associated with this date/time formatter.
  531.      */
  532.     public Calendar getCalendar()
  533.     {
  534.         return calendar;
  535.     }
  536.  
  537.     /**
  538.      * Allows you to set the number formatter.
  539.      * @param newNumberFormat the given new NumberFormat.
  540.      */
  541.     public void setNumberFormat(NumberFormat newNumberFormat)
  542.     {
  543.         this.numberFormat = newNumberFormat;
  544.     }
  545.  
  546.     /**
  547.      * Gets the number formatter which this date/time formatter uses to
  548.      * format and parse a time.
  549.      * @return the number formatter which this date/time formatter uses.
  550.      */
  551.     public NumberFormat getNumberFormat()
  552.     {
  553.         return numberFormat;
  554.     }
  555.  
  556.     /**
  557.      * Sets the time zone for the calendar of this DateFormat object.
  558.      * @param zone the given new time zone.
  559.      */
  560.     public void setTimeZone(TimeZone zone)
  561.     {
  562.         calendar.setTimeZone(zone);
  563.     }
  564.  
  565.     /**
  566.      * Gets the time zone.
  567.      * @return the time zone associated with the calendar of DateFormat.
  568.      */
  569.     public TimeZone getTimeZone()
  570.     {
  571.         return calendar.getTimeZone();
  572.     }
  573.  
  574.     /**
  575.      * Specify whether or not date/time parsing is to be lenient.  With
  576.      * lenient parsing, the parser may use heuristics to interpret inputs that
  577.      * do not precisely match this object's format.  With strict parsing,
  578.      * inputs must match this object's format.
  579.      * @param lenient when true, parsing is lenient
  580.      * @see java.util.Calendar#setLenient
  581.      */
  582.     public void setLenient(boolean lenient)
  583.     {
  584.         calendar.setLenient(lenient);
  585.     }
  586.  
  587.     /**
  588.      * Tell whether date/time parsing is to be lenient.
  589.      */
  590.     public boolean isLenient()
  591.     {
  592.         return calendar.isLenient();
  593.     }
  594.  
  595.     /**
  596.      * Overrides hashCode
  597.      */
  598.     public int hashCode() {
  599.         return numberFormat.hashCode();
  600.         // just enough fields for a reasonable distribution
  601.     }
  602.  
  603.     /**
  604.      * Overrides equals
  605.      */
  606.     public boolean equals(Object obj) {
  607.         if (this == obj) return true;
  608.         if (obj == null || getClass() != obj.getClass()) return false;
  609.         DateFormat other = (DateFormat) obj;
  610.         return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
  611.                 calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
  612.                 calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
  613.                 calendar.isLenient() == other.calendar.isLenient() &&
  614.                 calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
  615.                 numberFormat.equals(other.numberFormat));
  616.     }
  617.  
  618.     /**
  619.      * Overrides Cloneable
  620.      */
  621.     public Object clone()
  622.     {
  623.         DateFormat other = (DateFormat) super.clone();
  624.         other.calendar = (Calendar) calendar.clone();
  625.         other.numberFormat = (NumberFormat) numberFormat.clone();
  626.         return other;
  627.     }
  628.  
  629.     private static DateFormat get(int timeStyle, /* -1 for no time */
  630.                                   int dateStyle, /* -1 for no date */
  631.                                   Locale loc) {
  632.         try {
  633.             ResourceBundle resource
  634.                 = ResourceBundle.getBundle
  635.                 ("java.text.resources.LocaleElements", loc);
  636.             return new SimpleDateFormat(timeStyle, dateStyle, loc);
  637.  
  638.         } catch (MissingResourceException e) {
  639.             return new SimpleDateFormat("M/d/yy h:mm a");
  640.         }
  641.     }
  642.  
  643.     protected DateFormat() { }
  644.  
  645. }
  646.