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