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}. 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