Source for java.text.DateFormat

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