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