• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *******************************************************************************
3  * Copyright (C) 1996-2015, International Business Machines Corporation and
4  * others. All Rights Reserved.
5  *******************************************************************************
6  */
7 
8 package com.ibm.icu.text;
9 
10 import java.io.IOException;
11 import java.io.ObjectInputStream;
12 import java.io.Serializable;
13 import java.util.HashMap;
14 import java.util.Locale;
15 import java.util.Map;
16 import java.util.MissingResourceException;
17 import java.util.ResourceBundle;
18 
19 import com.ibm.icu.impl.CalendarData;
20 import com.ibm.icu.impl.CalendarUtil;
21 import com.ibm.icu.impl.ICUCache;
22 import com.ibm.icu.impl.ICUResourceBundle;
23 import com.ibm.icu.impl.SimpleCache;
24 import com.ibm.icu.impl.Utility;
25 import com.ibm.icu.text.TimeZoneNames.NameType;
26 import com.ibm.icu.util.Calendar;
27 import com.ibm.icu.util.ICUCloneNotSupportedException;
28 import com.ibm.icu.util.TimeZone;
29 import com.ibm.icu.util.ULocale;
30 import com.ibm.icu.util.ULocale.Category;
31 import com.ibm.icu.util.UResourceBundle;
32 import com.ibm.icu.util.UResourceBundleIterator;
33 
34 /**
35  * {@icuenhanced java.text.DateFormatSymbols}.{@icu _usage_}
36  *
37  * <p><code>DateFormatSymbols</code> is a public class for encapsulating
38  * localizable date-time formatting data, such as the names of the
39  * months, the names of the days of the week, and the time zone data.
40  * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
41  * <code>DateFormatSymbols</code> to encapsulate this information.
42  *
43  * <p>Typically you shouldn't use <code>DateFormatSymbols</code> directly.
44  * Rather, you are encouraged to create a date-time formatter with the
45  * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
46  * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
47  * These methods automatically create a <code>DateFormatSymbols</code> for
48  * the formatter so that you don't have to. After the
49  * formatter is created, you may modify its format pattern using the
50  * <code>setPattern</code> method. For more information about
51  * creating formatters using <code>DateFormat</code>'s factory methods,
52  * see {@link DateFormat}.
53  *
54  * <p>If you decide to create a date-time formatter with a specific
55  * format pattern for a specific locale, you can do so with:
56  * <blockquote>
57  * <pre>
58  * new SimpleDateFormat(aPattern, new DateFormatSymbols(aLocale)).
59  * </pre>
60  * </blockquote>
61  *
62  * <p><code>DateFormatSymbols</code> objects are clonable. When you obtain
63  * a <code>DateFormatSymbols</code> object, feel free to modify the
64  * date-time formatting data. For instance, you can replace the localized
65  * date-time format pattern characters with the ones that you feel easy
66  * to remember. Or you can change the representative cities
67  * to your favorite ones.
68  *
69  * <p>New <code>DateFormatSymbols</code> subclasses may be added to support
70  * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
71  *
72  * @see          DateFormat
73  * @see          SimpleDateFormat
74  * @see          com.ibm.icu.util.SimpleTimeZone
75  * @author       Chen-Lieh Huang
76  * @stable ICU 2.0
77  */
78 public class DateFormatSymbols implements Serializable, Cloneable {
79 
80     // TODO make sure local pattern char string is 18 characters long,
81     // that is, that it encompasses the new 'u' char for
82     // EXTENDED_YEAR.  Two options: 1. Make sure resource data is
83     // correct; 2. Make code add in 'u' at end if len == 17.
84 
85     // Constants for context
86     /**
87      * {@icu} Constant for context.
88      * @stable ICU 3.6
89      */
90     public static final int FORMAT = 0;
91 
92     /**
93      * {@icu} Constant for context.
94      * @stable ICU 3.6
95      */
96     public static final int STANDALONE = 1;
97 
98     /**
99      * {@icu} Constant for context. NUMERIC context
100      * is only supported for leapMonthPatterns.
101      * @internal
102      * @deprecated This API is ICU internal only.
103      */
104     @Deprecated
105     public static final int NUMERIC = 2;
106 
107     /**
108      * {@icu} Constant for context.
109      * @internal
110      * @deprecated This API is ICU internal only.
111      */
112     @Deprecated
113     public static final int DT_CONTEXT_COUNT = 3;
114 
115     // Constants for width
116 
117     /**
118      * {@icu} Constant for width.
119      * @stable ICU 3.6
120      */
121     public static final int ABBREVIATED = 0;
122 
123     /**
124      * {@icu} Constant for width.
125      * @stable ICU 3.6
126      */
127     public static final int WIDE = 1;
128 
129     /**
130      * {@icu} Constant for width.
131      * @stable ICU 3.6
132      */
133     public static final int NARROW = 2;
134 
135     /**
136      * {@icu} Constant for width; only supported for weekdays.
137      * @stable ICU 51
138      */
139     public static final int SHORT = 3;
140 
141     /**
142      * {@icu} Constant for width.
143      * @internal
144      * @deprecated This API is ICU internal only.
145      */
146     @Deprecated
147     public static final int DT_WIDTH_COUNT = 4;
148 
149     /**
150      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
151      * @internal
152      */
153     static final int DT_LEAP_MONTH_PATTERN_FORMAT_WIDE = 0;
154 
155     /**
156      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
157      * @internal
158      */
159     static final int DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV = 1;
160 
161     /**
162      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
163      * @internal
164      */
165     static final int DT_LEAP_MONTH_PATTERN_FORMAT_NARROW = 2;
166 
167     /**
168      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
169      * @internal
170      */
171     static final int DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE = 3;
172 
173     /**
174      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
175      * @internal
176      */
177     static final int DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV = 4;
178 
179     /**
180      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
181      * @internal
182      */
183     static final int DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW = 5;
184 
185     /**
186      * {@icu} Somewhat temporary constant for leap month pattern type, adequate for Chinese calendar.
187      * @internal
188      */
189     static final int DT_LEAP_MONTH_PATTERN_NUMERIC = 6;
190 
191     /**
192      * {@icu} Somewhat temporary constant for month pattern count, adequate for Chinese calendar.
193      * @internal
194      */
195     static final int DT_MONTH_PATTERN_COUNT = 7;
196 
197     /**
198      * {@icu} This default time separator is used for formatting when the locale
199      * doesn't specify any time separator, and always recognized when parsing.
200      * @internal
201      */
202     static final String DEFAULT_TIME_SEPARATOR = ":";
203 
204     /**
205      * {@icu} This alternate time separator is always recognized when parsing.
206      * @internal
207      */
208     static final String ALTERNATE_TIME_SEPARATOR = ".";
209 
210    /**
211      * Constructs a DateFormatSymbols object by loading format data from
212      * resources for the default <code>FORMAT</code> locale.
213      *
214      * @throws java.util.MissingResourceException if the resources for the default locale
215      *          cannot be found or cannot be loaded.
216      * @see Category#FORMAT
217      * @stable ICU 2.0
218      */
DateFormatSymbols()219     public DateFormatSymbols()
220     {
221         this(ULocale.getDefault(Category.FORMAT));
222     }
223 
224     /**
225      * Constructs a DateFormatSymbols object by loading format data from
226      * resources for the given locale.
227      *
228      * @throws java.util.MissingResourceException if the resources for the specified
229      *          locale cannot be found or cannot be loaded.
230      * @stable ICU 2.0
231      */
DateFormatSymbols(Locale locale)232     public DateFormatSymbols(Locale locale)
233     {
234         this(ULocale.forLocale(locale));
235     }
236 
237     /**
238      * {@icu} Constructs a DateFormatSymbols object by loading format data from
239      * resources for the given ulocale.
240      *
241      * @throws java.util.MissingResourceException if the resources for the specified
242      *          locale cannot be found or cannot be loaded.
243      * @stable ICU 3.2
244      */
DateFormatSymbols(ULocale locale)245     public DateFormatSymbols(ULocale locale)
246     {
247         initializeData(locale, CalendarUtil.getCalendarType(locale));
248     }
249 
250     /**
251      * Returns a DateFormatSymbols instance for the default locale.
252      *
253      * {@icunote} Unlike <code>java.text.DateFormatSymbols#getInstance</code>,
254      * this method simply returns <code>new com.ibm.icu.text.DateFormatSymbols()</code>.
255      * ICU does not support <code>DateFormatSymbolsProvider</code> introduced in Java 6
256      * or its equivalent implementation for now.
257      *
258      * @return A DateFormatSymbols instance.
259      * @stable ICU 3.8
260      */
getInstance()261     public static DateFormatSymbols getInstance() {
262         return new DateFormatSymbols();
263     }
264 
265     /**
266      * Returns a DateFormatSymbols instance for the given locale.
267      *
268      * {@icunote} Unlike <code>java.text.DateFormatSymbols#getInstance</code>,
269      * this method simply returns <code>new com.ibm.icu.text.DateFormatSymbols(locale)</code>.
270      * ICU does not support <code>DateFormatSymbolsProvider</code> introduced in Java 6
271      * or its equivalent implementation for now.
272      *
273      * @param locale the locale.
274      * @return A DateFormatSymbols instance.
275      * @stable ICU 3.8
276      */
getInstance(Locale locale)277     public static DateFormatSymbols getInstance(Locale locale) {
278         return new DateFormatSymbols(locale);
279     }
280 
281     /**
282      * {@icu} Returns a DateFormatSymbols instance for the given locale.
283      *
284      * {@icunote} Unlike <code>java.text.DateFormatSymbols#getInstance</code>,
285      * this method simply returns <code>new com.ibm.icu.text.DateFormatSymbols(locale)</code>.
286      * ICU does not support <code>DateFormatSymbolsProvider</code> introduced in Java 6
287      * or its equivalent implementation for now.
288      *
289      * @param locale the locale.
290      * @return A DateFormatSymbols instance.
291      * @stable ICU 3.8
292      */
getInstance(ULocale locale)293     public static DateFormatSymbols getInstance(ULocale locale) {
294         return new DateFormatSymbols(locale);
295     }
296 
297     /**
298      * Returns an array of all locales for which the <code>getInstance</code> methods of
299      * this class can return localized instances.
300      *
301      * {@icunote} Unlike <code>java.text.DateFormatSymbols#getAvailableLocales</code>,
302      * this method simply returns the array of <code>Locale</code>s available in this
303      * class.  ICU does not support <code>DateFormatSymbolsProvider</code> introduced in
304      * Java 6 or its equivalent implementation for now.
305      *
306      * @return An array of <code>Locale</code>s for which localized
307      * <code>DateFormatSymbols</code> instances are available.
308      * @stable ICU 3.8
309      */
getAvailableLocales()310     public static Locale[] getAvailableLocales() {
311         return ICUResourceBundle.getAvailableLocales();
312     }
313 
314     /**
315      * {@icu} Returns an array of all locales for which the <code>getInstance</code>
316      * methods of this class can return localized instances.
317      *
318      * {@icunote} Unlike <code>java.text.DateFormatSymbols#getAvailableLocales</code>,
319      * this method simply returns the array of <code>ULocale</code>s available in this
320      * class.  ICU does not support <code>DateFormatSymbolsProvider</code> introduced in
321      * Java 6 or its equivalent implementation for now.
322      *
323      * @return An array of <code>ULocale</code>s for which localized
324      * <code>DateFormatSymbols</code> instances are available.
325      * @draft ICU 3.8 (retain)
326      * @provisional This API might change or be removed in a future release.
327      */
getAvailableULocales()328     public static ULocale[] getAvailableULocales() {
329         return ICUResourceBundle.getAvailableULocales();
330     }
331 
332     /**
333      * Era strings. For example: "AD" and "BC".  An array of 2 strings,
334      * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
335      * @serial
336      */
337     String eras[] = null;
338 
339     /**
340      * Era name strings. For example: "Anno Domini" and "Before Christ".  An array of 2 strings,
341      * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
342      * @serial
343      */
344     String eraNames[] = null;
345 
346     /**
347      * Narrow era names. For example: "A" and "B". An array of 2 strings,
348      * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
349      * @serial
350      */
351     String narrowEras[] = null;
352 
353     /**
354      * Month strings. For example: "January", "February", etc.  An array
355      * of 13 strings (some calendars have 13 months), indexed by
356      * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
357      * @serial
358      */
359     String months[] = null;
360 
361     /**
362      * Short month strings. For example: "Jan", "Feb", etc.  An array of
363      * 13 strings (some calendars have 13 months), indexed by
364      * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
365 
366      * @serial
367      */
368     String shortMonths[] = null;
369 
370     /**
371      * Narrow month strings. For example: "J", "F", etc.  An array of
372      * 13 strings (some calendars have 13 months), indexed by
373      * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
374 
375      * @serial
376      */
377     String narrowMonths[] = null;
378 
379     /**
380      * Standalone month strings. For example: "January", "February", etc.  An array
381      * of 13 strings (some calendars have 13 months), indexed by
382      * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
383      * @serial
384      */
385     String standaloneMonths[] = null;
386 
387     /**
388      * Standalone short month strings. For example: "Jan", "Feb", etc.  An array of
389      * 13 strings (some calendars have 13 months), indexed by
390      * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
391 
392      * @serial
393      */
394     String standaloneShortMonths[] = null;
395 
396     /**
397      * Standalone narrow month strings. For example: "J", "F", etc.  An array of
398      * 13 strings (some calendars have 13 months), indexed by
399      * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
400 
401      * @serial
402      */
403     String standaloneNarrowMonths[] = null;
404 
405     /**
406      * Format wide weekday strings, for example: "Sunday", "Monday", etc.
407      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
408      * <code>Calendar.MONDAY</code>, etc.
409      * The element <code>weekdays[0]</code> is ignored.
410      * @serial
411      */
412     String weekdays[] = null;
413 
414     /**
415      * CLDR-style format abbreviated (not short) weekday strings,
416      * for example: "Sun", "Mon", etc.
417      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
418      * <code>Calendar.MONDAY</code>, etc.
419      * The element <code>shortWeekdays[0]</code> is ignored.
420      * @serial
421      */
422     String shortWeekdays[] = null;
423 
424     /**
425      * CLDR-style format short weekday strings, for example: "Su", "Mo", etc.
426      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
427      * <code>Calendar.MONDAY</code>, etc.
428      * The element <code>shorterWeekdays[0]</code> is ignored.
429      * @serial
430      */
431    // Note, serialization restore from pre-ICU-51 will leave this null.
432     String shorterWeekdays[] = null;
433 
434     /**
435      * CLDR-style format narrow weekday strings, for example: "S", "M", etc.
436      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
437      * <code>Calendar.MONDAY</code>, etc.
438      * The element <code>narrowWeekdays[0]</code> is ignored.
439      * @serial
440      */
441     String narrowWeekdays[] = null;
442 
443     /**
444      * Standalone wide weekday strings. For example: "Sunday", "Monday", etc.
445      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
446      * <code>Calendar.MONDAY</code>, etc.
447      * The element <code>standaloneWeekdays[0]</code> is ignored.
448      * @serial
449      */
450     String standaloneWeekdays[] = null;
451 
452     /**
453      * CLDR-style standalone abbreviated (not short) weekday strings,
454      * for example: "Sun", "Mon", etc.
455      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
456      * <code>Calendar.MONDAY</code>, etc.
457      * The element <code>standaloneShortWeekdays[0]</code> is ignored.
458      * @serial
459      */
460     String standaloneShortWeekdays[] = null;
461 
462     /**
463      * CLDR-style standalone short weekday strings, for example: "Sun", "Mon", etc.
464      * An array of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
465      * <code>Calendar.MONDAY</code>, etc.
466      * The element <code>standaloneShorterWeekdays[0]</code> is ignored.
467      * @serial
468      */
469     // Note, serialization restore from pre-ICU-51 will leave this null.
470     String standaloneShorterWeekdays[] = null;
471 
472     /**
473      * Standalone narrow weekday strings. For example: "S", "M", etc.  An array
474      * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
475      * <code>Calendar.MONDAY</code>, etc.
476      * The element <code>standaloneNarrowWeekdays[0]</code> is ignored.
477      * @serial
478      */
479     String standaloneNarrowWeekdays[] = null;
480 
481     /**
482      * AM and PM strings. For example: "AM" and "PM".  An array of
483      * 2 strings, indexed by <code>Calendar.AM</code> and
484      * <code>Calendar.PM</code>.
485      * @serial
486      */
487     String ampms[] = null;
488 
489     /**
490      * narrow AM and PM strings. For example: "a" and "p".  An array of
491      * 2 strings, indexed by <code>Calendar.AM</code> and
492      * <code>Calendar.PM</code>.
493      * @serial
494      */
495     String ampmsNarrow[] = null;
496 
497     /**
498      * Time separator string. For example: ":".
499      * @serial
500      */
501     private String timeSeparator = null;
502 
503     /**
504      * Abbreviated quarter names. For example: "Q1", "Q2", "Q3", "Q4". An array
505      * of 4 strings indexed by the month divided by 3.
506      * @serial
507      */
508     String shortQuarters[] = null;
509 
510     /**
511      * Full quarter names. For example: "1st Quarter", "2nd Quarter", "3rd Quarter",
512      * "4th Quarter". An array of 4 strings, indexed by the month divided by 3.
513      * @serial
514      */
515     String quarters[] = null;
516 
517     /**
518      * Standalone abbreviated quarter names. For example: "Q1", "Q2", "Q3", "Q4". An array
519      * of 4 strings indexed by the month divided by 3.
520      * @serial
521      */
522     String standaloneShortQuarters[] = null;
523 
524     /**
525      * Standalone full quarter names. For example: "1st Quarter", "2nd Quarter", "3rd Quarter",
526      * "4th Quarter". An array of 4 strings, indexed by the month divided by 3.
527      * @serial
528      */
529     String standaloneQuarters[] = null;
530 
531     /**
532      * All leap month patterns, for example "{0}bis".
533      * An array of DT_MONTH_PATTERN_COUNT strings, indexed by the DT_LEAP_MONTH_PATTERN_XXX value.
534      * @serial
535      */
536     String leapMonthPatterns[] = null;
537 
538      /**
539      * Cyclic year names, for example: "jia-zi", "yi-chou", ... "gui-hai".
540      * An array of (normally) 60 strings, corresponding to cyclic years 1-60 (in Calendar YEAR field).
541      * Currently we only have data for format/abbreviated.
542      * For the others, just get from format/abbreviated, ignore set.
543      * @serial
544      */
545     String shortYearNames[] = null;
546 
547      /**
548      * Cyclic zodiac names, for example: "Rat", "Ox", "Tiger", etc.
549      * An array of (normally) 12 strings.
550      * Currently we only have data for format/abbreviated.
551      * For the others, just get from format/abbreviated, ignore set.
552      * @serial
553      */
554     String shortZodiacNames[] = null;
555 
556    /**
557      * Localized names of time zones in this locale.  This is a
558      * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
559      * where <em>m</em> is at least 5 and up to 7.  Each of the <em>n</em> rows is an
560      * entry containing the localized names for a single <code>TimeZone</code>.
561      * Each such row contains (with <code>i</code> ranging from
562      * 0..<em>n</em>-1):
563      * <ul>
564      * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
565      * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
566      * time</li>
567      * <li><code>zoneStrings[i][2]</code> - short name of zone in
568      * standard time</li>
569      * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
570      * savings time</li>
571      * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
572      * savings time</li>
573      * <li><code>zoneStrings[i][5]</code> - location name of zone</li>
574      * <li><code>zoneStrings[i][6]</code> - long generic name of zone</li>
575      * <li><code>zoneStrings[i][7]</code> - short generic of zone</li>
576      * The zone ID is <em>not</em> localized; it corresponds to the ID
577      * value associated with a system time zone object.  All other entries
578      * are localized names.  If a zone does not implement daylight savings
579      * time, the daylight savings time names are ignored.
580      * <em>Note:</em>CLDR 1.5 introduced metazone and its historical mappings.
581      * This simple two-dimensional array is no longer sufficient to represent
582      * localized names and its historic changes.  Since ICU 3.8.1, localized
583      * zone names extracted from ICU locale data is stored in a ZoneStringFormat
584      * instance.  But we still need to support the old way of customizing
585      * localized zone names, so we keep this field for the purpose.
586      * @see com.ibm.icu.util.TimeZone
587      * @serial
588      */
589     private String zoneStrings[][] = null;
590 
591      /**
592      * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
593      * All locales use the same unlocalized pattern characters.
594      */
595     static final String patternChars = "GyMdkHmsSEDFwWahKzYeugAZvcLQqVUOXxr:";
596 
597     /**
598      * Localized date-time pattern characters. For example, a locale may
599      * wish to use 'u' rather than 'y' to represent years in its date format
600      * pattern strings.
601      * This string must be exactly 18 characters long, with the index of
602      * the characters described by <code>DateFormat.ERA_FIELD</code>,
603      * <code>DateFormat.YEAR_FIELD</code>, etc.  Thus, if the string were
604      * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
605      * @serial
606      */
607     String localPatternChars = null;
608 
609     /* use serialVersionUID from JDK 1.1.4 for interoperability */
610     private static final long serialVersionUID = -5987973545549424702L;
611 
612     private static final String[][] CALENDAR_CLASSES = {
613         {"GregorianCalendar", "gregorian"},
614         {"JapaneseCalendar", "japanese"},
615         {"BuddhistCalendar", "buddhist"},
616         {"TaiwanCalendar", "roc"},
617         {"PersianCalendar", "persian"},
618         {"IslamicCalendar", "islamic"},
619         {"HebrewCalendar", "hebrew"},
620         {"ChineseCalendar", "chinese"},
621         {"IndianCalendar", "indian"},
622         {"CopticCalendar", "coptic"},
623         {"EthiopicCalendar", "ethiopic"},
624     };
625 
626     /**
627      * {@icu} Constants for capitalization context usage types
628      * related to date formatting.
629      * @internal
630      */
631     enum CapitalizationContextUsage {
632         OTHER,
633         MONTH_FORMAT,     /* except narrow */
634         MONTH_STANDALONE, /* except narrow */
635         MONTH_NARROW,
636         DAY_FORMAT,     /* except narrow */
637         DAY_STANDALONE, /* except narrow */
638         DAY_NARROW,
639         ERA_WIDE,
640         ERA_ABBREV,
641         ERA_NARROW,
642         ZONE_LONG,
643         ZONE_SHORT,
644         METAZONE_LONG,
645         METAZONE_SHORT
646     }
647 
648     /** Map from resource key to CapitalizationContextUsage value
649      */
650     private static final Map<String, CapitalizationContextUsage> contextUsageTypeMap;
651     static {
652         contextUsageTypeMap=new HashMap<String, CapitalizationContextUsage>();
653         contextUsageTypeMap.put("month-format-except-narrow", CapitalizationContextUsage.MONTH_FORMAT);
654         contextUsageTypeMap.put("month-standalone-except-narrow", CapitalizationContextUsage.MONTH_STANDALONE);
655         contextUsageTypeMap.put("month-narrow",   CapitalizationContextUsage.MONTH_NARROW);
656         contextUsageTypeMap.put("day-format-except-narrow", CapitalizationContextUsage.DAY_FORMAT);
657         contextUsageTypeMap.put("day-standalone-except-narrow", CapitalizationContextUsage.DAY_STANDALONE);
658         contextUsageTypeMap.put("day-narrow",     CapitalizationContextUsage.DAY_NARROW);
659         contextUsageTypeMap.put("era-name",       CapitalizationContextUsage.ERA_WIDE);
660         contextUsageTypeMap.put("era-abbr",       CapitalizationContextUsage.ERA_ABBREV);
661         contextUsageTypeMap.put("era-narrow",     CapitalizationContextUsage.ERA_NARROW);
662         contextUsageTypeMap.put("zone-long",      CapitalizationContextUsage.ZONE_LONG);
663         contextUsageTypeMap.put("zone-short",     CapitalizationContextUsage.ZONE_SHORT);
664         contextUsageTypeMap.put("metazone-long",  CapitalizationContextUsage.METAZONE_LONG);
665         contextUsageTypeMap.put("metazone-short", CapitalizationContextUsage.METAZONE_SHORT);
666     }
667 
668      /**
669      * Capitalization transforms. For each usage type, the first array element indicates
670      * whether to titlecase for uiListOrMenu context, the second indicates whether to
671      * titlecase for stand-alone context.
672      * @serial
673      */
674     Map<CapitalizationContextUsage,boolean[]> capitalization = null;
675 
676     /**
677      * Returns era strings. For example: "AD" and "BC".
678      * @return the era strings.
679      * @stable ICU 2.0
680      */
getEras()681     public String[] getEras() {
682         return duplicate(eras);
683     }
684 
685     /**
686      * Sets era strings. For example: "AD" and "BC".
687      * @param newEras the new era strings.
688      * @stable ICU 2.0
689      */
setEras(String[] newEras)690     public void setEras(String[] newEras) {
691         eras = duplicate(newEras);
692     }
693 
694     /**
695      * {@icu} Returns era name strings. For example: "Anno Domini" and "Before Christ".
696      * @return the era strings.
697      * @stable ICU 3.4
698      */
getEraNames()699     public String[] getEraNames() {
700         return duplicate(eraNames);
701     }
702 
703     /**
704      * {@icu} Sets era name strings. For example: "Anno Domini" and "Before Christ".
705      * @param newEraNames the new era strings.
706      * @stable ICU 3.8
707      */
setEraNames(String[] newEraNames)708     public void setEraNames(String[] newEraNames) {
709         eraNames = duplicate(newEraNames);
710     }
711 
712     /**
713      * Returns month strings. For example: "January", "February", etc.
714      * @return the month strings.
715      * @stable ICU 2.0
716      */
getMonths()717     public String[] getMonths() {
718         return duplicate(months);
719     }
720 
721     /**
722      * Returns month strings. For example: "January", "February", etc.
723      * @param context    The month context, FORMAT or STANDALONE.
724      * @param width      The width or the returned month string,
725      *                   either WIDE, ABBREVIATED, or NARROW.
726      * @return the month strings.
727      * @stable ICU 3.4
728      */
getMonths(int context, int width)729     public String[] getMonths(int context, int width) {
730         String [] returnValue = null;
731         switch (context) {
732            case FORMAT :
733               switch(width) {
734                  case WIDE :
735                     returnValue = months;
736                     break;
737                  case ABBREVIATED :
738                  case SHORT : // no month data for this, defaults to ABBREVIATED
739                     returnValue = shortMonths;
740                     break;
741                  case NARROW :
742                     returnValue = narrowMonths;
743                     break;
744               }
745               break;
746            case STANDALONE :
747               switch(width) {
748                  case WIDE :
749                     returnValue = standaloneMonths;
750                     break;
751                  case ABBREVIATED :
752                  case SHORT : // no month data for this, defaults to ABBREVIATED
753                     returnValue = standaloneShortMonths;
754                     break;
755                  case NARROW :
756                     returnValue = standaloneNarrowMonths;
757                     break;
758               }
759               break;
760         }
761         if (returnValue == null) {
762             throw new IllegalArgumentException("Bad context or width argument");
763         }
764         return duplicate(returnValue);
765     }
766 
767     /**
768      * Sets month strings. For example: "January", "February", etc.
769      * @param newMonths the new month strings.
770      * @stable ICU 2.0
771      */
setMonths(String[] newMonths)772     public void setMonths(String[] newMonths) {
773         months = duplicate(newMonths);
774     }
775 
776     /**
777      * Sets month strings. For example: "January", "February", etc.
778      * @param newMonths the new month strings.
779      * @param context    The formatting context, FORMAT or STANDALONE.
780      * @param width      The width of the month string,
781      *                   either WIDE, ABBREVIATED, or NARROW.
782      * @stable ICU 3.8
783      */
setMonths(String[] newMonths, int context, int width)784     public void setMonths(String[] newMonths, int context, int width) {
785         switch (context) {
786            case FORMAT :
787               switch(width) {
788                  case WIDE :
789                     months = duplicate(newMonths);
790                     break;
791                  case ABBREVIATED :
792                     shortMonths = duplicate(newMonths);
793                     break;
794                  case NARROW :
795                     narrowMonths = duplicate(newMonths);
796                     break;
797                  default : // HANDLE SHORT, etc.
798                     break;
799               }
800               break;
801            case STANDALONE :
802               switch(width) {
803                  case WIDE :
804                     standaloneMonths = duplicate(newMonths);
805                     break;
806                  case ABBREVIATED :
807                     standaloneShortMonths = duplicate(newMonths);
808                     break;
809                  case NARROW :
810                     standaloneNarrowMonths = duplicate(newMonths);
811                     break;
812                  default : // HANDLE SHORT, etc.
813                     break;
814               }
815               break;
816         }
817     }
818 
819     /**
820      * Returns short month strings. For example: "Jan", "Feb", etc.
821      * @return the short month strings.
822      * @stable ICU 2.0
823      */
getShortMonths()824     public String[] getShortMonths() {
825         return duplicate(shortMonths);
826     }
827 
828     /**
829      * Sets short month strings. For example: "Jan", "Feb", etc.
830      * @param newShortMonths the new short month strings.
831      * @stable ICU 2.0
832      */
setShortMonths(String[] newShortMonths)833     public void setShortMonths(String[] newShortMonths) {
834         shortMonths = duplicate(newShortMonths);
835     }
836 
837     /**
838      * Returns wide weekday strings. For example: "Sunday", "Monday", etc.
839      * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
840      * <code>Calendar.MONDAY</code>, etc. to index the result array.
841      * @stable ICU 2.0
842      */
getWeekdays()843     public String[] getWeekdays() {
844         return duplicate(weekdays);
845     }
846 
847     /**
848      * Returns weekday strings. For example: "Sunday", "Monday", etc.
849      * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
850      * <code>Calendar.MONDAY</code>, etc. to index the result array.
851      * @param context    Formatting context, either FORMAT or STANDALONE.
852      * @param width      Width of strings to be returned, either
853      *                   WIDE, ABBREVIATED, SHORT, or NARROW
854      * @stable ICU 3.4
855      */
getWeekdays(int context, int width)856     public String[] getWeekdays(int context, int width) {
857         String [] returnValue = null;
858         switch (context) {
859            case FORMAT :
860               switch(width) {
861                  case WIDE :
862                     returnValue = weekdays;
863                     break;
864                  case ABBREVIATED :
865                     returnValue = shortWeekdays;
866                     break;
867                  case SHORT :
868                     returnValue = (shorterWeekdays != null)? shorterWeekdays: shortWeekdays;
869                     break;
870                  case NARROW :
871                     returnValue = narrowWeekdays;
872                     break;
873               }
874               break;
875            case STANDALONE :
876               switch(width) {
877                  case WIDE :
878                     returnValue = standaloneWeekdays;
879                     break;
880                  case ABBREVIATED :
881                     returnValue = standaloneShortWeekdays;
882                     break;
883                  case SHORT :
884                     returnValue = (standaloneShorterWeekdays != null)? standaloneShorterWeekdays: standaloneShortWeekdays;
885                     break;
886                  case NARROW :
887                     returnValue = standaloneNarrowWeekdays;
888                     break;
889               }
890               break;
891         }
892         if (returnValue == null) {
893             throw new IllegalArgumentException("Bad context or width argument");
894         }
895         return duplicate(returnValue);
896     }
897 
898     /**
899      * Sets weekday strings. For example: "Sunday", "Monday", etc.
900      * @param newWeekdays The new weekday strings.
901      * @param context     The formatting context, FORMAT or STANDALONE.
902      * @param width       The width of the strings,
903      *                    either WIDE, ABBREVIATED, SHORT, or NARROW.
904      * @stable ICU 3.8
905      */
setWeekdays(String[] newWeekdays, int context, int width)906     public void setWeekdays(String[] newWeekdays, int context, int width) {
907         switch (context) {
908            case FORMAT :
909               switch(width) {
910                  case WIDE :
911                     weekdays = duplicate(newWeekdays);
912                     break;
913                  case ABBREVIATED :
914                     shortWeekdays = duplicate(newWeekdays);
915                     break;
916                  case SHORT :
917                     shorterWeekdays = duplicate(newWeekdays);
918                     break;
919                  case NARROW :
920                     narrowWeekdays = duplicate(newWeekdays);
921                     break;
922               }
923               break;
924            case STANDALONE :
925               switch(width) {
926                  case WIDE :
927                     standaloneWeekdays = duplicate(newWeekdays);
928                     break;
929                  case ABBREVIATED :
930                     standaloneShortWeekdays = duplicate(newWeekdays);
931                     break;
932                  case SHORT :
933                     standaloneShorterWeekdays = duplicate(newWeekdays);
934                     break;
935                  case NARROW :
936                     standaloneNarrowWeekdays = duplicate(newWeekdays);
937                     break;
938               }
939               break;
940         }
941     }
942 
943     /**
944      * Sets wide weekday strings. For example: "Sunday", "Monday", etc.
945      * @param newWeekdays the new weekday strings. The array should
946      * be indexed by <code>Calendar.SUNDAY</code>,
947      * <code>Calendar.MONDAY</code>, etc.
948      * @stable ICU 2.0
949      */
setWeekdays(String[] newWeekdays)950     public void setWeekdays(String[] newWeekdays) {
951         weekdays = duplicate(newWeekdays);
952     }
953 
954     /**
955      * Returns abbreviated weekday strings; for example: "Sun", "Mon", etc.
956      * (Note: the method name is misleading; it does not get the CLDR-style
957      * "short" weekday strings, e.g. "Su", "Mo", etc.)
958      * @return the abbreviated weekday strings. Use <code>Calendar.SUNDAY</code>,
959      * <code>Calendar.MONDAY</code>, etc. to index the result array.
960      * @stable ICU 2.0
961      */
getShortWeekdays()962     public String[] getShortWeekdays() {
963         return duplicate(shortWeekdays);
964     }
965 
966     /**
967      * Sets abbreviated weekday strings; for example: "Sun", "Mon", etc.
968      * (Note: the method name is misleading; it does not set the CLDR-style
969      * "short" weekday strings, e.g. "Su", "Mo", etc.)
970      * @param newAbbrevWeekdays the new abbreviated weekday strings. The array should
971      * be indexed by <code>Calendar.SUNDAY</code>,
972      * <code>Calendar.MONDAY</code>, etc.
973      * @stable ICU 2.0
974      */
setShortWeekdays(String[] newAbbrevWeekdays)975     public void setShortWeekdays(String[] newAbbrevWeekdays) {
976         shortWeekdays = duplicate(newAbbrevWeekdays);
977     }
978     /**
979      * {@icu} Returns quarter strings. For example: "1st Quarter", "2nd Quarter", etc.
980      * @param context    The quarter context, FORMAT or STANDALONE.
981      * @param width      The width or the returned quarter string,
982      *                   either WIDE or ABBREVIATED. There are no NARROW quarters.
983      * @return the quarter strings.
984      * @stable ICU 3.6
985      */
getQuarters(int context, int width)986     public String[] getQuarters(int context, int width) {
987         String [] returnValue = null;
988         switch (context) {
989            case FORMAT :
990               switch(width) {
991                  case WIDE :
992                     returnValue = quarters;
993                     break;
994                  case ABBREVIATED :
995                  case SHORT : // no quarter data for this, defaults to ABBREVIATED
996                     returnValue = shortQuarters;
997                     break;
998                  case NARROW :
999                      returnValue = null;
1000                      break;
1001               }
1002               break;
1003 
1004            case STANDALONE :
1005               switch(width) {
1006                  case WIDE :
1007                     returnValue = standaloneQuarters;
1008                     break;
1009                  case ABBREVIATED :
1010                  case SHORT : // no quarter data for this, defaults to ABBREVIATED
1011                     returnValue = standaloneShortQuarters;
1012                     break;
1013                  case NARROW:
1014                      returnValue = null;
1015                      break;
1016               }
1017               break;
1018         }
1019         if (returnValue == null) {
1020             throw new IllegalArgumentException("Bad context or width argument");
1021         }
1022         return duplicate(returnValue);
1023     }
1024 
1025     /**
1026      * {@icu} Sets quarter strings. For example: "1st Quarter", "2nd Quarter", etc.
1027      * @param newQuarters the new quarter strings.
1028      * @param context    The formatting context, FORMAT or STANDALONE.
1029      * @param width      The width of the quarter string,
1030      *                   either WIDE or ABBREVIATED. There are no NARROW quarters.
1031      * @stable ICU 3.8
1032      */
setQuarters(String[] newQuarters, int context, int width)1033     public void setQuarters(String[] newQuarters, int context, int width) {
1034         switch (context) {
1035            case FORMAT :
1036               switch(width) {
1037                  case WIDE :
1038                     quarters = duplicate(newQuarters);
1039                     break;
1040                  case ABBREVIATED :
1041                     shortQuarters = duplicate(newQuarters);
1042                     break;
1043                  case NARROW :
1044                     //narrowQuarters = duplicate(newQuarters);
1045                     break;
1046                  default : // HANDLE SHORT, etc.
1047                     break;
1048               }
1049               break;
1050            case STANDALONE :
1051               switch(width) {
1052                  case WIDE :
1053                     standaloneQuarters = duplicate(newQuarters);
1054                     break;
1055                  case ABBREVIATED :
1056                     standaloneShortQuarters = duplicate(newQuarters);
1057                     break;
1058                  case NARROW :
1059                     //standaloneNarrowQuarters = duplicate(newQuarters);
1060                     break;
1061                  default : // HANDLE SHORT, etc.
1062                     break;
1063               }
1064               break;
1065         }
1066     }
1067 
1068     /**
1069      * Returns cyclic year name strings if the calendar has them,
1070      * for example: "jia-zi", "yi-chou", etc.
1071      * @param context   The usage context: FORMAT, STANDALONE.
1072      * @param width     The requested name width: WIDE, ABBREVIATED, SHORT, NARROW.
1073      * @return          The year name strings, or null if they are not
1074      *                  available for this calendar.
1075      * @draft ICU 54
1076      * @provisional This API might change or be removed in a future release.
1077      */
getYearNames(int context, int width)1078     public String[] getYearNames(int context, int width) {
1079         // context & width ignored for now, one set of names for all uses
1080         if (shortYearNames != null) {
1081             return duplicate(shortYearNames);
1082         }
1083         return null;
1084     }
1085 
1086     /**
1087      * Sets cyclic year name strings, for example: "jia-zi", "yi-chou", etc.
1088      * @param yearNames The new cyclic year name strings.
1089      * @param context   The usage context: FORMAT, STANDALONE (currently only FORMAT is supported).
1090      * @param width     The name width: WIDE, ABBREVIATED, NARROW (currently only ABBREVIATED is supported).
1091      * @draft ICU 54
1092      * @provisional This API might change or be removed in a future release.
1093      */
setYearNames(String[] yearNames, int context, int width)1094     public void setYearNames(String[] yearNames, int context, int width) {
1095         if (context == FORMAT && width == ABBREVIATED) {
1096             shortYearNames = duplicate(yearNames);
1097         }
1098     }
1099 
1100     /**
1101      * Returns calendar zodiac name strings if the calendar has them,
1102      * for example: "Rat", "Ox", "Tiger", etc.
1103      * @param context   The usage context: FORMAT, STANDALONE.
1104      * @param width     The requested name width: WIDE, ABBREVIATED, SHORT, NARROW.
1105      * @return          The zodiac name strings, or null if they are not
1106      *                  available for this calendar.
1107      * @draft ICU 54
1108      * @provisional This API might change or be removed in a future release.
1109      */
getZodiacNames(int context, int width)1110     public String[] getZodiacNames(int context, int width) {
1111         // context & width ignored for now, one set of names for all uses
1112         if (shortZodiacNames != null) {
1113             return duplicate(shortZodiacNames);
1114         }
1115         return null;
1116     }
1117 
1118     /**
1119      * Sets calendar zodiac name strings, for example: "Rat", "Ox", "Tiger", etc.
1120      * @param zodiacNames   The new zodiac name strings.
1121      * @param context   The usage context: FORMAT, STANDALONE (currently only FORMAT is supported).
1122      * @param width     The name width: WIDE, ABBREVIATED, NARROW (currently only ABBREVIATED is supported).
1123      * @draft ICU 54
1124      * @provisional This API might change or be removed in a future release.
1125      */
setZodiacNames(String[] zodiacNames, int context, int width)1126     public void setZodiacNames(String[] zodiacNames, int context, int width) {
1127         if (context == FORMAT && width == ABBREVIATED) {
1128             shortZodiacNames = duplicate(zodiacNames);
1129         }
1130     }
1131 
1132     /**
1133      * Returns the appropriate leapMonthPattern if the calendar has them,
1134      * for example: "{0}bis"
1135      * @param context   The usage context: FORMAT, STANDALONE, NUMERIC.
1136      * @param width     The requested pattern width: WIDE, ABBREVIATED, SHORT, NARROW.
1137      * @return          The leapMonthPattern, or null if not available for
1138      *                  this calendar.
1139      * @internal
1140      * @deprecated This API is ICU internal only.
1141      */
1142     @Deprecated
getLeapMonthPattern(int context, int width)1143     public String getLeapMonthPattern(int context, int width) {
1144         if (leapMonthPatterns != null) {
1145             int leapMonthPatternIndex = -1;
1146             switch (context) {
1147                case FORMAT :
1148                   switch(width) {
1149                      case WIDE :
1150                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_WIDE;
1151                         break;
1152                      case ABBREVIATED :
1153                      case SHORT : // no month data for this, defaults to ABBREVIATED
1154                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV;
1155                         break;
1156                      case NARROW :
1157                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_NARROW;
1158                         break;
1159                   }
1160                   break;
1161                case STANDALONE :
1162                   switch(width) {
1163                      case WIDE :
1164                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE;
1165                         break;
1166                      case ABBREVIATED :
1167                      case SHORT : // no month data for this, defaults to ABBREVIATED
1168                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV;
1169                         break;
1170                      case NARROW :
1171                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW;
1172                         break;
1173                   }
1174                   break;
1175                case NUMERIC :
1176                   leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_NUMERIC;
1177                   break;
1178             }
1179             if (leapMonthPatternIndex < 0) {
1180                 throw new IllegalArgumentException("Bad context or width argument");
1181             }
1182             return leapMonthPatterns[leapMonthPatternIndex];
1183         }
1184         return null;
1185     }
1186 
1187     /**
1188      * Sets a leapMonthPattern, for example: "{0}bis"
1189      * @param leapMonthPattern  The new leapMonthPattern.
1190      * @param context   The usage context: FORMAT, STANDALONE, NUMERIC.
1191      * @param width     The name width: WIDE, ABBREVIATED, NARROW.
1192      * @internal
1193      * @deprecated This API is ICU internal only.
1194      */
1195     @Deprecated
setLeapMonthPattern(String leapMonthPattern, int context, int width)1196     public void setLeapMonthPattern(String leapMonthPattern, int context, int width) {
1197         if (leapMonthPatterns != null) {
1198             int leapMonthPatternIndex = -1;
1199             switch (context) {
1200                case FORMAT :
1201                   switch(width) {
1202                      case WIDE :
1203                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_WIDE;
1204                         break;
1205                      case ABBREVIATED :
1206                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV;
1207                         break;
1208                      case NARROW :
1209                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_NARROW;
1210                         break;
1211                      default : // HANDLE SHORT, etc.
1212                         break;
1213                   }
1214                   break;
1215                case STANDALONE :
1216                   switch(width) {
1217                      case WIDE :
1218                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE;
1219                         break;
1220                      case ABBREVIATED :
1221                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV;
1222                         break;
1223                      case NARROW :
1224                         leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW;
1225                         break;
1226                      default : // HANDLE SHORT, etc.
1227                         break;
1228                   }
1229                   break;
1230                case NUMERIC :
1231                   leapMonthPatternIndex = DT_LEAP_MONTH_PATTERN_NUMERIC;
1232                   break;
1233                default :
1234                   break;
1235             }
1236             if (leapMonthPatternIndex >= 0) {
1237                 leapMonthPatterns[leapMonthPatternIndex] = leapMonthPattern;
1238             }
1239         }
1240     }
1241 
1242     /**
1243      * Returns am/pm strings. For example: "AM" and "PM".
1244      * @return the weekday strings.
1245      * @stable ICU 2.0
1246      */
getAmPmStrings()1247     public String[] getAmPmStrings() {
1248         return duplicate(ampms);
1249     }
1250 
1251     /**
1252      * Sets am/pm strings. For example: "AM" and "PM".
1253      * @param newAmpms the new ampm strings.
1254      * @stable ICU 2.0
1255      */
setAmPmStrings(String[] newAmpms)1256     public void setAmPmStrings(String[] newAmpms) {
1257         ampms = duplicate(newAmpms);
1258     }
1259 
1260     /**
1261      * Returns the time separator string. For example: ":".
1262      * @return the time separator string.
1263      * @draft ICU 55
1264      * @provisional This API might change or be removed in a future release.
1265      */
getTimeSeparatorString()1266     public String getTimeSeparatorString() {
1267         return timeSeparator;
1268     }
1269 
1270     /**
1271      * Sets the time separator string. For example: ":".
1272      * @param newTimeSeparator the new time separator string.
1273      * @draft ICU 55
1274      * @provisional This API might change or be removed in a future release.
1275      */
setTimeSeparatorString(String newTimeSeparator)1276     public void setTimeSeparatorString(String newTimeSeparator) {
1277         timeSeparator = newTimeSeparator;
1278     }
1279 
1280     /**
1281      * Returns time zone strings.
1282      * <p>
1283      * The array returned by this API is a two dimensional String array and
1284      * each row contains at least following strings:
1285      * <ul>
1286      * <li>ZoneStrings[n][0] - System time zone ID
1287      * <li>ZoneStrings[n][1] - Long standard time display name
1288      * <li>ZoneStrings[n][2] - Short standard time display name
1289      * <li>ZoneStrings[n][3] - Long daylight saving time display name
1290      * <li>ZoneStrings[n][4] - Short daylight saving time display name
1291      * </ul>
1292      * When a localized display name is not available, the corresponding
1293      * array element will be <code>null</code>.
1294      * <p>
1295      * <b>Note</b>: ICU implements time zone display name formatting algorithm
1296      * specified by <a href="http://www.unicode.org/reports/tr35/">UTS#35 Unicode
1297      * Locale Data Markup Language(LDML)</a>. The algorithm supports historic
1298      * display name changes and various different type of names not available in
1299      * JDK. For accessing the full set of time zone string data used by ICU implementation,
1300      * you should use {@link TimeZoneNames} APIs instead.
1301      *
1302      * @return the time zone strings.
1303      * @stable ICU 2.0
1304      */
getZoneStrings()1305     public String[][] getZoneStrings() {
1306         if (zoneStrings != null) {
1307             return duplicate(zoneStrings);
1308         }
1309 
1310         String[] tzIDs = TimeZone.getAvailableIDs();
1311         TimeZoneNames tznames = TimeZoneNames.getInstance(validLocale);
1312         long now = System.currentTimeMillis();
1313         String[][] array = new String[tzIDs.length][5];
1314         for (int i = 0; i < tzIDs.length; i++) {
1315             String canonicalID = TimeZone.getCanonicalID(tzIDs[i]);
1316             if (canonicalID == null) {
1317                 canonicalID = tzIDs[i];
1318             }
1319 
1320             array[i][0] = tzIDs[i];
1321             array[i][1] = tznames.getDisplayName(canonicalID, NameType.LONG_STANDARD, now);
1322             array[i][2] = tznames.getDisplayName(canonicalID, NameType.SHORT_STANDARD, now);
1323             array[i][3] = tznames.getDisplayName(canonicalID, NameType.LONG_DAYLIGHT, now);
1324             array[i][4] = tznames.getDisplayName(canonicalID, NameType.SHORT_DAYLIGHT, now);
1325         }
1326 
1327         zoneStrings = array;
1328         return zoneStrings;
1329     }
1330 
1331     /**
1332      * Sets time zone strings.
1333      * <p>
1334      * <b>Note</b>: {@link SimpleDateFormat} no longer uses the
1335      * zone strings stored in a <code>DateFormatSymbols</code>.
1336      * Therefore, the time zone strings set by this method have
1337      * no effects in an instance of <code>SimpleDateFormat</code>
1338      * for formatting time zones. If you want to customize time
1339      * zone display names formatted by <code>SimpleDateFormat</code>,
1340      * you should customize {@link TimeZoneFormat} and set the
1341      * instance by {@link SimpleDateFormat#setTimeZoneFormat(TimeZoneFormat)}
1342      * instead.
1343      *
1344      * @param newZoneStrings the new time zone strings.
1345      * @stable ICU 2.0
1346      */
setZoneStrings(String[][] newZoneStrings)1347     public void setZoneStrings(String[][] newZoneStrings) {
1348         zoneStrings = duplicate(newZoneStrings);
1349     }
1350 
1351     /**
1352      * Returns localized date-time pattern characters. For example: 'u', 't', etc.
1353      *
1354      * <p>Note: ICU no longer provides localized date-time pattern characters for a locale
1355      * starting ICU 3.8.  This method returns the non-localized date-time pattern
1356      * characters unless user defined localized data is set by setLocalPatternChars.
1357      * @return the localized date-time pattern characters.
1358      * @stable ICU 2.0
1359      */
getLocalPatternChars()1360     public String getLocalPatternChars() {
1361         return localPatternChars;
1362     }
1363 
1364     /**
1365      * Sets localized date-time pattern characters. For example: 'u', 't', etc.
1366      * @param newLocalPatternChars the new localized date-time
1367      * pattern characters.
1368      * @stable ICU 2.0
1369      */
setLocalPatternChars(String newLocalPatternChars)1370     public void setLocalPatternChars(String newLocalPatternChars) {
1371         localPatternChars = newLocalPatternChars;
1372     }
1373 
1374     /**
1375      * Overrides clone.
1376      * @stable ICU 2.0
1377      */
clone()1378     public Object clone()
1379     {
1380         try {
1381             DateFormatSymbols other = (DateFormatSymbols)super.clone();
1382             return other;
1383         } catch (CloneNotSupportedException e) {
1384             ///CLOVER:OFF
1385             throw new ICUCloneNotSupportedException(e);
1386             ///CLOVER:ON
1387         }
1388     }
1389 
1390     /**
1391      * Override hashCode.
1392      * Generates a hash code for the DateFormatSymbols object.
1393      * @stable ICU 2.0
1394      */
hashCode()1395     public int hashCode() {
1396         // Is this sufficient?
1397         return requestedLocale.toString().hashCode();
1398     }
1399 
1400     /**
1401      * Overrides equals.
1402      * @stable ICU 2.0
1403      */
equals(Object obj)1404     public boolean equals(Object obj)
1405     {
1406         if (this == obj) return true;
1407         if (obj == null || getClass() != obj.getClass()) return false;
1408         DateFormatSymbols that = (DateFormatSymbols) obj;
1409         return (Utility.arrayEquals(eras, that.eras)
1410                 && Utility.arrayEquals(eraNames, that.eraNames)
1411                 && Utility.arrayEquals(months, that.months)
1412                 && Utility.arrayEquals(shortMonths, that.shortMonths)
1413                 && Utility.arrayEquals(narrowMonths, that.narrowMonths)
1414                 && Utility.arrayEquals(standaloneMonths, that.standaloneMonths)
1415                 && Utility.arrayEquals(standaloneShortMonths, that.standaloneShortMonths)
1416                 && Utility.arrayEquals(standaloneNarrowMonths, that.standaloneNarrowMonths)
1417                 && Utility.arrayEquals(weekdays, that.weekdays)
1418                 && Utility.arrayEquals(shortWeekdays, that.shortWeekdays)
1419                 && Utility.arrayEquals(shorterWeekdays, that.shorterWeekdays)
1420                 && Utility.arrayEquals(narrowWeekdays, that.narrowWeekdays)
1421                 && Utility.arrayEquals(standaloneWeekdays, that.standaloneWeekdays)
1422                 && Utility.arrayEquals(standaloneShortWeekdays, that.standaloneShortWeekdays)
1423                 && Utility.arrayEquals(standaloneShorterWeekdays, that.standaloneShorterWeekdays)
1424                 && Utility.arrayEquals(standaloneNarrowWeekdays, that.standaloneNarrowWeekdays)
1425                 && Utility.arrayEquals(ampms, that.ampms)
1426                 && Utility.arrayEquals(ampmsNarrow, that.ampmsNarrow)
1427                 && Utility.arrayEquals(timeSeparator, that.timeSeparator)
1428                 && arrayOfArrayEquals(zoneStrings, that.zoneStrings)
1429                 // getDiplayName maps deprecated country and language codes to the current ones
1430                 // too bad there is no way to get the current codes!
1431                 // I thought canolicalize() would map the codes but .. alas! it doesn't.
1432                 && requestedLocale.getDisplayName().equals(that.requestedLocale.getDisplayName())
1433                 && Utility.arrayEquals(localPatternChars,
1434                                        that.localPatternChars));
1435     }
1436 
1437     // =======================privates===============================
1438 
1439     /**
1440      * Useful constant for defining timezone offsets.
1441      */
1442     static final int millisPerHour = 60*60*1000;
1443 
1444     // DateFormatSymbols cache
1445     private static ICUCache<String, DateFormatSymbols> DFSCACHE =
1446         new SimpleCache<String, DateFormatSymbols>();
1447 
1448     /**
1449      * Initializes format symbols for the locale and calendar type
1450      * @param desiredLocale The locale whose symbols are desired.
1451      * @param type          The calendar type whose date format symbols are desired.
1452      * @stable ICU 3.0
1453      */
1454     //TODO: This protected seems to be marked as @stable accidentally.
1455     // We may need to deescalate this API to @internal.
initializeData(ULocale desiredLocale, String type)1456     protected void initializeData(ULocale desiredLocale, String type)
1457     {
1458         String key = desiredLocale.getBaseName() + "+" + type;
1459         String ns = desiredLocale.getKeywordValue("numbers");
1460         if (ns != null && ns.length() > 0) {
1461             key += "+" + ns;
1462         }
1463         DateFormatSymbols dfs = DFSCACHE.get(key);
1464         if (dfs == null) {
1465             // Initialize data from scratch put a clone of this instance into the cache
1466             CalendarData calData = new CalendarData(desiredLocale, type);
1467             initializeData(desiredLocale, calData);
1468             // Do not cache subclass instances
1469             if (this.getClass().getName().equals("com.ibm.icu.text.DateFormatSymbols")) {
1470                 dfs = (DateFormatSymbols)this.clone();
1471                 DFSCACHE.put(key, dfs);
1472             }
1473         } else {
1474             initializeData(dfs);
1475         }
1476     }
1477 
1478     /**
1479      * Initializes format symbols using another instance.
1480      *
1481      * TODO Clean up initialization methods for subclasses
1482      */
initializeData(DateFormatSymbols dfs)1483     void initializeData(DateFormatSymbols dfs) {
1484         this.eras = dfs.eras;
1485         this.eraNames = dfs.eraNames;
1486         this.narrowEras = dfs.narrowEras;
1487         this.months = dfs.months;
1488         this.shortMonths = dfs.shortMonths;
1489         this.narrowMonths = dfs.narrowMonths;
1490         this.standaloneMonths = dfs.standaloneMonths;
1491         this.standaloneShortMonths = dfs.standaloneShortMonths;
1492         this.standaloneNarrowMonths = dfs.standaloneNarrowMonths;
1493         this.weekdays = dfs.weekdays;
1494         this.shortWeekdays = dfs.shortWeekdays;
1495         this.shorterWeekdays = dfs.shorterWeekdays;
1496         this.narrowWeekdays = dfs.narrowWeekdays;
1497         this.standaloneWeekdays = dfs.standaloneWeekdays;
1498         this.standaloneShortWeekdays = dfs.standaloneShortWeekdays;
1499         this.standaloneShorterWeekdays = dfs.standaloneShorterWeekdays;
1500         this.standaloneNarrowWeekdays = dfs.standaloneNarrowWeekdays;
1501         this.ampms = dfs.ampms;
1502         this.ampmsNarrow = dfs.ampmsNarrow;
1503         this.timeSeparator = dfs.timeSeparator;
1504         this.shortQuarters = dfs.shortQuarters;
1505         this.quarters = dfs.quarters;
1506         this.standaloneShortQuarters = dfs.standaloneShortQuarters;
1507         this.standaloneQuarters = dfs.standaloneQuarters;
1508         this.leapMonthPatterns = dfs.leapMonthPatterns;
1509         this.shortYearNames = dfs.shortYearNames;
1510         this.shortZodiacNames = dfs.shortZodiacNames;
1511 
1512         this.zoneStrings = dfs.zoneStrings; // always null at initialization time for now
1513         this.localPatternChars = dfs.localPatternChars;
1514 
1515         this.capitalization = dfs.capitalization;
1516 
1517         this.actualLocale = dfs.actualLocale;
1518         this.validLocale = dfs.validLocale;
1519         this.requestedLocale = dfs.requestedLocale;
1520     }
1521 
1522     /**
1523      * Initializes format symbols for the locale and calendar type
1524      * @param desiredLocale The locale whose symbols are desired.
1525      * @param calData       The calendar resource data
1526      * @internal
1527      * @deprecated This API is ICU internal only.
1528      */
1529     @Deprecated
1530     // This API was accidentally marked as @stable ICU 3.0 formerly.
initializeData(ULocale desiredLocale, CalendarData calData)1531     protected void initializeData(ULocale desiredLocale, CalendarData calData)
1532     {
1533         // FIXME: cache only ResourceBundle. Hence every time, will do
1534         // getObject(). This won't be necessary if the Resource itself
1535         // is cached.
1536         eras = calData.getEras("abbreviated");
1537 
1538         eraNames = calData.getEras("wide");
1539 
1540         narrowEras = calData.getEras("narrow");
1541 
1542         months = calData.getStringArray("monthNames", "wide");
1543         shortMonths = calData.getStringArray("monthNames", "abbreviated");
1544         narrowMonths = calData.getStringArray("monthNames", "narrow");
1545 
1546         standaloneMonths = calData.getStringArray("monthNames", "stand-alone", "wide");
1547         standaloneShortMonths = calData.getStringArray("monthNames", "stand-alone", "abbreviated");
1548         standaloneNarrowMonths = calData.getStringArray("monthNames", "stand-alone", "narrow");
1549 
1550         String[] lWeekdays = calData.getStringArray("dayNames", "wide");
1551         weekdays = new String[8];
1552         weekdays[0] = "";  // 1-based
1553         System.arraycopy(lWeekdays, 0, weekdays, 1, lWeekdays.length);
1554 
1555         String[] aWeekdays = calData.getStringArray("dayNames", "abbreviated");
1556         shortWeekdays = new String[8];
1557         shortWeekdays[0] = "";  // 1-based
1558         System.arraycopy(aWeekdays, 0, shortWeekdays, 1, aWeekdays.length);
1559 
1560         String[] sWeekdays = calData.getStringArray("dayNames", "short");
1561         shorterWeekdays = new String[8];
1562         shorterWeekdays[0] = "";  // 1-based
1563         System.arraycopy(sWeekdays, 0, shorterWeekdays, 1, sWeekdays.length);
1564 
1565         String [] nWeekdays = null;
1566         try {
1567            nWeekdays = calData.getStringArray("dayNames", "narrow");
1568         }
1569         catch (MissingResourceException e) {
1570             try {
1571                 nWeekdays = calData.getStringArray("dayNames", "stand-alone", "narrow");
1572             }
1573             catch (MissingResourceException e1) {
1574                 nWeekdays = calData.getStringArray("dayNames", "abbreviated");
1575             }
1576         }
1577         narrowWeekdays = new String[8];
1578         narrowWeekdays[0] = "";  // 1-based
1579         System.arraycopy(nWeekdays, 0, narrowWeekdays, 1, nWeekdays.length);
1580 
1581         String [] swWeekdays = null;
1582         swWeekdays = calData.getStringArray("dayNames", "stand-alone", "wide");
1583         standaloneWeekdays = new String[8];
1584         standaloneWeekdays[0] = "";  // 1-based
1585         System.arraycopy(swWeekdays, 0, standaloneWeekdays, 1, swWeekdays.length);
1586 
1587         String [] saWeekdays = null;
1588         saWeekdays = calData.getStringArray("dayNames", "stand-alone", "abbreviated");
1589         standaloneShortWeekdays = new String[8];
1590         standaloneShortWeekdays[0] = "";  // 1-based
1591         System.arraycopy(saWeekdays, 0, standaloneShortWeekdays, 1, saWeekdays.length);
1592 
1593         String [] ssWeekdays = null;
1594         ssWeekdays = calData.getStringArray("dayNames", "stand-alone", "short");
1595         standaloneShorterWeekdays = new String[8];
1596         standaloneShorterWeekdays[0] = "";  // 1-based
1597         System.arraycopy(ssWeekdays, 0, standaloneShorterWeekdays, 1, ssWeekdays.length);
1598 
1599         String [] snWeekdays = null;
1600         snWeekdays = calData.getStringArray("dayNames", "stand-alone", "narrow");
1601         standaloneNarrowWeekdays = new String[8];
1602         standaloneNarrowWeekdays[0] = "";  // 1-based
1603         System.arraycopy(snWeekdays, 0, standaloneNarrowWeekdays, 1, snWeekdays.length);
1604 
1605         ampms = calData.getStringArray("AmPmMarkers");
1606         ampmsNarrow = calData.getStringArray("AmPmMarkersNarrow");
1607 
1608         quarters = calData.getStringArray("quarters", "wide");
1609         shortQuarters = calData.getStringArray("quarters", "abbreviated");
1610 
1611         standaloneQuarters = calData.getStringArray("quarters", "stand-alone", "wide");
1612         standaloneShortQuarters = calData.getStringArray("quarters", "stand-alone", "abbreviated");
1613 
1614         // The code for getting individual symbols in the leapMonthSymbols array is here
1615         // rather than in CalendarData because it depends on DateFormatSymbols constants...
1616         ICUResourceBundle monthPatternsBundle = null;
1617         try {
1618            monthPatternsBundle = calData.get("monthPatterns");
1619         }
1620         catch (MissingResourceException e) {
1621             monthPatternsBundle = null; // probably redundant
1622         }
1623         if (monthPatternsBundle != null) {
1624             leapMonthPatterns = new String[DT_MONTH_PATTERN_COUNT];
1625             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_FORMAT_WIDE] = calData.get("monthPatterns", "wide").get("leap").getString();
1626             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV] = calData.get("monthPatterns", "abbreviated").get("leap").getString();
1627             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_FORMAT_NARROW] = calData.get("monthPatterns", "narrow").get("leap").getString();
1628             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE] = calData.get("monthPatterns", "stand-alone", "wide").get("leap").getString();
1629             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV] = calData.get("monthPatterns", "stand-alone", "abbreviated").get("leap").getString();
1630             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_STANDALONE_NARROW] = calData.get("monthPatterns", "stand-alone", "narrow").get("leap").getString();
1631             leapMonthPatterns[DT_LEAP_MONTH_PATTERN_NUMERIC] = calData.get("monthPatterns", "numeric", "all").get("leap").getString();
1632         }
1633 
1634         ICUResourceBundle cyclicNameSetsBundle = null;
1635         try {
1636            cyclicNameSetsBundle = calData.get("cyclicNameSets");
1637         }
1638         catch (MissingResourceException e) {
1639             cyclicNameSetsBundle = null; // probably redundant
1640         }
1641         if (cyclicNameSetsBundle != null) {
1642             shortYearNames = calData.get("cyclicNameSets", "years", "format", "abbreviated").getStringArray();
1643             shortZodiacNames = calData.get("cyclicNameSets", "zodiacs", "format", "abbreviated").getStringArray();
1644         }
1645 
1646         requestedLocale = desiredLocale;
1647 
1648         ICUResourceBundle rb =
1649             (ICUResourceBundle)UResourceBundle.getBundleInstance(
1650                 ICUResourceBundle.ICU_BASE_NAME, desiredLocale);
1651 
1652         // Because localized date/time pattern characters will be obsolete in CLDR,
1653         // we decided not to maintain localized pattern characters in ICU any more.
1654         // We always use the base pattern characters by default. (ticket#5597)
1655 
1656         //localPatternChars = rb.getString("localPatternChars");
1657         localPatternChars = patternChars;
1658 
1659         // TODO: obtain correct actual/valid locale later
1660         ULocale uloc = rb.getULocale();
1661         setLocale(uloc, uloc);
1662 
1663         capitalization = new HashMap<CapitalizationContextUsage,boolean[]>();
1664         boolean[] noTransforms = new boolean[2];
1665         noTransforms[0] = false;
1666         noTransforms[1] = false;
1667         CapitalizationContextUsage allUsages[] = CapitalizationContextUsage.values();
1668         for (CapitalizationContextUsage usage: allUsages) {
1669             capitalization.put(usage, noTransforms);
1670         }
1671         UResourceBundle contextTransformsBundle = null;
1672         try {
1673            contextTransformsBundle = (UResourceBundle)rb.getWithFallback("contextTransforms");
1674         }
1675         catch (MissingResourceException e) {
1676             contextTransformsBundle = null; // probably redundant
1677         }
1678         if (contextTransformsBundle != null) {
1679             UResourceBundleIterator ctIterator = contextTransformsBundle.getIterator();
1680             while ( ctIterator.hasNext() ) {
1681                 UResourceBundle contextTransformUsage = ctIterator.next();
1682                 int[] intVector = contextTransformUsage.getIntVector();
1683                 if (intVector.length >= 2) {
1684                     String usageKey = contextTransformUsage.getKey();
1685                     CapitalizationContextUsage usage = contextUsageTypeMap.get(usageKey);
1686                     if (usage != null) {
1687                         boolean[] transforms = new boolean[2];
1688                         transforms[0] = (intVector[0] != 0);
1689                         transforms[1] = (intVector[1] != 0);
1690                         capitalization.put(usage, transforms);
1691                     }
1692                 }
1693             }
1694         }
1695 
1696         NumberingSystem ns = NumberingSystem.getInstance(desiredLocale);
1697         String nsName = ns == null ? "latn" : ns.getName();  // Latin is default.
1698         String tsPath = "NumberElements/" + nsName + "/symbols/timeSeparator";
1699         try {
1700             setTimeSeparatorString(rb.getStringWithFallback(tsPath));
1701         } catch (MissingResourceException e) {
1702             setTimeSeparatorString(DEFAULT_TIME_SEPARATOR);
1703         }
1704     }
1705 
arrayOfArrayEquals(Object[][] aa1, Object[][]aa2)1706     private static final boolean arrayOfArrayEquals(Object[][] aa1, Object[][]aa2) {
1707         if (aa1 == aa2) { // both are null
1708             return true;
1709         }
1710         if (aa1 == null || aa2 == null) { // one is null and the other is not
1711             return false;
1712         }
1713         if (aa1.length != aa2.length) {
1714             return false;
1715         }
1716         boolean equal = true;
1717         for (int i = 0; i < aa1.length; i++) {
1718             equal = Utility.arrayEquals(aa1[i], aa2[i]);
1719             if (!equal) {
1720                 break;
1721             }
1722         }
1723         return equal;
1724     }
1725 
1726     /*
1727      * save the input locale
1728      */
1729     private ULocale requestedLocale;
1730 
1731     /*
1732      * Clones an array of Strings.
1733      * @param srcArray the source array to be cloned.
1734      * @return a cloned array.
1735      */
duplicate(String[] srcArray)1736     private final String[] duplicate(String[] srcArray)
1737     {
1738         return srcArray.clone();
1739     }
1740 
duplicate(String[][] srcArray)1741     private final String[][] duplicate(String[][] srcArray)
1742     {
1743         String[][] aCopy = new String[srcArray.length][];
1744         for (int i = 0; i < srcArray.length; ++i)
1745             aCopy[i] = duplicate(srcArray[i]);
1746         return aCopy;
1747     }
1748 
1749     /*
1750      * Compares the equality of the two arrays of String.
1751      * @param current this String array.
1752      * @param other that String array.
1753     private final boolean equals(String[] current, String[] other)
1754     {
1755         int count = current.length;
1756 
1757         for (int i = 0; i < count; ++i)
1758             if (!current[i].equals(other[i]))
1759                 return false;
1760         return true;
1761     }
1762      */
1763 
1764     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1765 
1766     /**
1767      * Returns the {@link DateFormatSymbols} object that should be used to format a
1768      * calendar system's dates in the given locale.
1769      * <p>
1770      * <b>Subclassing:</b><br>
1771      * When creating a new Calendar subclass, you must create the
1772      * {@link ResourceBundle ResourceBundle}
1773      * containing its {@link DateFormatSymbols DateFormatSymbols} in a specific place.
1774      * The resource bundle name is based on the calendar's fully-specified
1775      * class name, with ".resources" inserted at the end of the package name
1776      * (just before the class name) and "Symbols" appended to the end.
1777      * For example, the bundle corresponding to "com.ibm.icu.util.HebrewCalendar"
1778      * is "com.ibm.icu.impl.data.HebrewCalendarSymbols".
1779      * <p>
1780      * Within the ResourceBundle, this method searches for five keys:
1781      * <ul>
1782      * <li><b>DayNames</b> -
1783      *      An array of strings corresponding to each possible
1784      *      value of the <code>DAY_OF_WEEK</code> field.  Even though
1785      *      <code>DAY_OF_WEEK</code> starts with <code>SUNDAY</code> = 1,
1786      *      This array is 0-based; the name for Sunday goes in the
1787      *      first position, at index 0.  If this key is not found
1788      *      in the bundle, the day names are inherited from the
1789      *      default <code>DateFormatSymbols</code> for the requested locale.
1790      *
1791      * <li><b>DayAbbreviations</b> -
1792      *      An array of abbreviated day names corresponding
1793      *      to the values in the "DayNames" array.  If this key
1794      *      is not found in the resource bundle, the "DayNames"
1795      *      values are used instead.  If neither key is found,
1796      *      the day abbreviations are inherited from the default
1797      *      <code>DateFormatSymbols</code> for the locale.
1798      *
1799      * <li><b>MonthNames</b> -
1800      *      An array of strings corresponding to each possible
1801      *      value of the <code>MONTH</code> field.  If this key is not found
1802      *      in the bundle, the month names are inherited from the
1803      *      default <code>DateFormatSymbols</code> for the requested locale.
1804      *
1805      * <li><b>MonthAbbreviations</b> -
1806      *      An array of abbreviated day names corresponding
1807      *      to the values in the "MonthNames" array.  If this key
1808      *      is not found in the resource bundle, the "MonthNames"
1809      *      values are used instead.  If neither key is found,
1810      *      the day abbreviations are inherited from the default
1811      *      <code>DateFormatSymbols</code> for the locale.
1812      *
1813      * <li><b>Eras</b> -
1814      *      An array of strings corresponding to each possible
1815      *      value of the <code>ERA</code> field.  If this key is not found
1816      *      in the bundle, the era names are inherited from the
1817      *      default <code>DateFormatSymbols</code> for the requested locale.
1818      * </ul>
1819      * <p>
1820      * @param cal       The calendar system whose date format symbols are desired.
1821      * @param locale    The locale whose symbols are desired.
1822      *
1823      * @see DateFormatSymbols#DateFormatSymbols(java.util.Locale)
1824      * @stable ICU 2.0
1825      */
DateFormatSymbols(Calendar cal, Locale locale)1826     public DateFormatSymbols(Calendar cal, Locale locale) {
1827         initializeData(ULocale.forLocale(locale), cal.getType());
1828     }
1829 
1830     /**
1831      * Returns the {@link DateFormatSymbols} object that should be used to format a
1832      * calendar system's dates in the given locale.
1833      * <p>
1834      * <b>Subclassing:</b><br>
1835      * When creating a new Calendar subclass, you must create the
1836      * {@link ResourceBundle ResourceBundle}
1837      * containing its {@link DateFormatSymbols DateFormatSymbols} in a specific place.
1838      * The resource bundle name is based on the calendar's fully-specified
1839      * class name, with ".resources" inserted at the end of the package name
1840      * (just before the class name) and "Symbols" appended to the end.
1841      * For example, the bundle corresponding to "com.ibm.icu.util.HebrewCalendar"
1842      * is "com.ibm.icu.impl.data.HebrewCalendarSymbols".
1843      * <p>
1844      * Within the ResourceBundle, this method searches for five keys:
1845      * <ul>
1846      * <li><b>DayNames</b> -
1847      *      An array of strings corresponding to each possible
1848      *      value of the <code>DAY_OF_WEEK</code> field.  Even though
1849      *      <code>DAY_OF_WEEK</code> starts with <code>SUNDAY</code> = 1,
1850      *      This array is 0-based; the name for Sunday goes in the
1851      *      first position, at index 0.  If this key is not found
1852      *      in the bundle, the day names are inherited from the
1853      *      default <code>DateFormatSymbols</code> for the requested locale.
1854      *
1855      * <li><b>DayAbbreviations</b> -
1856      *      An array of abbreviated day names corresponding
1857      *      to the values in the "DayNames" array.  If this key
1858      *      is not found in the resource bundle, the "DayNames"
1859      *      values are used instead.  If neither key is found,
1860      *      the day abbreviations are inherited from the default
1861      *      <code>DateFormatSymbols</code> for the locale.
1862      *
1863      * <li><b>MonthNames</b> -
1864      *      An array of strings corresponding to each possible
1865      *      value of the <code>MONTH</code> field.  If this key is not found
1866      *      in the bundle, the month names are inherited from the
1867      *      default <code>DateFormatSymbols</code> for the requested locale.
1868      *
1869      * <li><b>MonthAbbreviations</b> -
1870      *      An array of abbreviated day names corresponding
1871      *      to the values in the "MonthNames" array.  If this key
1872      *      is not found in the resource bundle, the "MonthNames"
1873      *      values are used instead.  If neither key is found,
1874      *      the day abbreviations are inherited from the default
1875      *      <code>DateFormatSymbols</code> for the locale.
1876      *
1877      * <li><b>Eras</b> -
1878      *      An array of strings corresponding to each possible
1879      *      value of the <code>ERA</code> field.  If this key is not found
1880      *      in the bundle, the era names are inherited from the
1881      *      default <code>DateFormatSymbols</code> for the requested locale.
1882      * </ul>
1883      * <p>
1884      * @param cal       The calendar system whose date format symbols are desired.
1885      * @param locale    The ulocale whose symbols are desired.
1886      *
1887      * @see DateFormatSymbols#DateFormatSymbols(java.util.Locale)
1888      * @stable ICU 3.2
1889      */
DateFormatSymbols(Calendar cal, ULocale locale)1890     public DateFormatSymbols(Calendar cal, ULocale locale) {
1891         initializeData(locale, cal.getType());
1892     }
1893 
1894     /**
1895      * Variant of DateFormatSymbols(Calendar, Locale) that takes the Calendar class
1896      * instead of a Calendar instance.
1897      * @see #DateFormatSymbols(Calendar, Locale)
1898      * @stable ICU 2.2
1899      */
DateFormatSymbols(Class<? extends Calendar> calendarClass, Locale locale)1900     public DateFormatSymbols(Class<? extends Calendar> calendarClass, Locale locale) {
1901         this(calendarClass, ULocale.forLocale(locale));
1902     }
1903 
1904     /**
1905      * Variant of DateFormatSymbols(Calendar, ULocale) that takes the Calendar class
1906      * instead of a Calendar instance.
1907      * @see #DateFormatSymbols(Calendar, Locale)
1908      * @stable ICU 3.2
1909      */
DateFormatSymbols(Class<? extends Calendar> calendarClass, ULocale locale)1910     public DateFormatSymbols(Class<? extends Calendar> calendarClass, ULocale locale) {
1911         String fullName = calendarClass.getName();
1912         int lastDot = fullName.lastIndexOf('.');
1913         String className = fullName.substring(lastDot+1);
1914         String calType = null;
1915         for (String[] calClassInfo : CALENDAR_CLASSES) {
1916             if (calClassInfo[0].equals(className)) {
1917                 calType = calClassInfo[1];
1918                 break;
1919             }
1920         }
1921         if (calType == null) {
1922             calType = className.replaceAll("Calendar", "").toLowerCase(Locale.ENGLISH);
1923         }
1924 
1925         initializeData(locale, calType);
1926     }
1927 
1928     /**
1929      * Fetches a custom calendar's DateFormatSymbols out of the given resource
1930      * bundle.  Symbols that are not overridden are inherited from the
1931      * default DateFormatSymbols for the locale.
1932      * @see DateFormatSymbols#DateFormatSymbols(java.util.Locale)
1933      * @stable ICU 2.0
1934      */
DateFormatSymbols(ResourceBundle bundle, Locale locale)1935     public DateFormatSymbols(ResourceBundle bundle, Locale locale) {
1936         this(bundle, ULocale.forLocale(locale));
1937     }
1938 
1939     /**
1940      * Fetches a custom calendar's DateFormatSymbols out of the given resource
1941      * bundle.  Symbols that are not overridden are inherited from the
1942      * default DateFormatSymbols for the locale.
1943      * @see DateFormatSymbols#DateFormatSymbols(java.util.Locale)
1944      * @stable ICU 3.2
1945      */
DateFormatSymbols(ResourceBundle bundle, ULocale locale)1946     public DateFormatSymbols(ResourceBundle bundle, ULocale locale) {
1947         initializeData(locale,
1948             new CalendarData((ICUResourceBundle)bundle, CalendarUtil.getCalendarType(locale)));
1949     }
1950 
1951     /**
1952      * Finds the ResourceBundle containing the date format information for
1953      * a specified calendar subclass in a given locale.
1954      * <p>
1955      * The resource bundle name is based on the calendar's fully-specified
1956      * class name, with ".resources" inserted at the end of the package name
1957      * (just before the class name) and "Symbols" appended to the end.
1958      * For example, the bundle corresponding to "com.ibm.icu.util.HebrewCalendar"
1959      * is "com.ibm.icu.impl.data.HebrewCalendarSymbols".
1960      * <p>
1961      * <b>Note:</b>Because of the structural changes in the ICU locale bundle,
1962      * this API no longer works as described.  This method always returns null.
1963      * @deprecated ICU 4.0
1964      */
1965     @Deprecated
1966     // This API was formerly @stable ICU 2.0
getDateFormatBundle(Class<? extends Calendar> calendarClass, Locale locale)1967     static public ResourceBundle getDateFormatBundle(Class<? extends Calendar> calendarClass,
1968                                                      Locale locale)
1969         throws MissingResourceException {
1970         return null;
1971     }
1972 
1973     /**
1974      * Finds the ResourceBundle containing the date format information for
1975      * a specified calendar subclass in a given locale.
1976      * <p>
1977      * The resource bundle name is based on the calendar's fully-specified
1978      * class name, with ".resources" inserted at the end of the package name
1979      * (just before the class name) and "Symbols" appended to the end.
1980      * For example, the bundle corresponding to "com.ibm.icu.util.HebrewCalendar"
1981      * is "com.ibm.icu.impl.data.HebrewCalendarSymbols".
1982      * <p>
1983      * <b>Note:</b>Because of the structural changes in the ICU locale bundle,
1984      * this API no longer works as described.  This method always returns null.
1985      * @deprecated ICU 4.0
1986      */
1987     @Deprecated
1988     // This API was formerly @stable ICU 3.2
getDateFormatBundle(Class<? extends Calendar> calendarClass, ULocale locale)1989     static public ResourceBundle getDateFormatBundle(Class<? extends Calendar> calendarClass,
1990                                                      ULocale locale)
1991         throws MissingResourceException {
1992         return null;
1993     }
1994 
1995     /**
1996      * Variant of getDateFormatBundle(java.lang.Class, java.util.Locale) that takes
1997      * a Calendar instance instead of a Calendar class.
1998      * <p>
1999      * <b>Note:</b>Because of the structural changes in the ICU locale bundle,
2000      * this API no longer works as described.  This method always returns null.
2001      * @see #getDateFormatBundle(java.lang.Class, java.util.Locale)
2002      * @deprecated ICU 4.0
2003      */
2004     @Deprecated
2005     // This API was formerly @stable ICU 2.2
getDateFormatBundle(Calendar cal, Locale locale)2006     public static ResourceBundle getDateFormatBundle(Calendar cal, Locale locale)
2007         throws MissingResourceException {
2008         return null;
2009     }
2010 
2011     /**
2012      * Variant of getDateFormatBundle(java.lang.Class, java.util.Locale) that takes
2013      * a Calendar instance instead of a Calendar class.
2014      * <p>
2015      * <b>Note:</b>Because of the structural changes in the ICU locale bundle,
2016      * this API no longer works as described.  This method always returns null.
2017      * @see #getDateFormatBundle(java.lang.Class, java.util.Locale)
2018      * @deprecated ICU 4.0
2019      */
2020     @Deprecated
2021     // This API was formerly @stable ICU 3.2
getDateFormatBundle(Calendar cal, ULocale locale)2022     public static ResourceBundle getDateFormatBundle(Calendar cal, ULocale locale)
2023         throws MissingResourceException {
2024         return null;
2025     }
2026 
2027     // -------- BEGIN ULocale boilerplate --------
2028 
2029     /**
2030      * Returns the locale that was used to create this object, or null.
2031      * This may may differ from the locale requested at the time of
2032      * this object's creation.  For example, if an object is created
2033      * for locale <tt>en_US_CALIFORNIA</tt>, the actual data may be
2034      * drawn from <tt>en</tt> (the <i>actual</i> locale), and
2035      * <tt>en_US</tt> may be the most specific locale that exists (the
2036      * <i>valid</i> locale).
2037      *
2038      * <p>Note: This method will be implemented in ICU 3.0; ICU 2.8
2039      * contains a partial preview implementation.  The * <i>actual</i>
2040      * locale is returned correctly, but the <i>valid</i> locale is
2041      * not, in most cases.
2042      * @param type type of information requested, either {@link
2043      * com.ibm.icu.util.ULocale#VALID_LOCALE} or {@link
2044      * com.ibm.icu.util.ULocale#ACTUAL_LOCALE}.
2045      * @return the information specified by <i>type</i>, or null if
2046      * this object was not constructed from locale data.
2047      * @see com.ibm.icu.util.ULocale
2048      * @see com.ibm.icu.util.ULocale#VALID_LOCALE
2049      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
2050      * @draft ICU 2.8 (retain)
2051      * @provisional This API might change or be removed in a future release.
2052      */
getLocale(ULocale.Type type)2053     public final ULocale getLocale(ULocale.Type type) {
2054         return type == ULocale.ACTUAL_LOCALE ?
2055             this.actualLocale : this.validLocale;
2056     }
2057 
2058     /**
2059      * Sets information about the locales that were used to create this
2060      * object.  If the object was not constructed from locale data,
2061      * both arguments should be set to null.  Otherwise, neither
2062      * should be null.  The actual locale must be at the same level or
2063      * less specific than the valid locale.  This method is intended
2064      * for use by factories or other entities that create objects of
2065      * this class.
2066      * @param valid the most specific locale containing any resource
2067      * data, or null
2068      * @param actual the locale containing data used to construct this
2069      * object, or null
2070      * @see com.ibm.icu.util.ULocale
2071      * @see com.ibm.icu.util.ULocale#VALID_LOCALE
2072      * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE
2073      */
setLocale(ULocale valid, ULocale actual)2074     final void setLocale(ULocale valid, ULocale actual) {
2075         // Change the following to an assertion later
2076         if ((valid == null) != (actual == null)) {
2077             ///CLOVER:OFF
2078             throw new IllegalArgumentException();
2079             ///CLOVER:ON
2080         }
2081         // Another check we could do is that the actual locale is at
2082         // the same level or less specific than the valid locale.
2083         this.validLocale = valid;
2084         this.actualLocale = actual;
2085     }
2086 
2087     /**
2088      * The most specific locale containing any resource data, or null.
2089      * @see com.ibm.icu.util.ULocale
2090      */
2091     private ULocale validLocale;
2092 
2093     /**
2094      * The locale containing data used to construct this object, or
2095      * null.
2096      * @see com.ibm.icu.util.ULocale
2097      */
2098     private ULocale actualLocale;
2099 
2100     // -------- END ULocale boilerplate --------
2101 
2102     /**
2103      * 3.8 or older version did not have localized GMT format
2104      * patterns.
2105      */
readObject(ObjectInputStream stream)2106     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
2107         stream.defaultReadObject();
2108     }
2109 }
2110