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