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