001 /* DateFormat.java -- Class for formatting/parsing date/times 002 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005 003 Free Software Foundation, Inc. 004 005 This file is part of GNU Classpath. 006 007 GNU Classpath is free software; you can redistribute it and/or modify 008 it under the terms of the GNU General Public License as published by 009 the Free Software Foundation; either version 2, or (at your option) 010 any later version. 011 012 GNU Classpath is distributed in the hope that it will be useful, but 013 WITHOUT ANY WARRANTY; without even the implied warranty of 014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 General Public License for more details. 016 017 You should have received a copy of the GNU General Public License 018 along with GNU Classpath; see the file COPYING. If not, write to the 019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 020 02110-1301 USA. 021 022 Linking this library statically or dynamically with other modules is 023 making a combined work based on this library. Thus, the terms and 024 conditions of the GNU General Public License cover the whole 025 combination. 026 027 As a special exception, the copyright holders of this library give you 028 permission to link this library with independent modules to produce an 029 executable, regardless of the license terms of these independent 030 modules, and to copy and distribute the resulting executable under 031 terms of your choice, provided that you also meet, for each linked 032 independent module, the terms and conditions of the license of that 033 module. An independent module is a module which is not derived from 034 or based on this library. If you modify this library, you may extend 035 this exception to your version of the library, but you are not 036 obligated to do so. If you do not wish to do so, delete this 037 exception statement from your version. */ 038 039 040 package java.text; 041 042 import gnu.java.locale.LocaleHelper; 043 044 import java.text.spi.DateFormatProvider; 045 046 import java.io.InvalidObjectException; 047 import java.util.Calendar; 048 import java.util.Date; 049 import java.util.Locale; 050 import java.util.MissingResourceException; 051 import java.util.ResourceBundle; 052 import java.util.ServiceLoader; 053 import java.util.TimeZone; 054 055 /** 056 * @author Per Bothner (bothner@cygnus.com) 057 * @date October 25, 1998. 058 */ 059 /* Written using "Java Class Libraries", 2nd edition, plus online 060 * API docs for JDK 1.2 beta from http://www.javasoft.com. 061 * Status: Mostly complete; search for FIXME to see omissions. 062 */ 063 064 public abstract class DateFormat extends Format implements Cloneable 065 { 066 private static final long serialVersionUID = 7218322306649953788L; 067 068 // Names fixed by serialization spec. 069 protected Calendar calendar; 070 protected NumberFormat numberFormat; 071 072 // (Values determined using a test program.) 073 public static final int FULL = 0; 074 public static final int LONG = 1; 075 public static final int MEDIUM = 2; 076 public static final int SHORT = 3; 077 public static final int DEFAULT = MEDIUM; 078 079 /* These constants need to have these exact values. They 080 * correspond to index positions within the localPatternChars 081 * string for a given locale. Each locale may specify its 082 * own character for a particular field, but the position 083 * of these characters must correspond to an appropriate field 084 * number (as listed below), in order for their meaning to 085 * be determined. For example, the US locale uses 086 * the string "GyMdkHmsSEDFwWahKzYeugAZ", where 'G' is the character 087 * for era, 'y' for year, and so on down to 'Z' for time zone. 088 */ 089 /** 090 * Represents the position of the era 091 * pattern character in the array of 092 * localized pattern characters. 093 * For example, 'AD' is an era used 094 * in the Gregorian calendar system. 095 * In the U.S. locale, this is 'G'. 096 */ 097 public static final int ERA_FIELD = 0; 098 /** 099 * 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 * Represents the position of the ISO year 224 * pattern character in the array of 225 * localized pattern characters. 226 * In the U.S. locale, this is 'Y'. 227 * This is a GNU extension in accordance with 228 * the CLDR data used. This value may 229 * differ from the normal year value. 230 */ 231 public static final int ISO_YEAR_FIELD = 18; 232 /** 233 * Represents the position of the localized 234 * day of the week pattern character in the 235 * array of localized pattern characters. 236 * In the U.S. locale, this is 'e'. 237 * This is a GNU extension in accordance with 238 * the CLDR data used. This value only 239 * differs from the day of the week with 240 * numeric formatting, in which case the 241 * locale's first day of the week is used. 242 */ 243 public static final int LOCALIZED_DAY_OF_WEEK_FIELD = 19; 244 /** 245 * Represents the position of the extended year 246 * pattern character in the array of 247 * localized pattern characters. 248 * In the U.S. locale, this is 'u'. 249 * This is a GNU extension in accordance with 250 * the CLDR data used. This value modifies 251 * the year value, so as to incorporate the era. 252 * For example, in the Gregorian calendar system, 253 * the extended year is negative instead of being 254 * marked as BC. 255 */ 256 public static final int EXTENDED_YEAR_FIELD = 20; 257 /** 258 * Represents the position of the modified Julian 259 * day pattern character in the array of 260 * localized pattern characters. 261 * In the U.S. locale, this is 'g'. 262 * This is a GNU extension in accordance with 263 * the CLDR data used. This value differs 264 * from the standard Julian day in that days 265 * are marked from midnight onwards rather than 266 * noon, and the local time zone affects the value. 267 * In simple terms, it can be thought of as all 268 * the date fields represented as a single number. 269 */ 270 public static final int MODIFIED_JULIAN_DAY_FIELD = 21; 271 /** 272 * Represents the position of the millisecond 273 * in the day pattern character in the array of 274 * localized pattern characters. 275 * In the U.S. locale, this is 'A'. 276 * This is a GNU extension in accordance with 277 * the CLDR data used. This value represents 278 * all the time fields (excluding the time zone) 279 * numerically, giving the number of milliseconds 280 * into the day (e.g. 10 in the morning would 281 * be 10 * 60 * 60 * 1000). Any daylight savings 282 * offset also affects this value. 283 */ 284 public static final int MILLISECOND_IN_DAY_FIELD = 22; 285 /** 286 * Represents the position of the RFC822 287 * timezone pattern character in the array of 288 * localized pattern characters. 289 * In the U.S. locale, this is 'Z'. 290 * This is a GNU extension in accordance with 291 * the CLDR data used. The value is the offset 292 * of the current time from GMT e.g. -0500 would 293 * be five hours prior to GMT. 294 */ 295 public static final int RFC822_TIMEZONE_FIELD = 23; 296 297 public static class Field extends Format.Field 298 { 299 static final long serialVersionUID = 7441350119349544720L; 300 301 private int calendarField; 302 303 public static final DateFormat.Field ERA 304 = new Field("era", Calendar.ERA); 305 public static final DateFormat.Field YEAR 306 = new Field("year", Calendar.YEAR); 307 public static final DateFormat.Field MONTH 308 = new Field("month", Calendar.MONTH); 309 public static final DateFormat.Field DAY_OF_MONTH 310 = new Field("day of month", Calendar.DAY_OF_MONTH); 311 public static final DateFormat.Field HOUR_OF_DAY1 312 = new Field("hour of day 1", Calendar.HOUR_OF_DAY); 313 public static final DateFormat.Field HOUR_OF_DAY0 314 = new Field("hour of day 0", Calendar.HOUR_OF_DAY); 315 public static final DateFormat.Field MINUTE 316 = new Field("minute", Calendar.MINUTE); 317 public static final DateFormat.Field SECOND 318 = new Field("second", Calendar.SECOND); 319 public static final DateFormat.Field MILLISECOND 320 = new Field("millisecond", Calendar.MILLISECOND); 321 public static final DateFormat.Field DAY_OF_WEEK 322 = new Field("day of week", Calendar.DAY_OF_WEEK); 323 public static final DateFormat.Field DAY_OF_YEAR 324 = new Field("day of year", Calendar.DAY_OF_YEAR); 325 public static final DateFormat.Field DAY_OF_WEEK_IN_MONTH 326 = new Field("day of week in month", Calendar.DAY_OF_WEEK_IN_MONTH); 327 public static final DateFormat.Field WEEK_OF_YEAR 328 = new Field("week of year", Calendar.WEEK_OF_YEAR); 329 public static final DateFormat.Field WEEK_OF_MONTH 330 = new Field("week of month", Calendar.WEEK_OF_MONTH); 331 public static final DateFormat.Field AM_PM 332 = new Field("am/pm", Calendar.AM_PM); 333 public static final DateFormat.Field HOUR1 334 = new Field("hour1", Calendar.HOUR); 335 public static final DateFormat.Field HOUR0 336 = new Field("hour0", Calendar.HOUR); 337 public static final DateFormat.Field TIME_ZONE 338 = new Field("timezone", Calendar.ZONE_OFFSET); 339 public static final DateFormat.Field ISO_YEAR 340 = new Field("iso year", Calendar.YEAR); 341 public static final DateFormat.Field LOCALIZED_DAY_OF_WEEK 342 = new Field("localized day of week", Calendar.DAY_OF_WEEK); 343 public static final DateFormat.Field EXTENDED_YEAR 344 = new Field("extended year", Calendar.YEAR); 345 public static final DateFormat.Field MODIFIED_JULIAN_DAY 346 = new Field("julian day", -1); 347 public static final DateFormat.Field MILLISECOND_IN_DAY 348 = new Field("millisecond in day", -1); 349 public static final DateFormat.Field RFC822_TIME_ZONE 350 = new Field("rfc822 timezone", Calendar.ZONE_OFFSET); 351 352 static final DateFormat.Field[] allFields = 353 { 354 ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY1, 355 HOUR_OF_DAY0, MINUTE, SECOND, MILLISECOND, 356 DAY_OF_WEEK, DAY_OF_YEAR, DAY_OF_WEEK_IN_MONTH, 357 WEEK_OF_YEAR, WEEK_OF_MONTH, AM_PM, HOUR1, HOUR0, 358 TIME_ZONE, ISO_YEAR, LOCALIZED_DAY_OF_WEEK, 359 EXTENDED_YEAR, MODIFIED_JULIAN_DAY, MILLISECOND_IN_DAY, 360 RFC822_TIME_ZONE 361 }; 362 363 // For deserialization 364 private Field() 365 { 366 super(""); 367 } 368 369 protected Field(String name, int calendarField) 370 { 371 super(name); 372 this.calendarField = calendarField; 373 } 374 375 public int getCalendarField() 376 { 377 return calendarField; 378 } 379 380 public static Field ofCalendarField(int calendarField) 381 { 382 if (calendarField >= allFields.length || calendarField < 0) 383 throw new IllegalArgumentException("no such calendar field (" 384 + calendarField + ")"); 385 386 return allFields[calendarField]; 387 } 388 389 protected Object readResolve() throws InvalidObjectException 390 { 391 String s = getName(); 392 393 for (int i=0;i<allFields.length;i++) 394 if (s.equals(allFields[i].getName())) 395 return allFields[i]; 396 397 throw new InvalidObjectException("no such DateFormat field called " + s); 398 } 399 } 400 401 /** 402 * This method initializes a new instance of <code>DateFormat</code>. 403 */ 404 protected DateFormat () 405 { 406 } 407 408 /** 409 * This method tests this object for equality against the specified object. 410 * The two objects will be considered equal if an only if the specified 411 * object: 412 * <P> 413 * <ul> 414 * <li>Is not <code>null</code>.</li> 415 * <li>Is an instance of <code>DateFormat</code>.</li> 416 * <li>Has equal numberFormat field as this object.</li> 417 * <li>Has equal (Calendar) TimeZone rules as this object.</li> 418 * <li>Has equal (Calendar) isLenient results.</li> 419 * <li>Has equal Calendar first day of week and minimal days in week 420 * values.</li> 421 * </ul> 422 * Note that not all properties of the Calendar are relevant for a 423 * DateFormat. For formatting only the fact whether or not the 424 * TimeZone has the same rules and whether the calendar is lenient 425 * and has the same week rules is compared for this implementation 426 * of equals. Other properties of the Calendar (such as the time) 427 * are not taken into account. 428 * 429 * @param obj The object to test for equality against. 430 * 431 * @return <code>true</code> if the specified object is equal to this object, 432 * <code>false</code> otherwise. 433 */ 434 public boolean equals (Object obj) 435 { 436 if (!(obj instanceof DateFormat)) 437 return false; 438 439 DateFormat d = (DateFormat) obj; 440 TimeZone tz = getTimeZone(); 441 TimeZone tzd = d.getTimeZone(); 442 if (tz.hasSameRules(tzd)) 443 if (isLenient() == d.isLenient()) 444 { 445 Calendar c = getCalendar(); 446 Calendar cd = d.getCalendar(); 447 if ((c == null && cd == null) 448 || 449 (c.getFirstDayOfWeek() == cd.getFirstDayOfWeek() 450 && 451 c.getMinimalDaysInFirstWeek() 452 == cd.getMinimalDaysInFirstWeek())) 453 return ((numberFormat == null && d.numberFormat == null) 454 || numberFormat.equals(d.numberFormat)); 455 } 456 457 return false; 458 } 459 460 /** 461 * This method returns a copy of this object. 462 * 463 * @return A copy of this object. 464 */ 465 public Object clone () 466 { 467 // We know the superclass just call's Object's generic cloner. 468 return super.clone (); 469 } 470 471 /** 472 * This method formats the specified <code>Object</code> into a date string 473 * and appends it to the specified <code>StringBuffer</code>. 474 * The specified object must be an instance of <code>Number</code> or 475 * <code>Date</code> or an <code>IllegalArgumentException</code> will be 476 * thrown. 477 * 478 * @param obj The <code>Object</code> to format. 479 * @param buf The <code>StringBuffer</code> to append the resultant 480 * <code>String</code> to. 481 * @param pos Is updated to the start and end index of the 482 * specified field. 483 * 484 * @return The <code>StringBuffer</code> supplied on input, with the 485 * formatted date/time appended. 486 */ 487 public final StringBuffer format (Object obj, 488 StringBuffer buf, FieldPosition pos) 489 { 490 if (obj instanceof Number) 491 obj = new Date(((Number) obj).longValue()); 492 else if (! (obj instanceof Date)) 493 throw new IllegalArgumentException 494 ("Cannot format given Object as a Date"); 495 496 return format ((Date) obj, buf, pos); 497 } 498 499 /** 500 * Formats the date argument according to the pattern specified. 501 * 502 * @param date The formatted date. 503 */ 504 public final String format (Date date) 505 { 506 StringBuffer sb = new StringBuffer (); 507 format (date, sb, new FieldPosition (MONTH_FIELD)); 508 return sb.toString(); 509 } 510 511 /** 512 * This method formats a <code>Date</code> into a string and appends it 513 * to the specified <code>StringBuffer</code>. 514 * 515 * @param date The <code>Date</code> value to format. 516 * @param buf The <code>StringBuffer</code> to append the resultant 517 * <code>String</code> to. 518 * @param pos Is updated to the start and end index of the 519 * specified field. 520 * 521 * @return The <code>StringBuffer</code> supplied on input, with the 522 * formatted date/time appended. 523 */ 524 public abstract StringBuffer format (Date date, 525 StringBuffer buf, FieldPosition pos); 526 527 /** 528 * This method returns a list of available locales supported by this 529 * class. 530 */ 531 public static Locale[] getAvailableLocales() 532 { 533 return Locale.getAvailableLocales(); 534 } 535 536 /** 537 * This method returns the <code>Calendar</code> object being used by 538 * this object to parse/format datetimes. 539 * 540 * @return The <code>Calendar</code> being used by this object. 541 * 542 * @see java.util.Calendar 543 */ 544 public Calendar getCalendar () 545 { 546 return calendar; 547 } 548 549 private static DateFormat computeInstance (int style, Locale loc, 550 boolean use_date, boolean use_time) 551 { 552 return computeInstance (style, style, loc, use_date, use_time); 553 } 554 555 private static DateFormat computeInstance (int dateStyle, int timeStyle, 556 Locale loc, boolean use_date, 557 boolean use_time) 558 throws MissingResourceException 559 { 560 if (loc.equals(Locale.ROOT)) 561 return computeDefault(dateStyle,timeStyle,use_date,use_time); 562 563 ResourceBundle res = 564 ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 565 loc, ClassLoader.getSystemClassLoader()); 566 567 String pattern = null; 568 if (use_date) 569 { 570 String name, def; 571 switch (dateStyle) 572 { 573 case FULL: 574 name = "fullDateFormat"; 575 def = "EEEE MMMM d, yyyy G"; 576 break; 577 case LONG: 578 name = "longDateFormat"; 579 def = "MMMM d, yyyy"; 580 break; 581 case MEDIUM: 582 name = "mediumDateFormat"; 583 def = "d-MMM-yy"; 584 break; 585 case SHORT: 586 name = "shortDateFormat"; 587 def = "M/d/yy"; 588 break; 589 default: 590 throw new IllegalArgumentException (); 591 } 592 try 593 { 594 pattern = res == null ? def : res.getString(name); 595 } 596 catch (MissingResourceException x) 597 { 598 pattern = def; 599 } 600 } 601 602 if (use_time) 603 { 604 if (pattern == null) 605 pattern = ""; 606 else 607 pattern += " "; 608 609 String name, def; 610 switch (timeStyle) 611 { 612 case FULL: 613 name = "fullTimeFormat"; 614 def = "h:mm:ss;S 'o''clock' a z"; 615 break; 616 case LONG: 617 name = "longTimeFormat"; 618 def = "h:mm:ss a z"; 619 break; 620 case MEDIUM: 621 name = "mediumTimeFormat"; 622 def = "h:mm:ss a"; 623 break; 624 case SHORT: 625 name = "shortTimeFormat"; 626 def = "h:mm a"; 627 break; 628 default: 629 throw new IllegalArgumentException (); 630 } 631 632 String s; 633 try 634 { 635 s = res == null ? def : res.getString(name); 636 } 637 catch (MissingResourceException x) 638 { 639 s = def; 640 } 641 pattern += s; 642 } 643 644 return new SimpleDateFormat (pattern, loc); 645 } 646 647 private static DateFormat computeDefault (int dateStyle, int timeStyle, 648 boolean use_date, boolean use_time) 649 { 650 String pattern = null; 651 if (use_date) 652 { 653 switch (dateStyle) 654 { 655 case FULL: 656 pattern = "EEEE MMMM d, yyyy G"; 657 break; 658 case LONG: 659 pattern = "MMMM d, yyyy"; 660 break; 661 case MEDIUM: 662 pattern = "d-MMM-yy"; 663 break; 664 case SHORT: 665 pattern = "M/d/yy"; 666 default: 667 throw new IllegalArgumentException (); 668 } 669 } 670 671 if (use_time) 672 { 673 if (pattern == null) 674 pattern = ""; 675 else 676 pattern += " "; 677 678 switch (timeStyle) 679 { 680 case FULL: 681 pattern += "h:mm:ss;S 'o''clock' a z"; 682 break; 683 case LONG: 684 pattern += "h:mm:ss a z"; 685 break; 686 case MEDIUM: 687 pattern += "h:mm:ss a"; 688 break; 689 case SHORT: 690 pattern += "h:mm a"; 691 break; 692 default: 693 throw new IllegalArgumentException (); 694 } 695 } 696 697 return new SimpleDateFormat (pattern, Locale.ROOT); 698 } 699 700 /** 701 * This method returns an instance of <code>DateFormat</code> that will 702 * format using the default formatting style for dates. 703 * 704 * @return A new <code>DateFormat</code> instance. 705 */ 706 public static final DateFormat getDateInstance () 707 { 708 return getDateInstance (DEFAULT, Locale.getDefault()); 709 } 710 711 /** 712 * This method returns an instance of <code>DateFormat</code> that will 713 * format using the specified formatting style for dates. 714 * 715 * @param style The type of formatting to perform. 716 * 717 * @return A new <code>DateFormat</code> instance. 718 */ 719 public static final DateFormat getDateInstance (int style) 720 { 721 return getDateInstance (style, Locale.getDefault()); 722 } 723 724 /** 725 * This method returns an instance of <code>DateFormat</code> that will 726 * format using the specified formatting style for dates. The specified 727 * localed will be used in place of the default. 728 * 729 * @param style The type of formatting to perform. 730 * @param loc The desired locale. 731 * 732 * @return A new <code>DateFormat</code> instance. 733 */ 734 public static final DateFormat getDateInstance (int style, Locale loc) 735 { 736 try 737 { 738 return computeInstance (style, loc, true, false); 739 } 740 catch (MissingResourceException e) 741 { 742 for (DateFormatProvider p : 743 ServiceLoader.load(DateFormatProvider.class)) 744 { 745 for (Locale l : p.getAvailableLocales()) 746 { 747 if (l.equals(loc)) 748 { 749 DateFormat df = p.getDateInstance(style, loc); 750 if (df != null) 751 return df; 752 break; 753 } 754 } 755 } 756 return getDateInstance(style, 757 LocaleHelper.getFallbackLocale(loc)); 758 } 759 } 760 761 /** 762 * This method returns a new instance of <code>DateFormat</code> that 763 * formats both dates and times using the <code>SHORT</code> style. 764 * 765 * @return A new <code>DateFormat</code>instance. 766 */ 767 public static final DateFormat getDateTimeInstance () 768 { 769 return getDateTimeInstance (DEFAULT, DEFAULT, Locale.getDefault()); 770 } 771 772 /** 773 * This method returns a new instance of <code>DateFormat</code> that 774 * formats both dates and times using the <code>DEFAULT</code> style. 775 * 776 * @return A new <code>DateFormat</code>instance. 777 */ 778 public static final DateFormat getDateTimeInstance (int dateStyle, 779 int timeStyle) 780 { 781 return getDateTimeInstance (dateStyle, timeStyle, Locale.getDefault()); 782 } 783 784 /** 785 * This method returns a new instance of <code>DateFormat</code> that 786 * formats both dates and times using the specified styles. 787 * 788 * @param dateStyle The desired style for date formatting. 789 * @param timeStyle The desired style for time formatting 790 * 791 * @return A new <code>DateFormat</code>instance. 792 */ 793 public static final DateFormat getDateTimeInstance (int dateStyle, 794 int timeStyle, 795 Locale loc) 796 { 797 try 798 { 799 return computeInstance (dateStyle, timeStyle, loc, true, true); 800 } 801 catch (MissingResourceException e) 802 { 803 for (DateFormatProvider p : 804 ServiceLoader.load(DateFormatProvider.class)) 805 { 806 for (Locale l : p.getAvailableLocales()) 807 { 808 if (l.equals(loc)) 809 { 810 DateFormat df = p.getDateTimeInstance(dateStyle, 811 timeStyle, loc); 812 if (df != null) 813 return df; 814 break; 815 } 816 } 817 } 818 return getDateTimeInstance(dateStyle, timeStyle, 819 LocaleHelper.getFallbackLocale(loc)); 820 } 821 } 822 823 /** 824 * This method returns a new instance of <code>DateFormat</code> that 825 * formats both dates and times using the <code>SHORT</code> style. 826 * 827 * @return A new <code>DateFormat</code>instance. 828 */ 829 public static final DateFormat getInstance () 830 { 831 // JCL book says SHORT. 832 return getDateTimeInstance (SHORT, SHORT, Locale.getDefault()); 833 } 834 835 /** 836 * This method returns the <code>NumberFormat</code> object being used 837 * by this object to parse/format time values. 838 * 839 * @return The <code>NumberFormat</code> in use by this object. 840 */ 841 public NumberFormat getNumberFormat () 842 { 843 return numberFormat; 844 } 845 846 /** 847 * This method returns an instance of <code>DateFormat</code> that will 848 * format using the default formatting style for times. 849 * 850 * @return A new <code>DateFormat</code> instance. 851 */ 852 public static final DateFormat getTimeInstance () 853 { 854 return getTimeInstance (DEFAULT, Locale.getDefault()); 855 } 856 857 /** 858 * This method returns an instance of <code>DateFormat</code> that will 859 * format using the specified formatting style for times. 860 * 861 * @param style The type of formatting to perform. 862 * 863 * @return A new <code>DateFormat</code> instance. 864 */ 865 public static final DateFormat getTimeInstance (int style) 866 { 867 return getTimeInstance (style, Locale.getDefault()); 868 } 869 870 /** 871 * This method returns an instance of <code>DateFormat</code> that will 872 * format using the specified formatting style for times. The specified 873 * localed will be used in place of the default. 874 * 875 * @param style The type of formatting to perform. 876 * @param loc The desired locale. 877 * 878 * @return A new <code>DateFormat</code> instance. 879 */ 880 public static final DateFormat getTimeInstance (int style, Locale loc) 881 { 882 try 883 { 884 return computeInstance (style, loc, false, true); 885 } 886 catch (MissingResourceException e) 887 { 888 for (DateFormatProvider p : 889 ServiceLoader.load(DateFormatProvider.class)) 890 { 891 for (Locale l : p.getAvailableLocales()) 892 { 893 if (l.equals(loc)) 894 { 895 DateFormat df = p.getTimeInstance(style, loc); 896 if (df != null) 897 return df; 898 break; 899 } 900 } 901 } 902 return getTimeInstance(style, 903 LocaleHelper.getFallbackLocale(loc)); 904 } 905 } 906 907 /** 908 * This method returns the <code>TimeZone</code> object being used by 909 * this instance. 910 * 911 * @return The time zone in use. 912 */ 913 public TimeZone getTimeZone () 914 { 915 return calendar.getTimeZone(); 916 } 917 918 /** 919 * This method returns a hash value for this object. 920 * 921 * @return A hash value for this object. 922 */ 923 public int hashCode () 924 { 925 if (numberFormat != null) 926 return numberFormat.hashCode(); 927 else 928 return 0; 929 } 930 931 /** 932 * This method indicates whether or not the parsing of date and time 933 * values should be done in a lenient value. 934 * 935 * @return <code>true</code> if date/time parsing is lenient, 936 * <code>false</code> otherwise. 937 */ 938 public boolean isLenient () 939 { 940 return calendar.isLenient(); 941 } 942 943 /** 944 * This method parses the specified date/time string. 945 * 946 * @param source The string to parse. 947 * @return The resultant date. 948 * 949 * @exception ParseException If the specified string cannot be parsed. 950 */ 951 public Date parse (String source) throws ParseException 952 { 953 ParsePosition pos = new ParsePosition(0); 954 Date result = parse (source, pos); 955 if (result == null) 956 { 957 int index = pos.getErrorIndex(); 958 if (index < 0) 959 index = pos.getIndex(); 960 throw new ParseException("invalid Date syntax in \"" 961 + source + '\"', index); 962 } 963 return result; 964 } 965 966 /** 967 * This method parses the specified <code>String</code> into a 968 * <code>Date</code>. The <code>pos</code> argument contains the 969 * starting parse position on method entry and the ending parse 970 * position on method exit. 971 * 972 * @param source The string to parse. 973 * @param pos The starting parse position in entry, the ending parse 974 * position on exit. 975 * 976 * @return The parsed date, or <code>null</code> if the string cannot 977 * be parsed. 978 */ 979 public abstract Date parse (String source, ParsePosition pos); 980 981 /** 982 * This method is identical to <code>parse(String, ParsePosition)</code>, 983 * but returns its result as an <code>Object</code> instead of a 984 * <code>Date</code>. 985 * 986 * @param source The string to parse. 987 * @param pos The starting parse position in entry, the ending parse 988 * position on exit. 989 * 990 * @return The parsed date, or <code>null</code> if the string cannot 991 * be parsed. 992 */ 993 public Object parseObject (String source, ParsePosition pos) 994 { 995 return parse(source, pos); 996 } 997 998 /** 999 * This method specified the <code>Calendar</code> that should be used 1000 * by this object to parse/format datetimes. 1001 * 1002 * @param calendar The new <code>Calendar</code> for this object. 1003 * 1004 * @see java.util.Calendar 1005 */ 1006 public void setCalendar (Calendar calendar) 1007 { 1008 this.calendar = calendar; 1009 } 1010 1011 /** 1012 * This method specifies whether or not this object should be lenient in 1013 * the syntax it accepts while parsing date/time values. 1014 * 1015 * @param lenient <code>true</code> if parsing should be lenient, 1016 * <code>false</code> otherwise. 1017 */ 1018 public void setLenient (boolean lenient) 1019 { 1020 calendar.setLenient(lenient); 1021 } 1022 1023 /** 1024 * This method specifies the <code>NumberFormat</code> object that should 1025 * be used by this object to parse/format times. 1026 * 1027 * @param numberFormat The <code>NumberFormat</code> in use by this object. 1028 */ 1029 public void setNumberFormat (NumberFormat numberFormat) 1030 { 1031 this.numberFormat = numberFormat; 1032 } 1033 1034 /** 1035 * This method sets the time zone that should be used by this object. 1036 * 1037 * @param timeZone The new time zone. 1038 */ 1039 public void setTimeZone (TimeZone timeZone) 1040 { 1041 calendar.setTimeZone(timeZone); 1042 } 1043 }