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