001/* DateFormatSymbols.java -- Format over a range of numbers 002 Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package java.text; 040 041import gnu.java.locale.LocaleHelper; 042 043import java.io.IOException; 044 045import java.text.spi.DateFormatSymbolsProvider; 046 047import java.util.ArrayList; 048import java.util.Arrays; 049import java.util.HashMap; 050import java.util.List; 051import java.util.Locale; 052import java.util.Map; 053import java.util.MissingResourceException; 054import java.util.Properties; 055import java.util.ResourceBundle; 056import java.util.ServiceLoader; 057import java.util.TimeZone; 058 059import java.util.spi.TimeZoneNameProvider; 060 061/** 062 * This class acts as container for locale specific date/time formatting 063 * information such as the days of the week and the months of the year. 064 * 065 * @author Per Bothner (bothner@cygnus.com) 066 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 067 * @date October 24, 1998. 068 */ 069/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3. 070 * Status: Believed complete and correct. 071 */ 072public class DateFormatSymbols implements java.io.Serializable, Cloneable 073{ 074 String[] ampms; 075 String[] eras; 076 private String localPatternChars; 077 String[] months; 078 String[] shortMonths; 079 String[] shortWeekdays; 080 String[] weekdays; 081 082 /** 083 * The set of properties for obtaining the metazone data. 084 */ 085 private static transient final Properties properties; 086 087 /** 088 * Reads in the properties. 089 */ 090 static 091 { 092 properties = new Properties(); 093 try 094 { 095 properties.load(DateFormatSymbols.class.getResourceAsStream("metazones.properties")); 096 } 097 catch (IOException exception) 098 { 099 System.out.println("Failed to load weeks resource: " + exception); 100 } 101 } 102 103 /** 104 * The timezone strings supplied by the runtime. 105 */ 106 private String[][] runtimeZoneStrings; 107 108 /** 109 * Custom timezone strings supplied by {@link #setZoneStrings()}. 110 */ 111 private String[][] zoneStrings; 112 113 private static final long serialVersionUID = -5987973545549424702L; 114 115 // The order of these prefixes must be the same as in DateFormat 116 private static final String[] formatPrefixes = 117 { 118 "full", "long", "medium", "short" 119 }; 120 121 // These are each arrays with a value for SHORT, MEDIUM, LONG, FULL, 122 // and DEFAULT (constants defined in java.text.DateFormat). While 123 // not part of the official spec, we need a way to get at locale-specific 124 // default formatting patterns. They are declared package scope so 125 // as to be easily accessible where needed (DateFormat, SimpleDateFormat). 126 transient String[] dateFormats; 127 transient String[] timeFormats; 128 129 /** 130 * Compiles a string array for a property using data from each of the locales in the 131 * hierarchy as necessary. 132 * 133 * @param bundles the locale hierarchy, starting with the most specific. 134 * @param name the name of the property. 135 * @param size the size the array should be when complete. 136 * @return a completed string array. 137 */ 138 private static String[] getStringArray(List<ResourceBundle> bundles, String name, int size) 139 { 140 return getStringArray(bundles, name, size, null); 141 } 142 143 /** 144 * Compiles a string array for a property using data from each of the locales in the 145 * hierarchy as necessary. If non-null, the fallback array is also used for "sideways" 146 * inheritance (e.g. if there is no short name for a month, the long name is used rather 147 * than the empty string). 148 * 149 * @param bundles the locale hierarchy, starting with the most specific. 150 * @param name the name of the property. 151 * @param size the size the array should be when complete. 152 * @param fallback an array of long name fallback strings for data with both long and short names. 153 * @return a completed string array. 154 */ 155 private static String[] getStringArray(List<ResourceBundle> bundles, String name, int size, 156 String[] fallback) 157 { 158 String[] data = new String[size]; 159 Arrays.fill(data, ""); 160 // Populate array with data from each locale back to the root, starting with the most specific 161 for (int a = 0; a < bundles.size(); ++a) 162 { 163 String localeData = bundles.get(a).getString(name); 164 String[] array = localeData.split("\u00ae", size); 165 for (int b = 0; b < data.length; ++b) 166 { 167 if (array.length > b && array[b] != null && data[b].isEmpty() && !array[b].isEmpty()) 168 data[b] = array[b]; 169 } 170 } 171 // Replace any remaining empty strings with data from the fallback array, if non-null 172 if (fallback != null && fallback.length == size) 173 { 174 for (int a = 0; a < data.length; ++a) 175 { 176 if (data[a].isEmpty() && fallback[a] != null && !fallback[a].isEmpty()) 177 data[a] = fallback[a]; 178 } 179 } 180 return data; 181 } 182 183 private String[][] getZoneStrings(ResourceBundle res, Locale locale) 184 { 185 List<String[]> allZones = new ArrayList<String[]>(); 186 try 187 { 188 Map<String,String[]> systemZones = new HashMap<String,String[]>(); 189 while (true) 190 { 191 int index = 0; 192 String country = locale.getCountry(); 193 String data = res.getString("zoneStrings"); 194 String[] zones = data.split("\u00a9"); 195 for (int a = 0; a < zones.length; ++a) 196 { 197 String[] strings = zones[a].split("\u00ae"); 198 String type = properties.getProperty(strings[0] + "." + country); 199 if (type == null) 200 type = properties.getProperty(strings[0] + ".DEFAULT"); 201 if (type != null) 202 strings[0] = type; 203 if (strings.length < 5) 204 { 205 String[] newStrings = new String[5]; 206 System.arraycopy(strings, 0, newStrings, 0, strings.length); 207 for (int b = strings.length; b < newStrings.length; ++b) 208 newStrings[b] = ""; 209 strings = newStrings; 210 } 211 String[] existing = systemZones.get(strings[0]); 212 if (existing != null && existing.length > 1) 213 { 214 for (int b = 1; b < existing.length; ++b) 215 if (!existing[b].equals("")) 216 strings[b] = existing[b]; 217 } 218 systemZones.put(strings[0], strings); 219 } 220 if (res.getLocale() == Locale.ROOT) 221 break; 222 else 223 res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 224 LocaleHelper.getFallbackLocale(res.getLocale()), 225 ClassLoader.getSystemClassLoader()); 226 } 227 /* Final sanity check for missing values */ 228 for (String[] zstrings : systemZones.values()) 229 { 230 if (zstrings[1].equals("") && zstrings[2].equals("")) 231 { 232 for (Map.Entry<Object,Object> entry : properties.entrySet()) 233 { 234 String val = (String) entry.getValue(); 235 if (val.equals(zstrings[0])) 236 { 237 String key = (String) entry.getKey(); 238 String metazone = key.substring(0, key.indexOf(".")); 239 String type = properties.getProperty(metazone + "." + locale.getCountry()); 240 if (type == null) 241 type = properties.getProperty(metazone + ".DEFAULT"); 242 if (type != null) 243 { 244 String[] ostrings = systemZones.get(type); 245 zstrings[1] = ostrings[1]; 246 zstrings[2] = ostrings[2]; 247 } 248 } 249 } 250 } 251 } 252 allZones.addAll(systemZones.values()); 253 } 254 catch (MissingResourceException e) 255 { 256 /* This means runtime support for the locale 257 * is not available, so we just include providers. */ 258 } 259 for (TimeZoneNameProvider p : 260 ServiceLoader.load(TimeZoneNameProvider.class)) 261 { 262 for (Locale loc : p.getAvailableLocales()) 263 { 264 if (loc.equals(locale)) 265 { 266 for (String id : TimeZone.getAvailableIDs()) 267 { 268 String[] z = new String[5]; 269 z[0] = id; 270 z[1] = p.getDisplayName(id, false, 271 TimeZone.LONG, 272 locale); 273 z[2] = p.getDisplayName(id, false, 274 TimeZone.SHORT, 275 locale); 276 z[3] = p.getDisplayName(id, true, 277 TimeZone.LONG, 278 locale); 279 z[4] = p.getDisplayName(id, true, 280 TimeZone.SHORT, 281 locale); 282 allZones.add(z); 283 } 284 break; 285 } 286 } 287 } 288 return allZones.toArray(new String[allZones.size()][]); 289 } 290 291 private String[] formatsForKey(ResourceBundle res, String key) 292 { 293 String[] values = new String[formatPrefixes.length]; 294 295 for (int i = 0; i < formatPrefixes.length; i++) 296 values[i] = res.getString(formatPrefixes[i] + key); 297 298 return values; 299 } 300 301 /** 302 * This method initializes a new instance of <code>DateFormatSymbols</code> 303 * by loading the date format information for the specified locale. 304 * This constructor only obtains instances using the runtime's resources; 305 * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances, 306 * call {@link #getInstance(java.util.Locale)} instead. 307 * 308 * @param locale The locale for which date formatting symbols should 309 * be loaded. 310 * @throws MissingResourceException if the resources for the specified 311 * locale could not be found or loaded. 312 * @see #getInstance(java.util.Locale) 313 */ 314 public DateFormatSymbols (Locale locale) 315 throws MissingResourceException 316 { 317 ClassLoader ldr = ClassLoader.getSystemClassLoader(); 318 List<ResourceBundle> bundles = new ArrayList<ResourceBundle>(); 319 ResourceBundle res 320 = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, ldr); 321 bundles.add(res); 322 Locale resLocale = res.getLocale(); 323 while (resLocale != Locale.ROOT) 324 { 325 res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", 326 LocaleHelper.getFallbackLocale(resLocale), ldr); 327 bundles.add(res); 328 resLocale = res.getLocale(); 329 } 330 ampms = getStringArray(bundles, "ampms", 2); 331 eras = getStringArray(bundles, "eras", 2); 332 localPatternChars = res.getString("localPatternChars"); 333 months = getStringArray(bundles, "months", 13); 334 shortMonths = getStringArray(bundles, "shortMonths", 13, months); 335 weekdays = getStringArray(bundles, "weekdays", 8); 336 shortWeekdays = getStringArray(bundles, "shortWeekdays", 8, weekdays); 337 dateFormats = formatsForKey(res, "DateFormat"); 338 timeFormats = formatsForKey(res, "TimeFormat"); 339 runtimeZoneStrings = getZoneStrings(res, locale); 340 } 341 342 /** 343 * This method loads the format symbol information for the default 344 * locale. This constructor only obtains instances using the runtime's resources; 345 * to also include {@link java.text.spi.DateFormatSymbolsProvider} instances, 346 * call {@link #getInstance()} instead. 347 * 348 * @throws MissingResourceException if the resources for the default 349 * locale could not be found or loaded. 350 * @see #getInstance() 351 */ 352 public DateFormatSymbols() 353 throws MissingResourceException 354 { 355 this (Locale.getDefault()); 356 } 357 358 /** 359 * This method returns the list of strings used for displaying AM or PM. 360 * This is a two element <code>String</code> array indexed by 361 * <code>Calendar.AM</code> and <code>Calendar.PM</code> 362 * 363 * @return The list of AM/PM display strings. 364 */ 365 public String[] getAmPmStrings() 366 { 367 return ampms; 368 } 369 370 /** 371 * This method returns the list of strings used for displaying eras 372 * (e.g., "BC" and "AD"). This is a two element <code>String</code> 373 * array indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>. 374 * 375 * @return The list of era disply strings. 376 */ 377 public String[] getEras() 378 { 379 return eras; 380 } 381 382 /** 383 * This method returns the pattern character information for this 384 * object. This is an 18 character string that contains the characters 385 * that are used in creating the date formatting strings in 386 * <code>SimpleDateFormat</code>. The following are the character 387 * positions in the string and which format character they correspond 388 * to (the character in parentheses is the default value in the US English 389 * locale): 390 * <p> 391 * <ul> 392 * <li>0 - era (G)</li> 393 * <li>1 - year (y)</li> 394 * <li>2 - month (M)</li> 395 * <li>3 - day of month (d)</li> 396 * <li>4 - hour out of 12, from 1-12 (h)</li> 397 * <li>5 - hour out of 24, from 0-23 (H)</li> 398 * <li>6 - minute (m)</li> 399 * <li>7 - second (s)</li> 400 * <li>8 - millisecond (S)</li> 401 * <li>9 - date of week (E)</li> 402 * <li>10 - date of year (D)</li> 403 * <li>11 - day of week in month, eg. "4th Thur in Nov" (F)</li> 404 * <li>12 - week in year (w)</li> 405 * <li>13 - week in month (W)</li> 406 * <li>14 - am/pm (a)</li> 407 * <li>15 - hour out of 24, from 1-24 (k)</li> 408 * <li>16 - hour out of 12, from 0-11 (K)</li> 409 * <li>17 - time zone (z)</li> 410 * </ul> 411 * 412 * @return The format patter characters 413 */ 414 public String getLocalPatternChars() 415 { 416 return localPatternChars; 417 } 418 419 /** 420 * This method returns the list of strings used for displaying month 421 * names (e.g., "January" and "February"). This is a thirteen element 422 * string array indexed by <code>Calendar.JANUARY</code> through 423 * <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 424 * elements because some calendars have thriteen months. 425 * 426 * @return The list of month display strings. 427 */ 428 public String[] getMonths () 429 { 430 return months; 431 } 432 433 /** 434 * This method returns the list of strings used for displaying abbreviated 435 * month names (e.g., "Jan" and "Feb"). This is a thirteen element 436 * <code>String</code> array indexed by <code>Calendar.JANUARY</code> 437 * through <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 438 * elements because some calendars have thirteen months. 439 * 440 * @return The list of abbreviated month display strings. 441 */ 442 public String[] getShortMonths () 443 { 444 return shortMonths; 445 } 446 447 /** 448 * This method returns the list of strings used for displaying abbreviated 449 * weekday names (e.g., "Sun" and "Mon"). This is an eight element 450 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 451 * through <code>Calendar.SATURDAY</code>. Note that the first element 452 * of this array is ignored. 453 * 454 * @return This list of abbreviated weekday display strings. 455 */ 456 public String[] getShortWeekdays () 457 { 458 return shortWeekdays; 459 } 460 461 /** 462 * This method returns the list of strings used for displaying weekday 463 * names (e.g., "Sunday" and "Monday"). This is an eight element 464 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 465 * through <code>Calendar.SATURDAY</code>. Note that the first element 466 * of this array is ignored. 467 * 468 * @return This list of weekday display strings. 469 */ 470 public String[] getWeekdays () 471 { 472 return weekdays; 473 } 474 475 /** 476 * This method returns this list of localized timezone display strings. 477 * This is a two dimensional <code>String</code> array where each row in 478 * the array contains five values: 479 * <P> 480 * <ul> 481 * <li>0 - The non-localized time zone id string.</li> 482 * <li>1 - The long name of the time zone (standard time).</li> 483 * <li>2 - The short name of the time zone (standard time).</li> 484 * <li>3 - The long name of the time zone (daylight savings time).</li> 485 * <li>4 - the short name of the time zone (daylight savings time).</li> 486 * </ul> 487 * <p> 488 * If {@link #setZoneStrings(String[][])} has been called, then the value 489 * passed to this will be returned. Otherwise the returned array contains 490 * zone names provided by the runtime environment and any 491 * {@link java.util.spi.TimeZoneProvider} instances. 492 * </p> 493 * 494 * @return The list of time zone display strings. 495 * @see #setZoneStrings(String[][]) 496 */ 497 public String[][] getZoneStrings() 498 { 499 if (zoneStrings != null) 500 return zoneStrings; 501 return runtimeZoneStrings; 502 } 503 504 /** 505 * This method sets the list of strings used to display AM/PM values to 506 * the specified list. 507 * This is a two element <code>String</code> array indexed by 508 * <code>Calendar.AM</code> and <code>Calendar.PM</code> 509 * 510 * @param value The new list of AM/PM display strings. 511 */ 512 public void setAmPmStrings (String[] value) 513 { 514 if(value==null) 515 throw new NullPointerException(); 516 ampms = value; 517 } 518 519 /** 520 * This method sets the list of strings used to display time eras to 521 * to the specified list. 522 * This is a two element <code>String</code> 523 * array indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>. 524 * 525 * @param labels The new list of era display strings. 526 */ 527 public void setEras (String[] labels) 528 { 529 if(labels==null) 530 throw new NullPointerException(); 531 eras = labels; 532 } 533 534 /** 535 * This method sets the list of characters used to specific date/time 536 * formatting strings. 537 * This is an 18 character string that contains the characters 538 * that are used in creating the date formatting strings in 539 * <code>SimpleDateFormat</code>. The following are the character 540 * positions in the string and which format character they correspond 541 * to (the character in parentheses is the default value in the US English 542 * locale): 543 * <p> 544 * <ul> 545 * <li>0 - era (G)</li> 546 * <li>1 - year (y)</li> 547 * <li>2 - month (M)</li> 548 * <li>3 - day of month (d)</li> 549 * <li>4 - hour out of 12, from 1-12 (h)</li> 550 * <li>5 - hour out of 24, from 0-23 (H)</li> 551 * <li>6 - minute (m)</li> 552 * <li>7 - second (s)</li> 553 * <li>8 - millisecond (S)</li> 554 * <li>9 - date of week (E)</li> 555 * <li>10 - date of year (D)</li> 556 * <li>11 - day of week in month, eg. "4th Thur in Nov" (F)</li> 557 * <li>12 - week in year (w)</li> 558 * <li>13 - week in month (W)</li> 559 * <li>14 - am/pm (a)</li> 560 * <li>15 - hour out of 24, from 1-24 (k)</li> 561 * <li>16 - hour out of 12, from 0-11 (K)</li> 562 * <li>17 - time zone (z)</li> 563 * </ul> 564 * 565 * @param chars The new format pattern characters 566 */ 567 public void setLocalPatternChars (String chars) 568 { 569 if(chars==null) 570 throw new NullPointerException(); 571 localPatternChars = chars; 572 } 573 574 /** 575 * This method sets the list of strings used to display month names. 576 * This is a thirteen element 577 * string array indexed by <code>Calendar.JANUARY</code> through 578 * <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 579 * elements because some calendars have thriteen months. 580 * 581 * @param labels The list of month display strings. 582 */ 583 public void setMonths (String[] labels) 584 { 585 if(labels==null) 586 throw new NullPointerException(); 587 months = labels; 588 } 589 590 /** 591 * This method sets the list of strings used to display abbreviated month 592 * names. 593 * This is a thirteen element 594 * <code>String</code> array indexed by <code>Calendar.JANUARY</code> 595 * through <code>Calendar.UNDECEMBER</code>. Note that there are thirteen 596 * elements because some calendars have thirteen months. 597 * 598 * @param labels The new list of abbreviated month display strings. 599 */ 600 public void setShortMonths (String[] labels) 601 { 602 if(labels==null) 603 throw new NullPointerException(); 604 shortMonths = labels; 605 } 606 607 /** 608 * This method sets the list of strings used to display abbreviated 609 * weekday names. 610 * This is an eight element 611 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 612 * through <code>Calendar.SATURDAY</code>. Note that the first element 613 * of this array is ignored. 614 * 615 * @param labels This list of abbreviated weekday display strings. 616 */ 617 public void setShortWeekdays (String[] labels) 618 { 619 if(labels==null) 620 throw new NullPointerException(); 621 shortWeekdays = labels; 622 } 623 624 /** 625 * This method sets the list of strings used to display weekday names. 626 * This is an eight element 627 * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> 628 * through <code>Calendar.SATURDAY</code>. Note that the first element 629 * of this array is ignored. 630 * 631 * @param labels This list of weekday display strings. 632 */ 633 public void setWeekdays (String[] labels) 634 { 635 if(labels==null) 636 throw new NullPointerException(); 637 weekdays = labels; 638 } 639 640 /** 641 * This method sets the list of display strings for time zones. 642 * This is a two dimensional <code>String</code> array where each row in 643 * the array contains five values: 644 * <P> 645 * <ul> 646 * <li>0 - The non-localized time zone id string.</li> 647 * <li>1 - The long name of the time zone (standard time).</li> 648 * <li>2 - The short name of the time zone (standard time).</li> 649 * <li>3 - The long name of the time zone (daylight savings time).</li> 650 * <li>4 - the short name of the time zone (daylight savings time).</li> 651 * </ul> 652 * 653 * @params zones The list of time zone display strings. 654 */ 655 public void setZoneStrings (String[][] zones) 656 { 657 if(zones==null) 658 throw new NullPointerException(); 659 zoneStrings = zones; 660 } 661 662 /* Does a "deep" equality test - recurses into arrays. */ 663 private static boolean equals (Object x, Object y) 664 { 665 if (x == y) 666 return true; 667 if (x == null || y == null) 668 return false; 669 if (! (x instanceof Object[]) || ! (y instanceof Object[])) 670 return x.equals(y); 671 Object[] xa = (Object[]) x; 672 Object[] ya = (Object[]) y; 673 if (xa.length != ya.length) 674 return false; 675 for (int i = xa.length; --i >= 0; ) 676 { 677 if (! equals(xa[i], ya[i])) 678 return false; 679 } 680 return true; 681 } 682 683 private static int hashCode (Object x) 684 { 685 if (x == null) 686 return 0; 687 if (! (x instanceof Object[])) 688 return x.hashCode(); 689 Object[] xa = (Object[]) x; 690 int hash = 0; 691 for (int i = 0; i < xa.length; i++) 692 hash = 37 * hashCode(xa[i]); 693 return hash; 694 } 695 696 /** 697 * This method tests a specified object for equality against this object. 698 * This will be true if and only if the specified object: 699 * <p> 700 * <ul> 701 * <li> Is not <code>null</code>.</li> 702 * <li> Is an instance of <code>DateFormatSymbols</code>.</li> 703 * <li> Contains identical formatting symbols to this object.</li> 704 * </ul> 705 * 706 * @param obj The <code>Object</code> to test for equality against. 707 * 708 * @return <code>true</code> if the specified object is equal to this one, 709 * <code>false</code> otherwise. 710 */ 711 public boolean equals (Object obj) 712 { 713 if (! (obj instanceof DateFormatSymbols)) 714 return false; 715 DateFormatSymbols other = (DateFormatSymbols) obj; 716 return (equals(ampms, other.ampms) 717 && equals(eras, other.eras) 718 && equals(localPatternChars, other.localPatternChars) 719 && equals(months, other.months) 720 && equals(shortMonths, other.shortMonths) 721 && equals(shortWeekdays, other.shortWeekdays) 722 && equals(weekdays, other.weekdays) 723 && equals(zoneStrings, other.zoneStrings)); 724 } 725 726 /** 727 * Returns a new copy of this object. 728 * 729 * @return A copy of this object 730 */ 731 public Object clone () 732 { 733 try 734 { 735 return super.clone (); 736 } 737 catch (CloneNotSupportedException e) 738 { 739 return null; 740 } 741 } 742 743 /** 744 * This method returns a hash value for this object. 745 * 746 * @return A hash value for this object. 747 */ 748 public int hashCode () 749 { 750 return (hashCode(ampms) 751 ^ hashCode(eras) 752 ^ hashCode(localPatternChars) 753 ^ hashCode(months) 754 ^ hashCode(shortMonths) 755 ^ hashCode(shortWeekdays) 756 ^ hashCode(weekdays) 757 ^ hashCode(zoneStrings)); 758 } 759 760 /** 761 * Returns a {@link DateFormatSymbols} instance for the 762 * default locale obtained from either the runtime itself 763 * or one of the installed 764 * {@link java.text.spi.DateFormatSymbolsProvider} instances. 765 * This is equivalent to calling 766 * <code>getInstance(Locale.getDefault())</code>. 767 * 768 * @return a {@link DateFormatSymbols} instance for the default 769 * locale. 770 * @since 1.6 771 */ 772 public static final DateFormatSymbols getInstance() 773 { 774 return getInstance(Locale.getDefault()); 775 } 776 777 /** 778 * Returns a {@link DateFormatSymbols} instance for the 779 * specified locale obtained from either the runtime itself 780 * or one of the installed 781 * {@link java.text.spi.DateFormatSymbolsProvider} instances. 782 * 783 * @param locale the locale for which an instance should be 784 * returned. 785 * @return a {@link DateFormatSymbols} instance for the specified 786 * locale. 787 * @throws NullPointerException if <code>locale</code> is 788 * <code>null</code>. 789 * @since 1.6 790 */ 791 public static final DateFormatSymbols getInstance(Locale locale) 792 { 793 try 794 { 795 DateFormatSymbols syms = new DateFormatSymbols(locale); 796 return syms; 797 } 798 catch (MissingResourceException e) 799 { 800 /* This means runtime support for the locale 801 * is not available, so we check providers. */ 802 } 803 for (DateFormatSymbolsProvider p : 804 ServiceLoader.load(DateFormatSymbolsProvider.class)) 805 { 806 for (Locale loc : p.getAvailableLocales()) 807 { 808 if (loc.equals(locale)) 809 { 810 DateFormatSymbols syms = p.getInstance(locale); 811 if (syms != null) 812 return syms; 813 break; 814 } 815 } 816 } 817 return getInstance(LocaleHelper.getFallbackLocale(locale)); 818 } 819 820}