OSDN Git Service

libjava/ChangeLog:
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / text / DateFormat.java
1 /* DateFormat.java -- Class for formatting/parsing date/times
2    Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11  
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39
40 package java.text;
41
42 import gnu.java.locale.LocaleHelper;
43
44 import java.text.spi.DateFormatProvider;
45
46 import java.io.InvalidObjectException;
47 import java.util.Calendar;
48 import java.util.Date;
49 import java.util.Locale;
50 import java.util.MissingResourceException;
51 import java.util.ResourceBundle;
52 import java.util.ServiceLoader;
53 import java.util.TimeZone;
54
55 /**
56  * @author Per Bothner (bothner@cygnus.com)
57  * @date October 25, 1998.
58  */
59 /* Written using "Java Class Libraries", 2nd edition, plus online
60  * API docs for JDK 1.2 beta from http://www.javasoft.com.
61  * Status:  Mostly complete; search for FIXME to see omissions.
62  */
63
64 public abstract class DateFormat extends Format implements Cloneable
65 {
66   private static final long serialVersionUID = 7218322306649953788L;
67
68   // Names fixed by serialization spec.
69   protected Calendar calendar;
70   protected NumberFormat numberFormat;
71
72   // (Values determined using a test program.)
73   public static final int FULL = 0;
74   public static final int LONG = 1;
75   public static final int MEDIUM = 2;
76   public static final int SHORT = 3;
77   public static final int DEFAULT = MEDIUM;
78
79   /* These constants need to have these exact values.  They
80    * correspond to index positions within the localPatternChars
81    * string for a given locale.  Each locale may specify its
82    * own character for a particular field, but the position
83    * of these characters must correspond to an appropriate field
84    * number (as listed below), in order for their meaning to
85    * be determined.  For example, the US locale uses
86    * the string "GyMdkHmsSEDFwWahKzYeugAZ", where 'G' is the character
87    * for era, 'y' for year, and so on down to 'Z' for time zone.
88    */
89   /**
90    * Represents the position of the era
91    * pattern character in the array of
92    * localized pattern characters. 
93    * For example, 'AD' is an era used
94    * in the Gregorian calendar system.
95    * In the U.S. locale, this is 'G'.
96    */  
97   public static final int ERA_FIELD = 0;
98   /**
99    * Represents the position of the year
100    * pattern character in the array of
101    * localized pattern characters.
102    * In the U.S. locale, this is 'y'.
103    */
104   public static final int YEAR_FIELD = 1;
105   /**
106    * Represents the position of the month
107    * pattern character in the array of
108    * localized pattern characters.
109    * In the U.S. locale, this is 'M'.
110    */
111   public static final int MONTH_FIELD = 2;
112   /**
113    * Represents the position of the date
114    * or day of the month pattern character
115    * in the array of localized pattern
116    * characters.  In the U.S. locale,
117    * this is 'd'.
118    */
119   public static final int DATE_FIELD = 3;
120   /**
121    * Represents the position of the 24
122    * hour pattern character in the array of
123    * localized pattern characters.
124    * In the U.S. locale, this is 'k'.
125    * This field numbers hours from 1 to 24.
126    */
127   public static final int HOUR_OF_DAY1_FIELD = 4;
128   /**
129    * Represents the position of the 24
130    * hour pattern character in the array of
131    * localized pattern characters.
132    * In the U.S. locale, this is 'H'.
133    * This field numbers hours from 0 to 23.
134    */
135   public static final int HOUR_OF_DAY0_FIELD = 5;
136   /**
137    * Represents the position of the minute
138    * pattern character in the array of
139    * localized pattern characters.
140    * In the U.S. locale, this is 'm'.
141    */
142   public static final int MINUTE_FIELD = 6;
143   /**
144    * Represents the position of the second
145    * pattern character in the array of
146    * localized pattern characters.
147    * In the U.S. locale, this is 's'.
148    */
149   public static final int SECOND_FIELD = 7;
150   /**
151    * Represents the position of the millisecond
152    * pattern character in the array of
153    * localized pattern characters.
154    * In the U.S. locale, this is 'S'.
155    */
156   public static final int MILLISECOND_FIELD = 8;
157   /**
158    * Represents the position of the day of the
159    * week pattern character in the array of
160    * localized pattern characters.
161    * In the U.S. locale, this is 'E'.
162    */
163   public static final int DAY_OF_WEEK_FIELD = 9;
164   /**
165    * Represents the position of the day of the
166    * year pattern character in the array of
167    * localized pattern characters.
168    * In the U.S. locale, this is 'D'.
169    */
170   public static final int DAY_OF_YEAR_FIELD = 10;
171   /**
172    * Represents the position of the day of the
173    * week in the month pattern character in the
174    * array of localized pattern characters.
175    * In the U.S. locale, this is 'F'.
176    */
177   public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
178   /**
179    * Represents the position of the week of the
180    * year pattern character in the array of
181    * localized pattern characters.
182    * In the U.S. locale, this is 'w'.
183    */
184   public static final int WEEK_OF_YEAR_FIELD = 12;
185   /**
186    * Represents the position of the week of the
187    * month pattern character in the array of
188    * localized pattern characters.
189    * In the U.S. locale, this is 'W'.
190    */
191   public static final int WEEK_OF_MONTH_FIELD = 13;
192   /**
193    * Represents the position of the am/pm
194    * pattern character in the array of
195    * localized pattern characters.
196    * In the U.S. locale, this is 'a'.
197    */
198   public static final int AM_PM_FIELD = 14;
199   /**
200    * Represents the position of the 12 
201    * hour pattern character in the array of
202    * localized pattern characters.
203    * In the U.S. locale, this is 'h'.
204    * This field numbers hours from 1 to 12.
205    */
206   public static final int HOUR1_FIELD = 15;
207   /**
208    * Represents the position of the 12 
209    * hour pattern character in the array of
210    * localized pattern characters.
211    * In the U.S. locale, this is 'K'.
212    * This field numbers hours from 0 to 11.
213    */
214   public static final int HOUR0_FIELD = 16;
215   /**
216    * Represents the position of the generic
217    * timezone pattern character in the array of
218    * localized pattern characters.
219    * In the U.S. locale, this is 'z'.
220    */
221   public static final int TIMEZONE_FIELD = 17;
222
223   public static class Field extends Format.Field
224   {
225     static final long serialVersionUID = 7441350119349544720L;
226     
227     private int calendarField;
228
229     public static final DateFormat.Field ERA
230         = new Field("era", Calendar.ERA);
231     public static final DateFormat.Field YEAR
232         = new Field("year", Calendar.YEAR);
233     public static final DateFormat.Field MONTH
234         = new Field("month", Calendar.MONTH);
235     public static final DateFormat.Field DAY_OF_MONTH
236         = new Field("day of month", Calendar.DAY_OF_MONTH);
237     public static final DateFormat.Field HOUR_OF_DAY1
238         = new Field("hour of day 1", Calendar.HOUR_OF_DAY);
239     public static final DateFormat.Field HOUR_OF_DAY0
240         = new Field("hour of day 0", Calendar.HOUR_OF_DAY);
241     public static final DateFormat.Field MINUTE
242         = new Field("minute", Calendar.MINUTE);
243     public static final DateFormat.Field SECOND
244         = new Field("second", Calendar.SECOND);
245     public static final DateFormat.Field MILLISECOND
246         = new Field("millisecond", Calendar.MILLISECOND);
247     public static final DateFormat.Field DAY_OF_WEEK
248         = new Field("day of week", Calendar.DAY_OF_WEEK);
249     public static final DateFormat.Field DAY_OF_YEAR
250         = new Field("day of year", Calendar.DAY_OF_YEAR);
251     public static final DateFormat.Field DAY_OF_WEEK_IN_MONTH
252         = new Field("day of week in month", Calendar.DAY_OF_WEEK_IN_MONTH);
253     public static final DateFormat.Field WEEK_OF_YEAR
254         = new Field("week of year", Calendar.WEEK_OF_YEAR);
255     public static final DateFormat.Field WEEK_OF_MONTH
256         = new Field("week of month", Calendar.WEEK_OF_MONTH);
257     public static final DateFormat.Field AM_PM
258         = new Field("am/pm", Calendar.AM_PM);
259     public static final DateFormat.Field HOUR1
260         = new Field("hour1", Calendar.HOUR);
261     public static final DateFormat.Field HOUR0
262         = new Field("hour0", Calendar.HOUR);
263     public static final DateFormat.Field TIME_ZONE
264         = new Field("timezone", Calendar.ZONE_OFFSET);
265
266     static final DateFormat.Field[] allFields =
267     {
268       ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY1,
269       HOUR_OF_DAY0, MINUTE, SECOND, MILLISECOND,
270       DAY_OF_WEEK, DAY_OF_YEAR, DAY_OF_WEEK_IN_MONTH,
271       WEEK_OF_YEAR, WEEK_OF_MONTH, AM_PM, HOUR1, HOUR0,
272       TIME_ZONE
273     };
274
275     // For deserialization
276     private Field()
277     {
278       super("");
279     }
280
281     protected Field(String name, int calendarField)
282     {
283       super(name);
284       this.calendarField = calendarField;
285     }
286     
287     public int getCalendarField()
288     {
289       return calendarField;
290     }
291
292     public static Field ofCalendarField(int calendarField)
293     {
294       if (calendarField >= allFields.length || calendarField < 0)
295         throw new IllegalArgumentException("no such calendar field ("
296                                            + calendarField + ")");
297       
298       return allFields[calendarField];
299     }
300     
301     protected Object readResolve() throws InvalidObjectException
302     {
303       String s = getName();
304
305       for (int i=0;i<allFields.length;i++)
306         if (s.equals(allFields[i].getName()))
307           return allFields[i];
308       
309       throw new InvalidObjectException("no such DateFormat field called " + s);
310     }
311   }
312
313   /**
314    * This method initializes a new instance of <code>DateFormat</code>.
315    */
316   protected DateFormat ()
317   {
318   }
319
320   /**
321    * This method tests this object for equality against the specified object.
322    * The two objects will be considered equal if an only if the specified
323    * object:
324    * <P>
325    * <ul>
326    * <li>Is not <code>null</code>.</li>
327    * <li>Is an instance of <code>DateFormat</code>.</li>
328    * <li>Has equal numberFormat field as this object.</li>
329    * <li>Has equal (Calendar) TimeZone rules as this object.</li>
330    * <li>Has equal (Calendar) isLenient results.</li> 
331    * <li>Has equal Calendar first day of week and minimal days in week
332    * values.</li>
333    * </ul>
334    * Note that not all properties of the Calendar are relevant for a
335    * DateFormat. For formatting only the fact whether or not the
336    * TimeZone has the same rules and whether the calendar is lenient
337    * and has the same week rules is compared for this implementation
338    * of equals. Other properties of the Calendar (such as the time)
339    * are not taken into account.
340    *
341    * @param obj The object to test for equality against.
342    * 
343    * @return <code>true</code> if the specified object is equal to this object,
344    * <code>false</code> otherwise.
345    */
346   public boolean equals (Object obj)
347   {
348     if (!(obj instanceof DateFormat))
349       return false;
350
351     DateFormat d = (DateFormat) obj;
352     TimeZone tz = getTimeZone();
353     TimeZone tzd = d.getTimeZone();
354     if (tz.hasSameRules(tzd))
355       if (isLenient() == d.isLenient())
356         {
357           Calendar c = getCalendar();
358           Calendar cd = d.getCalendar();
359           if ((c == null && cd == null)
360               ||
361               (c.getFirstDayOfWeek() == cd.getFirstDayOfWeek()
362                &&
363                c.getMinimalDaysInFirstWeek()
364                == cd.getMinimalDaysInFirstWeek()))
365             return ((numberFormat == null && d.numberFormat == null)
366                     || numberFormat.equals(d.numberFormat));
367         }
368
369     return false;
370   }
371
372   /**
373    * This method returns a copy of this object.
374    *
375    * @return A copy of this object.
376    */
377   public Object clone ()
378   {
379     // We know the superclass just call's Object's generic cloner.
380     return super.clone ();
381   }
382
383   /**
384    * This method formats the specified <code>Object</code> into a date string
385    * and appends it to the specified <code>StringBuffer</code>.
386    * The specified object must be an instance of <code>Number</code> or
387    * <code>Date</code> or an <code>IllegalArgumentException</code> will be
388    * thrown.
389    *
390    * @param obj The <code>Object</code> to format.
391    * @param buf The <code>StringBuffer</code> to append the resultant
392    * <code>String</code> to.
393    * @param pos Is updated to the start and end index of the
394    * specified field.
395    *
396    * @return The <code>StringBuffer</code> supplied on input, with the
397    * formatted date/time appended.
398    */
399   public final StringBuffer format (Object obj,
400                                     StringBuffer buf, FieldPosition pos)
401   {
402     if (obj instanceof Number)
403       obj = new Date(((Number) obj).longValue());
404     else if (! (obj instanceof Date))
405       throw new IllegalArgumentException
406         ("Cannot format given Object as a Date");
407
408     return format ((Date) obj, buf, pos);
409   }
410
411   /**  
412     * Formats the date argument according to the pattern specified. 
413     *
414     * @param date The formatted date.
415     */
416   public final String format (Date date)
417   {
418     StringBuffer sb = new StringBuffer ();
419     format (date, sb, new FieldPosition (MONTH_FIELD));
420     return sb.toString();
421   }
422
423   /**
424    * This method formats a <code>Date</code> into a string and appends it
425    * to the specified <code>StringBuffer</code>.
426    *
427    * @param date The <code>Date</code> value to format.
428    * @param buf The <code>StringBuffer</code> to append the resultant
429    * <code>String</code> to.
430    * @param pos Is updated to the start and end index of the
431    * specified field.
432    *
433    * @return The <code>StringBuffer</code> supplied on input, with the
434    * formatted date/time appended.
435    */
436   public abstract StringBuffer format (Date date,
437                                        StringBuffer buf, FieldPosition pos);
438
439   /**
440    * This method returns a list of available locales supported by this
441    * class.
442    */
443   public static Locale[] getAvailableLocales()
444   {
445     return Locale.getAvailableLocales();
446   }
447
448   /**
449     * This method returns the <code>Calendar</code> object being used by
450     * this object to parse/format datetimes.
451     *
452     * @return The <code>Calendar</code> being used by this object.
453     *
454     * @see java.util.Calendar
455     */
456   public Calendar getCalendar ()
457   {
458     return calendar;
459   }
460
461   private static DateFormat computeInstance (int style, Locale loc,
462                                              boolean use_date, boolean use_time)
463   {
464     return computeInstance (style, style, loc, use_date, use_time);
465   }
466
467   private static DateFormat computeInstance (int dateStyle, int timeStyle,
468                                              Locale loc, boolean use_date,
469                                              boolean use_time)
470     throws MissingResourceException
471   {
472     if (loc.equals(Locale.ROOT))
473       return computeDefault(dateStyle,timeStyle,use_date,use_time);
474
475     ResourceBundle res =
476       ResourceBundle.getBundle("gnu.java.locale.LocaleInformation",
477                                loc, ClassLoader.getSystemClassLoader());
478
479     String pattern = null;
480     if (use_date)
481       {
482         String name, def;
483         switch (dateStyle)
484           {
485           case FULL:
486             name = "fullDateFormat";
487             def = "EEEE MMMM d, yyyy G";
488             break;
489           case LONG:
490             name = "longDateFormat";
491             def = "MMMM d, yyyy";
492             break;
493           case MEDIUM:
494             name = "mediumDateFormat";
495             def = "d-MMM-yy";
496             break;
497           case SHORT:
498             name = "shortDateFormat";
499             def = "M/d/yy";
500             break;
501           default:
502             throw new IllegalArgumentException ();
503           }
504         try
505           {
506             pattern = res == null ? def : res.getString(name);
507           }
508         catch (MissingResourceException x)
509           {
510             pattern = def;
511           }
512       }
513
514     if (use_time)
515       {
516         if (pattern == null)
517           pattern = "";
518         else
519           pattern += " ";
520
521         String name, def;
522         switch (timeStyle)
523           {
524           case FULL:
525             name = "fullTimeFormat";
526             def = "h:mm:ss;S 'o''clock' a z";
527             break;
528           case LONG:
529             name = "longTimeFormat";
530             def = "h:mm:ss a z";
531             break;
532           case MEDIUM:
533             name = "mediumTimeFormat";
534             def = "h:mm:ss a";
535             break;
536           case SHORT:
537             name = "shortTimeFormat";
538             def = "h:mm a";
539             break;
540           default:
541             throw new IllegalArgumentException ();
542           }
543
544         String s;
545         try
546           {
547             s = res == null ? def : res.getString(name);
548           }
549         catch (MissingResourceException x)
550           {
551             s = def;
552           }
553         pattern += s;
554       }
555
556     return new SimpleDateFormat (pattern, loc);
557   }
558
559   private static DateFormat computeDefault (int dateStyle, int timeStyle,
560                                             boolean use_date, boolean use_time)
561   {
562     String pattern = null;
563     if (use_date)
564       {
565         switch (dateStyle)
566           {
567           case FULL:
568             pattern = "EEEE MMMM d, yyyy G";
569             break;
570           case LONG:
571             pattern = "MMMM d, yyyy";
572             break;
573           case MEDIUM:
574             pattern = "d-MMM-yy";
575             break;
576           case SHORT:
577             pattern = "M/d/yy";
578           default:
579             throw new IllegalArgumentException ();
580           }
581       }
582     
583     if (use_time)
584       {
585         if (pattern == null)
586           pattern = "";
587         else
588           pattern += " ";
589
590         switch (timeStyle)
591           {
592           case FULL:
593             pattern += "h:mm:ss;S 'o''clock' a z";
594             break;
595           case LONG:
596             pattern += "h:mm:ss a z";
597             break;
598           case MEDIUM:
599             pattern += "h:mm:ss a";
600             break;
601           case SHORT:
602             pattern += "h:mm a";
603             break;
604           default:
605             throw new IllegalArgumentException ();
606           }
607       }
608
609     return new SimpleDateFormat (pattern, Locale.ROOT);
610   }
611
612  /**
613    * This method returns an instance of <code>DateFormat</code> that will
614    * format using the default formatting style for dates.
615    *
616    * @return A new <code>DateFormat</code> instance.
617    */
618   public static final DateFormat getDateInstance ()
619   {
620     return getDateInstance (DEFAULT, Locale.getDefault());
621   }
622
623   /**
624    * This method returns an instance of <code>DateFormat</code> that will
625    * format using the specified formatting style for dates.
626    *
627    * @param style The type of formatting to perform. 
628    * 
629    * @return A new <code>DateFormat</code> instance.
630    */
631   public static final DateFormat getDateInstance (int style)
632   {
633     return getDateInstance (style, Locale.getDefault());
634   }
635
636   /**
637    * This method returns an instance of <code>DateFormat</code> that will
638    * format using the specified formatting style for dates.  The specified
639    * localed will be used in place of the default.
640    *
641    * @param style The type of formatting to perform. 
642    * @param loc The desired locale.
643    * 
644    * @return A new <code>DateFormat</code> instance.
645    */
646   public static final DateFormat getDateInstance (int style, Locale loc)
647   {
648     try
649       {
650         return computeInstance (style, loc, true, false);
651       }
652     catch (MissingResourceException e)
653       {
654         for (DateFormatProvider p :
655                ServiceLoader.load(DateFormatProvider.class))
656           {
657             for (Locale l : p.getAvailableLocales())
658               {
659                 if (l.equals(loc))
660                   {
661                     DateFormat df = p.getDateInstance(style, loc);
662                     if (df != null)
663                       return df;
664                     break;
665                   }
666               }
667           }
668         return getDateInstance(style,
669                                LocaleHelper.getFallbackLocale(loc));
670       }
671   }
672
673   /**
674    * This method returns a new instance of <code>DateFormat</code> that
675    * formats both dates and times using the <code>SHORT</code> style.
676    *
677    * @return A new <code>DateFormat</code>instance.
678    */
679   public static final DateFormat getDateTimeInstance ()
680   {
681     return getDateTimeInstance (DEFAULT, DEFAULT, Locale.getDefault());
682   }
683
684   /**
685    * This method returns a new instance of <code>DateFormat</code> that
686    * formats both dates and times using the <code>DEFAULT</code> style.
687    *
688    * @return A new <code>DateFormat</code>instance.
689    */
690   public static final DateFormat getDateTimeInstance (int dateStyle, 
691                                                       int timeStyle)
692   {
693     return getDateTimeInstance (dateStyle, timeStyle, Locale.getDefault());
694   }
695
696   /**
697    * This method returns a new instance of <code>DateFormat</code> that
698    * formats both dates and times using the specified styles.
699    * 
700    * @param dateStyle The desired style for date formatting.
701    * @param timeStyle The desired style for time formatting
702    *
703    * @return A new <code>DateFormat</code>instance.
704    */
705   public static final DateFormat getDateTimeInstance (int dateStyle, 
706                                                       int timeStyle, 
707                                                       Locale loc)
708   {
709     try
710       {
711         return computeInstance (dateStyle, timeStyle, loc, true, true);
712       }
713     catch (MissingResourceException e)
714       {
715         for (DateFormatProvider p :
716                ServiceLoader.load(DateFormatProvider.class))
717           {
718             for (Locale l : p.getAvailableLocales())
719               {
720                 if (l.equals(loc))
721                   {
722                     DateFormat df = p.getDateTimeInstance(dateStyle,
723                                                           timeStyle, loc);
724                     if (df != null)
725                       return df;
726                     break;
727                   }
728               }
729           }
730         return getDateTimeInstance(dateStyle, timeStyle,
731                                    LocaleHelper.getFallbackLocale(loc));
732       }
733   }
734
735   /**
736    * This method returns a new instance of <code>DateFormat</code> that
737    * formats both dates and times using the <code>SHORT</code> style.
738    *
739    * @return A new <code>DateFormat</code>instance.
740    */
741   public static final DateFormat getInstance ()
742   {
743     // JCL book says SHORT.
744     return getDateTimeInstance (SHORT, SHORT, Locale.getDefault());
745   }
746
747   /**
748    * This method returns the <code>NumberFormat</code> object being used
749    * by this object to parse/format time values.
750    *
751    * @return The <code>NumberFormat</code> in use by this object.
752    */
753   public NumberFormat getNumberFormat ()
754   {
755     return numberFormat;
756   }
757
758  /**
759    * This method returns an instance of <code>DateFormat</code> that will
760    * format using the default formatting style for times.
761    *
762    * @return A new <code>DateFormat</code> instance.
763    */
764   public static final DateFormat getTimeInstance ()
765   {
766     return getTimeInstance (DEFAULT, Locale.getDefault());
767   }
768
769   /**
770    * This method returns an instance of <code>DateFormat</code> that will
771    * format using the specified formatting style for times.
772    *
773    * @param style The type of formatting to perform. 
774    * 
775    * @return A new <code>DateFormat</code> instance.
776    */
777   public static final DateFormat getTimeInstance (int style)
778   {
779     return getTimeInstance (style, Locale.getDefault());
780   }
781
782   /**
783    * This method returns an instance of <code>DateFormat</code> that will
784    * format using the specified formatting style for times.  The specified
785    * localed will be used in place of the default.
786    *
787    * @param style The type of formatting to perform. 
788    * @param loc The desired locale.
789    * 
790    * @return A new <code>DateFormat</code> instance.
791    */
792   public static final DateFormat getTimeInstance (int style, Locale loc)
793   {
794     try
795       {
796         return computeInstance (style, loc, false, true);
797       }
798     catch (MissingResourceException e)
799       {
800         for (DateFormatProvider p :
801                ServiceLoader.load(DateFormatProvider.class))
802           {
803             for (Locale l : p.getAvailableLocales())
804               {
805                 if (l.equals(loc))
806                   {
807                     DateFormat df = p.getTimeInstance(style, loc);
808                     if (df != null)
809                       return df;
810                     break;
811                   }
812               }
813           }
814         return getTimeInstance(style,
815                                LocaleHelper.getFallbackLocale(loc));
816       }
817   }
818
819   /**
820    * This method returns the <code>TimeZone</code> object being used by
821    * this instance.
822    *
823    * @return The time zone in use.
824    */
825   public TimeZone getTimeZone ()
826   {
827     return calendar.getTimeZone();
828   }
829
830   /**
831    * This method returns a hash value for this object.
832    * 
833    * @return A hash value for this object.
834    */
835   public int hashCode ()
836   {
837     if (numberFormat != null)
838       return numberFormat.hashCode();
839     else
840       return 0;
841   }
842
843   /**
844    * This method indicates whether or not the parsing of date and time
845    * values should be done in a lenient value.
846    *
847    * @return <code>true</code> if date/time parsing is lenient,
848    * <code>false</code> otherwise.
849    */
850   public boolean isLenient ()
851   {
852     return calendar.isLenient();
853   }
854
855   /**
856    * This method parses the specified date/time string.
857    *
858    * @param source The string to parse.
859    * @return The resultant date.
860    *
861    * @exception ParseException If the specified string cannot be parsed.
862    */
863   public Date parse (String source) throws ParseException
864   {
865     ParsePosition pos = new ParsePosition(0);
866     Date result = parse (source, pos);
867     if (result == null)
868       {
869         int index = pos.getErrorIndex();
870         if (index < 0)
871           index = pos.getIndex();
872         throw new ParseException("invalid Date syntax in \""
873                                  + source + '\"', index);
874       }
875     return result;
876   }
877
878   /** 
879    * This method parses the specified <code>String</code> into a 
880    * <code>Date</code>.  The <code>pos</code> argument contains the
881    * starting parse position on method entry and the ending parse
882    * position on method exit.
883    *
884    * @param source The string to parse.
885    * @param pos The starting parse position in entry, the ending parse
886    * position on exit.
887    *
888    * @return The parsed date, or <code>null</code> if the string cannot
889    * be parsed.
890    */
891   public abstract Date parse (String source, ParsePosition pos);
892
893   /**
894    * This method is identical to <code>parse(String, ParsePosition)</code>,
895    * but returns its result as an <code>Object</code> instead of a
896    * <code>Date</code>.
897    * 
898    * @param source The string to parse.
899    * @param pos The starting parse position in entry, the ending parse
900    * position on exit.
901    *
902    * @return The parsed date, or <code>null</code> if the string cannot
903    * be parsed.
904    */
905   public Object parseObject (String source, ParsePosition pos)
906   {
907     return parse(source, pos);
908   }
909
910   /**
911    * This method specified the <code>Calendar</code> that should be used 
912    * by this object to parse/format datetimes.
913    *
914    * @param calendar The new <code>Calendar</code> for this object.
915    *
916    * @see java.util.Calendar
917    */
918   public void setCalendar (Calendar calendar)
919   {
920     this.calendar = calendar;
921   }
922
923   /**
924    * This method specifies whether or not this object should be lenient in 
925    * the syntax it accepts while parsing date/time values.
926    *
927    * @param lenient <code>true</code> if parsing should be lenient,
928    * <code>false</code> otherwise.
929    */
930   public void setLenient (boolean lenient)
931   {
932     calendar.setLenient(lenient);
933   }
934
935   /**
936    * This method specifies the <code>NumberFormat</code> object that should
937    * be used by this object to parse/format times.
938    *
939    * @param numberFormat The <code>NumberFormat</code> in use by this object.
940    */
941   public void setNumberFormat (NumberFormat numberFormat)
942   {
943     this.numberFormat = numberFormat;
944   }
945
946   /**
947    * This method sets the time zone that should be used by this object.
948    *
949    * @param timeZone The new time zone.
950    */
951   public void setTimeZone (TimeZone timeZone)
952   {
953     calendar.setTimeZone(timeZone);
954   }
955 }