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