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