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 * @(#)TimeZone.java 1.51 00/01/19 6 * 7 * Copyright (C) 1996-2016, International Business Machines 8 * Corporation and others. All Rights Reserved. 9 */ 10 11 package ohos.global.icu.util; 12 13 import java.io.Serializable; 14 import java.util.Date; 15 import java.util.Locale; 16 import java.util.MissingResourceException; 17 import java.util.Set; 18 import java.util.logging.Logger; 19 20 import ohos.global.icu.impl.Grego; 21 import ohos.global.icu.impl.ICUConfig; 22 import ohos.global.icu.impl.ICUData; 23 import ohos.global.icu.impl.ICUResourceBundle; 24 import ohos.global.icu.impl.JavaTimeZone; 25 import ohos.global.icu.impl.TimeZoneAdapter; 26 import ohos.global.icu.impl.ZoneMeta; 27 import ohos.global.icu.text.TimeZoneFormat; 28 import ohos.global.icu.text.TimeZoneFormat.Style; 29 import ohos.global.icu.text.TimeZoneFormat.TimeType; 30 import ohos.global.icu.text.TimeZoneNames; 31 import ohos.global.icu.text.TimeZoneNames.NameType; 32 import ohos.global.icu.util.ULocale.Category; 33 34 /** 35 * <strong>[icu enhancement]</strong> ICU's replacement for {@link java.util.TimeZone}. Methods, fields, and other functionality specific to ICU are labeled '<strong>[icu]</strong>'. 36 * 37 * <p><code>TimeZone</code> represents a time zone offset, and also computes daylight 38 * savings. 39 * 40 * <p>Typically, you get a <code>TimeZone</code> using {@link #getDefault()} 41 * which creates a <code>TimeZone</code> based on the time zone where the program 42 * is running. For example, for a program running in Japan, <code>getDefault</code> 43 * creates a <code>TimeZone</code> object based on Japanese Standard Time. 44 * 45 * <p>You can also get a <code>TimeZone</code> using {@link #getTimeZone(String)} 46 * along with a time zone ID. For instance, the time zone ID for the 47 * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a 48 * U.S. Pacific Time <code>TimeZone</code> object with: 49 * 50 * <blockquote> 51 * <pre> 52 * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); 53 * </pre> 54 * </blockquote> 55 * You can use the {@link #getAvailableIDs()} method to iterate through 56 * all the supported time zone IDs, or getCanonicalID method to check 57 * if a time zone ID is supported or not. You can then choose a 58 * supported ID to get a <code>TimeZone</code>. 59 * If the time zone you want is not represented by one of the 60 * supported IDs, then you can create a custom time zone ID with 61 * the following syntax: 62 * 63 * <blockquote> 64 * <pre> 65 * GMT[+|-]hh[[:]mm] 66 * </pre> 67 * </blockquote> 68 * 69 * For example, you might specify GMT+14:00 as a custom 70 * time zone ID. The <code>TimeZone</code> that is returned 71 * when you specify a custom time zone ID uses the specified 72 * offset from GMT(=UTC) and does not observe daylight saving 73 * time. For example, you might specify GMT+14:00 as a custom 74 * time zone ID to create a TimeZone representing 14 hours ahead 75 * of GMT (with no daylight saving time). In addition, 76 * <code>getCanonicalID</code> can also be used to 77 * normalize a custom time zone ID. 78 * 79 * <p>For compatibility with JDK 1.1.x, some other three-letter time zone IDs 80 * (such as "PST", "CTT", "AST") are also supported. However, <strong>their 81 * use is deprecated</strong> because the same abbreviation is often used 82 * for multiple time zones (for example, "CST" could be U.S. "Central Standard 83 * Time" and "China Standard Time"), and the Java platform can then only 84 * recognize one of them. 85 * 86 * <p><strong>Note:</strong> Starting from ICU4J 4.0, you can optionally choose 87 * JDK <code>TimeZone</code> as the time zone implementation. The TimeZone factory 88 * method <code>getTimeZone</code> creates an instance of ICU's own <code>TimeZone</code> 89 * subclass by default. If you want to use the JDK implementation always, you can 90 * set the default time zone implementation type by the new method 91 * <code>setDefaultTimeZoneType</code>. Alternatively, you can change the initial 92 * default implementation type by setting a property below. 93 * 94 * <blockquote> 95 * <pre> 96 * # 97 * # The default TimeZone implementation type used by the ICU TimeZone 98 * # factory method. [ ICU | JDK ] 99 * # 100 * ohos.global.icu.util.TimeZone.DefaultTimeZoneType = ICU 101 * </pre> 102 * </blockquote> 103 * 104 * <p>This property is included in ICUConfig.properties in ohos.global.icu package. When the 105 * <code>TimeZone</code> class is loaded, the initialization code checks if the property 106 * <code>ohos.global.icu.util.TimeZone.DefaultTimeZoneType=xxx</code> is defined by the system 107 * properties. If not available, then it loads ICUConfig.properties to get the default 108 * time zone implementation type. The property setting is only used for the initial 109 * default value and you can change the default type by calling 110 * <code>setDefaultTimeZoneType</code> at runtime. 111 * 112 * @see Calendar 113 * @see GregorianCalendar 114 * @see SimpleTimeZone 115 * @author Mark Davis, Deborah Goldsmith, Chen-Lieh Huang, Alan Liu 116 */ 117 abstract public class TimeZone implements Serializable, Cloneable, Freezable<TimeZone> { 118 /** 119 * Logger instance for this class 120 */ 121 private static final Logger LOGGER = Logger.getLogger("ohos.global.icu.util.TimeZone"); 122 123 // using serialver from jdk1.4.2_05 124 private static final long serialVersionUID = -744942128318337471L; 125 126 /** 127 * Default constructor. (For invocation by subclass constructors, 128 * typically implicit.) 129 */ TimeZone()130 public TimeZone() { 131 } 132 133 /** 134 * Constructing a TimeZone with the given time zone ID. 135 * @param ID the time zone ID. 136 * @deprecated This API is ICU internal only. 137 * @hide deprecated on icu4j-org 138 * @hide draft / provisional / internal are hidden on OHOS 139 */ 140 @Deprecated TimeZone(String ID)141 protected TimeZone(String ID) { 142 if (ID == null) { 143 throw new NullPointerException(); 144 } 145 this.ID = ID; 146 } 147 148 /** 149 * <strong>[icu]</strong> A time zone implementation type indicating ICU's own TimeZone used by 150 * <code>getTimeZone</code>, <code>setDefaultTimeZoneType</code> 151 * and <code>getDefaultTimeZoneType</code>. 152 */ 153 public static final int TIMEZONE_ICU = 0; 154 /** 155 * <strong>[icu]</strong> A time zone implementation type indicating the {@link java.util.TimeZone} 156 * used by <code>getTimeZone</code>, <code>setDefaultTimeZoneType</code> 157 * and <code>getDefaultTimeZoneType</code>. 158 */ 159 public static final int TIMEZONE_JDK = 1; 160 161 /** 162 * A style specifier for <code>getDisplayName()</code> indicating 163 * a short name, such as "PST." 164 * @see #LONG 165 */ 166 public static final int SHORT = 0; 167 168 /** 169 * A style specifier for <code>getDisplayName()</code> indicating 170 * a long name, such as "Pacific Standard Time." 171 * @see #SHORT 172 */ 173 public static final int LONG = 1; 174 175 /** 176 * <strong>[icu]</strong> A style specifier for <code>getDisplayName()</code> indicating 177 * a short generic name, such as "PT." 178 * @see #LONG_GENERIC 179 */ 180 public static final int SHORT_GENERIC = 2; 181 182 /** 183 * <strong>[icu]</strong> A style specifier for <code>getDisplayName()</code> indicating 184 * a long generic name, such as "Pacific Time." 185 * @see #SHORT_GENERIC 186 */ 187 public static final int LONG_GENERIC = 3; 188 189 /** 190 * <strong>[icu]</strong> A style specifier for <code>getDisplayName()</code> indicating 191 * a short name derived from the timezone's offset, such as "-0800." 192 * @see #LONG_GMT 193 */ 194 public static final int SHORT_GMT = 4; 195 196 /** 197 * <strong>[icu]</strong> A style specifier for <code>getDisplayName()</code> indicating 198 * a long name derived from the timezone's offset, such as "GMT-08:00." 199 * @see #SHORT_GMT 200 */ 201 public static final int LONG_GMT = 5; 202 203 /** 204 * <strong>[icu]</strong> A style specifier for <code>getDisplayName()</code> indicating 205 * a short name derived from the timezone's short standard or daylight 206 * timezone name ignoring commonlyUsed, such as "PDT." 207 */ 208 209 public static final int SHORT_COMMONLY_USED = 6; 210 211 /** 212 * <strong>[icu]</strong> A style specifier for <code>getDisplayName()</code> indicating 213 * a long name derived from the timezone's fallback name, such as 214 * "United States (Los Angeles)." 215 */ 216 public static final int GENERIC_LOCATION = 7; 217 218 /** 219 * <strong>[icu]</strong> The time zone ID reserved for unknown time zone. 220 * @see #getTimeZone(String) 221 */ 222 public static final String UNKNOWN_ZONE_ID = "Etc/Unknown"; 223 224 /** 225 * The canonical ID for GMT(UTC) time zone. 226 */ 227 static final String GMT_ZONE_ID = "Etc/GMT"; 228 229 /** 230 * <strong>[icu]</strong> The immutable (frozen) "unknown" time zone. 231 * It behaves like the GMT/UTC time zone but has the UNKNOWN_ZONE_ID = "Etc/Unknown". 232 * {@link TimeZone#getTimeZone(String)} returns a mutable clone of this 233 * time zone if the input ID is not recognized. 234 * 235 * @see #UNKNOWN_ZONE_ID 236 * @see #getTimeZone(String) 237 */ 238 public static final TimeZone UNKNOWN_ZONE = new ConstantZone(0, UNKNOWN_ZONE_ID).freeze(); 239 240 /** 241 * <strong>[icu]</strong> The immutable GMT (=UTC) time zone. Its ID is "Etc/GMT". 242 */ 243 public static final TimeZone GMT_ZONE = new ConstantZone(0, GMT_ZONE_ID).freeze(); 244 245 /** 246 * <strong>[icu]</strong> System time zone type constants used by filtering zones in 247 * {@link TimeZone#getAvailableIDs(SystemTimeZoneType, String, Integer)} 248 */ 249 public enum SystemTimeZoneType { 250 /** 251 * Any system zones. 252 */ 253 ANY, 254 255 /** 256 * Canonical system zones. 257 */ 258 CANONICAL, 259 260 /** 261 * Canonical system zones associated with actual locations. 262 */ 263 CANONICAL_LOCATION, 264 } 265 266 /** 267 * Gets the time zone offset, for current date, modified in case of 268 * daylight savings. This is the offset to add *to* UTC to get local time. 269 * @param era the era of the given date. 270 * @param year the year in the given date. 271 * @param month the month in the given date. 272 * Month is 0-based. e.g., 0 for January. 273 * @param day the day-in-month of the given date. 274 * @param dayOfWeek the day-of-week of the given date. 275 * @param milliseconds the millis in day in <em>standard</em> local time. 276 * @return the offset to add *to* GMT to get local time. 277 */ getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds)278 abstract public int getOffset(int era, int year, int month, int day, 279 int dayOfWeek, int milliseconds); 280 281 282 /** 283 * Returns the offset of this time zone from UTC at the specified 284 * date. If Daylight Saving Time is in effect at the specified 285 * date, the offset value is adjusted with the amount of daylight 286 * saving. 287 * 288 * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT 289 * @return the amount of time in milliseconds to add to UTC to get local time. 290 * 291 * @see Calendar#ZONE_OFFSET 292 * @see Calendar#DST_OFFSET 293 * @see #getOffset(long, boolean, int[]) 294 */ getOffset(long date)295 public int getOffset(long date) { 296 int[] result = new int[2]; 297 getOffset(date, false, result); 298 return result[0]+result[1]; 299 } 300 301 /** 302 * Returns the time zone raw and GMT offset for the given moment 303 * in time. Upon return, local-millis = GMT-millis + rawOffset + 304 * dstOffset. All computations are performed in the proleptic 305 * Gregorian calendar. The default implementation in the TimeZone 306 * class delegates to the 8-argument getOffset(). 307 * 308 * @param date moment in time for which to return offsets, in 309 * units of milliseconds from January 1, 1970 0:00 GMT, either GMT 310 * time or local wall time, depending on `local'. 311 * @param local if true, `date' is local wall time; otherwise it 312 * is in GMT time. 313 * @param offsets output parameter to receive the raw offset, that 314 * is, the offset not including DST adjustments, in offsets[0], 315 * and the DST offset, that is, the offset to be added to 316 * `rawOffset' to obtain the total offset between local and GMT 317 * time, in offsets[1]. If DST is not in effect, the DST offset is 318 * zero; otherwise it is a positive value, typically one hour. 319 */ getOffset(long date, boolean local, int[] offsets)320 public void getOffset(long date, boolean local, int[] offsets) { 321 offsets[0] = getRawOffset(); 322 if (!local) { 323 date += offsets[0]; // now in local standard millis 324 } 325 326 // When local == true, date might not be in local standard 327 // millis. getOffset taking 6 parameters used here assume 328 // the given time in day is local standard time. 329 // At STD->DST transition, there is a range of time which 330 // does not exist. When 'date' is in this time range 331 // (and local == true), this method interprets the specified 332 // local time as DST. At DST->STD transition, there is a 333 // range of time which occurs twice. In this case, this 334 // method interprets the specified local time as STD. 335 // To support the behavior above, we need to call getOffset 336 // (with 6 args) twice when local == true and DST is 337 // detected in the initial call. 338 int fields[] = new int[6]; 339 for (int pass = 0; ; pass++) { 340 Grego.timeToFields(date, fields); 341 offsets[1] = getOffset(GregorianCalendar.AD, 342 fields[0], fields[1], fields[2], 343 fields[3], fields[5]) - offsets[0]; 344 345 if (pass != 0 || !local || offsets[1] == 0) { 346 break; 347 } 348 // adjust to local standard millis 349 date -= offsets[1]; 350 } 351 } 352 353 /** 354 * Sets the base time zone offset to GMT. 355 * This is the offset to add *to* UTC to get local time. 356 * @param offsetMillis the given base time zone offset to GMT. 357 */ setRawOffset(int offsetMillis)358 abstract public void setRawOffset(int offsetMillis); 359 360 /** 361 * Gets unmodified offset, NOT modified in case of daylight savings. 362 * This is the offset to add *to* UTC to get local time. 363 * @return the unmodified offset to add *to* UTC to get local time. 364 */ getRawOffset()365 abstract public int getRawOffset(); 366 367 /** 368 * Gets the ID of this time zone. 369 * @return the ID of this time zone. 370 */ getID()371 public String getID() { 372 return ID; 373 } 374 375 /** 376 * Sets the time zone ID. This does not change any other data in 377 * the time zone object. 378 * @param ID the new time zone ID. 379 */ setID(String ID)380 public void setID(String ID) { 381 if (ID == null) { 382 throw new NullPointerException(); 383 } 384 if (isFrozen()) { 385 throw new UnsupportedOperationException("Attempt to modify a frozen TimeZone instance."); 386 } 387 this.ID = ID; 388 } 389 390 /** 391 * Returns a name of this time zone suitable for presentation to the user 392 * in the default <code>DISPLAY</code> locale. 393 * This method returns the long generic name. 394 * If the display name is not available for the locale, 395 * a fallback based on the country, city, or time zone id will be used. 396 * @return the human-readable name of this time zone in the default locale. 397 * @see Category#DISPLAY 398 */ getDisplayName()399 public final String getDisplayName() { 400 return _getDisplayName(LONG_GENERIC, false, ULocale.getDefault(Category.DISPLAY)); 401 } 402 403 /** 404 * Returns a name of this time zone suitable for presentation to the user 405 * in the specified locale. 406 * This method returns the long generic name. 407 * If the display name is not available for the locale, 408 * a fallback based on the country, city, or time zone id will be used. 409 * @param locale the locale in which to supply the display name. 410 * @return the human-readable name of this time zone in the given locale 411 * or in the default locale if the given locale is not recognized. 412 */ getDisplayName(Locale locale)413 public final String getDisplayName(Locale locale) { 414 return _getDisplayName(LONG_GENERIC, false, ULocale.forLocale(locale)); 415 } 416 417 /** 418 * Returns a name of this time zone suitable for presentation to the user 419 * in the specified locale. 420 * This method returns the long name, not including daylight savings. 421 * If the display name is not available for the locale, 422 * a fallback based on the country, city, or time zone id will be used. 423 * @param locale the ulocale in which to supply the display name. 424 * @return the human-readable name of this time zone in the given locale 425 * or in the default ulocale if the given ulocale is not recognized. 426 */ getDisplayName(ULocale locale)427 public final String getDisplayName(ULocale locale) { 428 return _getDisplayName(LONG_GENERIC, false, locale); 429 } 430 431 /** 432 * Returns a name of this time zone suitable for presentation to the user 433 * in the default <code>DISPLAY</code> locale. 434 * If the display name is not available for the locale, 435 * then this method returns a string in the localized GMT offset format 436 * such as <code>GMT[+-]HH:mm</code>. 437 * @param daylight if true, return the daylight savings name. 438 * @param style the output style of the display name. Valid styles are 439 * <code>SHORT</code>, <code>LONG</code>, <code>SHORT_GENERIC</code>, 440 * <code>LONG_GENERIC</code>, <code>SHORT_GMT</code>, <code>LONG_GMT</code>, 441 * <code>SHORT_COMMONLY_USED</code> or <code>GENERIC_LOCATION</code>. 442 * @return the human-readable name of this time zone in the default locale. 443 * @see Category#DISPLAY 444 */ getDisplayName(boolean daylight, int style)445 public final String getDisplayName(boolean daylight, int style) { 446 return getDisplayName(daylight, style, ULocale.getDefault(Category.DISPLAY)); 447 } 448 449 /** 450 * Returns a name of this time zone suitable for presentation to the user 451 * in the specified locale. 452 * If the display name is not available for the locale, 453 * then this method returns a string in the localized GMT offset format 454 * such as <code>GMT[+-]HH:mm</code>. 455 * @param daylight if true, return the daylight savings name. 456 * @param style the output style of the display name. Valid styles are 457 * <code>SHORT</code>, <code>LONG</code>, <code>SHORT_GENERIC</code>, 458 * <code>LONG_GENERIC</code>, <code>SHORT_GMT</code>, <code>LONG_GMT</code>, 459 * <code>SHORT_COMMONLY_USED</code> or <code>GENERIC_LOCATION</code>. 460 * @param locale the locale in which to supply the display name. 461 * @return the human-readable name of this time zone in the given locale 462 * or in the default locale if the given locale is not recognized. 463 * @exception IllegalArgumentException style is invalid. 464 */ getDisplayName(boolean daylight, int style, Locale locale)465 public String getDisplayName(boolean daylight, int style, Locale locale) { 466 return getDisplayName(daylight, style, ULocale.forLocale(locale)); 467 } 468 469 /** 470 * Returns a name of this time zone suitable for presentation to the user 471 * in the specified locale. 472 * If the display name is not available for the locale, 473 * then this method returns a string in the localized GMT offset format 474 * such as <code>GMT[+-]HH:mm</code>. 475 * @param daylight if true, return the daylight savings name. 476 * @param style the output style of the display name. Valid styles are 477 * <code>SHORT</code>, <code>LONG</code>, <code>SHORT_GENERIC</code>, 478 * <code>LONG_GENERIC</code>, <code>SHORT_GMT</code>, <code>LONG_GMT</code>, 479 * <code>SHORT_COMMONLY_USED</code> or <code>GENERIC_LOCATION</code>. 480 * @param locale the locale in which to supply the display name. 481 * @return the human-readable name of this time zone in the given locale 482 * or in the default locale if the given locale is not recognized. 483 * @exception IllegalArgumentException style is invalid. 484 */ getDisplayName(boolean daylight, int style, ULocale locale)485 public String getDisplayName(boolean daylight, int style, ULocale locale) { 486 if (style < SHORT || style > GENERIC_LOCATION) { 487 throw new IllegalArgumentException("Illegal style: " + style); 488 } 489 490 return _getDisplayName(style, daylight, locale); 491 } 492 493 /** 494 * internal version (which is called by public APIs) accepts 495 * SHORT, LONG, SHORT_GENERIC, LONG_GENERIC, SHORT_GMT, LONG_GMT, 496 * SHORT_COMMONLY_USED and GENERIC_LOCATION. 497 */ _getDisplayName(int style, boolean daylight, ULocale locale)498 private String _getDisplayName(int style, boolean daylight, ULocale locale) { 499 if (locale == null) { 500 throw new NullPointerException("locale is null"); 501 } 502 503 String result = null; 504 505 if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) { 506 // Generic format 507 TimeZoneFormat tzfmt = TimeZoneFormat.getInstance(locale); 508 long date = System.currentTimeMillis(); 509 Output<TimeType> timeType = new Output<>(TimeType.UNKNOWN); 510 511 switch (style) { 512 case GENERIC_LOCATION: 513 result = tzfmt.format(Style.GENERIC_LOCATION, this, date, timeType); 514 break; 515 case LONG_GENERIC: 516 result = tzfmt.format(Style.GENERIC_LONG, this, date, timeType); 517 break; 518 case SHORT_GENERIC: 519 result = tzfmt.format(Style.GENERIC_SHORT, this, date, timeType); 520 break; 521 } 522 523 // Generic format many use Localized GMT as the final fallback. 524 // When Localized GMT format is used, the result might not be 525 // appropriate for the requested daylight value. 526 if (daylight && timeType.value == TimeType.STANDARD || 527 !daylight && timeType.value == TimeType.DAYLIGHT) { 528 int offset = daylight ? getRawOffset() + getDSTSavings() : getRawOffset(); 529 result = (style == SHORT_GENERIC) ? 530 tzfmt.formatOffsetShortLocalizedGMT(offset) : tzfmt.formatOffsetLocalizedGMT(offset); 531 } 532 533 } else if (style == LONG_GMT || style == SHORT_GMT) { 534 // Offset format 535 TimeZoneFormat tzfmt = TimeZoneFormat.getInstance(locale); 536 int offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset(); 537 switch (style) { 538 case LONG_GMT: 539 result = tzfmt.formatOffsetLocalizedGMT(offset); 540 break; 541 case SHORT_GMT: 542 result = tzfmt.formatOffsetISO8601Basic(offset, false, false, false); 543 break; 544 } 545 } else { 546 // Specific format 547 assert(style == LONG || style == SHORT || style == SHORT_COMMONLY_USED); 548 549 // Gets the name directly from TimeZoneNames 550 long date = System.currentTimeMillis(); 551 TimeZoneNames tznames = TimeZoneNames.getInstance(locale); 552 NameType nameType = null; 553 switch (style) { 554 case LONG: 555 nameType = daylight ? NameType.LONG_DAYLIGHT : NameType.LONG_STANDARD; 556 break; 557 case SHORT: 558 case SHORT_COMMONLY_USED: 559 nameType = daylight ? NameType.SHORT_DAYLIGHT : NameType.SHORT_STANDARD; 560 break; 561 } 562 result = tznames.getDisplayName(ZoneMeta.getCanonicalCLDRID(this), nameType, date); 563 if (result == null) { 564 // Fallback to localized GMT 565 TimeZoneFormat tzfmt = TimeZoneFormat.getInstance(locale); 566 int offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset(); 567 result = (style == LONG) ? 568 tzfmt.formatOffsetLocalizedGMT(offset) : tzfmt.formatOffsetShortLocalizedGMT(offset); 569 } 570 } 571 assert(result != null); 572 573 return result; 574 } 575 576 /** 577 * Returns the amount of time to be added to local standard time 578 * to get local wall clock time. 579 * <p> 580 * The default implementation always returns 3600000 milliseconds 581 * (i.e., one hour) if this time zone observes Daylight Saving 582 * Time. Otherwise, 0 (zero) is returned. 583 * <p> 584 * If an underlying TimeZone implementation subclass supports 585 * historical Daylight Saving Time changes, this method returns 586 * the known latest daylight saving value. 587 * 588 * @return the amount of saving time in milliseconds 589 */ getDSTSavings()590 public int getDSTSavings() { 591 if (useDaylightTime()) { 592 return 3600000; 593 } 594 return 0; 595 } 596 597 /** 598 * Queries if this time zone uses daylight savings time. 599 * @return true if this time zone uses daylight savings time, 600 * false, otherwise. 601 * <p><strong>Note:</strong>The default implementation of 602 * ICU TimeZone uses the tz database, which supports historic 603 * rule changes, for system time zones. With the implementation, 604 * there are time zones that used daylight savings time in the 605 * past, but no longer used currently. For example, Asia/Tokyo has 606 * never used daylight savings time since 1951. Most clients would 607 * expect that this method to return <code>false</code> for such case. 608 * The default implementation of this method returns <code>true</code> 609 * when the time zone uses daylight savings time in the current 610 * (Gregorian) calendar year. 611 */ useDaylightTime()612 abstract public boolean useDaylightTime(); 613 614 /** 615 * Queries if this time zone is in daylight saving time or will observe 616 * daylight saving time at any future time. 617 * <p>The default implementation in this class returns <code>true</code> if {@link #useDaylightTime()} 618 * or {@link #inDaylightTime(Date) inDaylightTime(new Date())} returns <code>true</code>. 619 * <p> 620 * <strong>Note:</strong> This method was added for {@link java.util.TimeZone} compatibility 621 * support. The {@link java.util.TimeZone#useDaylightTime()} method only checks the last known 622 * rule(s), therefore it may return false even the zone observes daylight saving time currently. 623 * {@link java.util.TimeZone} added <code>observesDaylightTime()</code> to resolve the issue. 624 * In ICU, {@link #useDaylightTime()} works differently. The ICU implementation checks if the 625 * zone uses daylight saving time in the current calendar year. Therefore, it will never return 626 * <code>false</code> if daylight saving time is currently used. 627 * <p> 628 * ICU's TimeZone subclass implementations override this method to support the same behavior 629 * with {@link java.util.TimeZone#observesDaylightTime()}. Unlike {@link #useDaylightTime()}, 630 * the implementation does not take past daylight saving time into account, so 631 * that this method may return <code>false</code> even when {@link #useDaylightTime()} returns 632 * <code>true</code>. 633 * 634 * @return <code>true</code> if this time zone is in daylight saving time or will observe 635 * daylight saving time at any future time. 636 * @see #useDaylightTime 637 */ observesDaylightTime()638 public boolean observesDaylightTime() { 639 return useDaylightTime() || inDaylightTime(new Date()); 640 } 641 642 /** 643 * Queries if the given date is in daylight savings time in 644 * this time zone. 645 * @param date the given Date. 646 * @return true if the given date is in daylight savings time, 647 * false, otherwise. 648 */ inDaylightTime(Date date)649 abstract public boolean inDaylightTime(Date date); 650 651 /** 652 * Gets the <code>TimeZone</code> for the given ID. 653 * 654 * @param ID the ID for a <code>TimeZone</code>, such as "America/Los_Angeles", 655 * or a custom ID such as "GMT-8:00". Note that the support of abbreviations, 656 * such as "PST", is for JDK 1.1.x compatibility only and full names should be used. 657 * 658 * @return the specified <code>TimeZone</code>, or a mutable clone of the UNKNOWN_ZONE 659 * if the given ID cannot be understood or if the given ID is "Etc/Unknown". 660 * @see #UNKNOWN_ZONE 661 */ getTimeZone(String ID)662 public static TimeZone getTimeZone(String ID) { 663 return getTimeZone(ID, TZ_IMPL, false); 664 } 665 666 /** 667 * Gets the <code>TimeZone</code> for the given ID. The instance of <code>TimeZone</code> 668 * returned by this method is immutable. Any methods mutate the instance({@link #setID(String)}, 669 * {@link #setRawOffset(int)}) will throw <code>UnsupportedOperationException</code> upon its 670 * invocation. 671 * 672 * @param ID the ID for a <code>TimeZone</code>, such as "America/Los_Angeles", 673 * or a custom ID such as "GMT-8:00". Note that the support of abbreviations, 674 * such as "PST", is for JDK 1.1.x compatibility only and full names should be used. 675 * 676 * @return the specified <code>TimeZone</code>, or the UNKNOWN_ZONE 677 * if the given ID cannot be understood. 678 * @see #UNKNOWN_ZONE 679 */ getFrozenTimeZone(String ID)680 public static TimeZone getFrozenTimeZone(String ID) { 681 return getTimeZone(ID, TZ_IMPL, true); 682 } 683 684 /** 685 * Gets the <code>TimeZone</code> for the given ID and the timezone type. 686 * @param ID the ID for a <code>TimeZone</code>, such as "America/Los_Angeles", or a 687 * custom ID such as "GMT-8:00". Note that the support of abbreviations, such as 688 * "PST", is for JDK 1.1.x compatibility only and full names should be used. 689 * @param type Time zone type, either <code>TIMEZONE_ICU</code> or 690 * <code>TIMEZONE_JDK</code>. 691 * @return the specified <code>TimeZone</code>, or a mutable clone of the UNKNOWN_ZONE if the given ID 692 * cannot be understood or if the given ID is "Etc/Unknown". 693 * @see #UNKNOWN_ZONE 694 */ getTimeZone(String ID, int type)695 public static TimeZone getTimeZone(String ID, int type) { 696 return getTimeZone(ID, type, false); 697 } 698 699 /** 700 * Gets the <code>TimeZone</code> for the given ID and the timezone type. 701 * @param id time zone ID 702 * @param type time zone implementation type, TIMEZONE_JDK or TIMEZONE_ICU 703 * @param frozen specify if the returned object can be frozen 704 * @return the specified <code>TimeZone</code> or UNKNOWN_ZONE if the given ID 705 * cannot be understood. 706 */ getTimeZone(String id, int type, boolean frozen)707 private static TimeZone getTimeZone(String id, int type, boolean frozen) { 708 TimeZone result; 709 if (type == TIMEZONE_JDK) { 710 result = JavaTimeZone.createTimeZone(id); 711 if (result != null) { 712 return frozen ? result.freeze() : result; 713 } 714 result = getFrozenICUTimeZone(id, false); 715 } else { 716 result = getFrozenICUTimeZone(id, true); 717 } 718 if (result == null) { 719 LOGGER.fine("\"" +id + "\" is a bogus id so timezone is falling back to Etc/Unknown(GMT)."); 720 result = UNKNOWN_ZONE; 721 } 722 return frozen ? result : result.cloneAsThawed(); 723 } 724 725 /** 726 * Returns a frozen ICU type TimeZone object given a time zone ID. 727 * @param id the time zone ID 728 * @param trySystem if true tries the system time zones first otherwise skip to the 729 * custom time zones. 730 * @return the frozen ICU TimeZone or null if one could not be created. 731 */ getFrozenICUTimeZone(String id, boolean trySystem)732 static BasicTimeZone getFrozenICUTimeZone(String id, boolean trySystem) { 733 BasicTimeZone result = null; 734 if (trySystem) { 735 result = ZoneMeta.getSystemTimeZone(id); 736 } 737 if (result == null) { 738 result = ZoneMeta.getCustomTimeZone(id); 739 } 740 return result; 741 } 742 743 /** 744 * Sets the default time zone type used by <code>getTimeZone</code>. 745 * @param type time zone type, either <code>TIMEZONE_ICU</code> or 746 * <code>TIMEZONE_JDK</code>. 747 * @hide unsupported on OHOS 748 */ setDefaultTimeZoneType(int type)749 public static synchronized void setDefaultTimeZoneType(int type) { 750 if (type != TIMEZONE_ICU && type != TIMEZONE_JDK) { 751 throw new IllegalArgumentException("Invalid timezone type"); 752 } 753 TZ_IMPL = type; 754 } 755 756 /** 757 * <strong>[icu]</strong> Returns the default time zone type currently used. 758 * @return The default time zone type, either <code>TIMEZONE_ICU</code> or 759 * <code>TIMEZONE_JDK</code>. 760 * @hide unsupported on OHOS 761 */ getDefaultTimeZoneType()762 public static int getDefaultTimeZoneType() { 763 return TZ_IMPL; 764 } 765 766 /** 767 * <strong>[icu]</strong> Returns a set of time zone ID strings with the given filter conditions. 768 * <p><b>Note:</b>A <code>Set</code> returned by this method is 769 * immutable. 770 * @param zoneType The system time zone type. 771 * @param region The ISO 3166 two-letter country code or UN M.49 three-digit area code. 772 * When null, no filtering done by region. 773 * @param rawOffset An offset from GMT in milliseconds, ignoring the effect of daylight savings 774 * time, if any. When null, no filtering done by zone offset. 775 * @return an immutable set of system time zone IDs. 776 * @see SystemTimeZoneType 777 */ getAvailableIDs(SystemTimeZoneType zoneType, String region, Integer rawOffset)778 public static Set<String> getAvailableIDs(SystemTimeZoneType zoneType, 779 String region, Integer rawOffset) { 780 return ZoneMeta.getAvailableIDs(zoneType, region, rawOffset); 781 } 782 783 /** 784 * Return a new String array containing all system TimeZone IDs 785 * with the given raw offset from GMT. These IDs may be passed to 786 * <code>get()</code> to construct the corresponding TimeZone 787 * object. 788 * @param rawOffset the offset in milliseconds from GMT 789 * @return an array of IDs for system TimeZones with the given 790 * raw offset. If there are none, return a zero-length array. 791 * @see #getAvailableIDs(SystemTimeZoneType, String, Integer) 792 */ getAvailableIDs(int rawOffset)793 public static String[] getAvailableIDs(int rawOffset) { 794 Set<String> ids = getAvailableIDs(SystemTimeZoneType.ANY, null, Integer.valueOf(rawOffset)); 795 return ids.toArray(new String[0]); 796 } 797 798 /** 799 * Return a new String array containing all system TimeZone IDs 800 * associated with the given country. These IDs may be passed to 801 * <code>get()</code> to construct the corresponding TimeZone 802 * object. 803 * @param country a two-letter ISO 3166 country code, or <code>null</code> 804 * to return zones not associated with any country 805 * @return an array of IDs for system TimeZones in the given 806 * country. If there are none, return a zero-length array. 807 * @see #getAvailableIDs(SystemTimeZoneType, String, Integer) 808 */ getAvailableIDs(String country)809 public static String[] getAvailableIDs(String country) { 810 Set<String> ids = getAvailableIDs(SystemTimeZoneType.ANY, country, null); 811 return ids.toArray(new String[0]); 812 } 813 814 /** 815 * Return a new String array containing all system TimeZone IDs. 816 * These IDs (and only these IDs) may be passed to 817 * <code>get()</code> to construct the corresponding TimeZone 818 * object. 819 * @return an array of all system TimeZone IDs 820 * @see #getAvailableIDs(SystemTimeZoneType, String, Integer) 821 */ getAvailableIDs()822 public static String[] getAvailableIDs() { 823 Set<String> ids = getAvailableIDs(SystemTimeZoneType.ANY, null, null); 824 return ids.toArray(new String[0]); 825 } 826 827 /** 828 * <strong>[icu]</strong> Returns the number of IDs in the equivalency group that 829 * includes the given ID. An equivalency group contains zones 830 * that have the same GMT offset and rules. 831 * 832 * <p>The returned count includes the given ID; it is always >= 1 833 * for valid IDs. The given ID must be a system time zone. If it 834 * is not, returns zero. 835 * @param id a system time zone ID 836 * @return the number of zones in the equivalency group containing 837 * 'id', or zero if 'id' is not a valid system ID 838 * @see #getEquivalentID 839 */ countEquivalentIDs(String id)840 public static int countEquivalentIDs(String id) { 841 return ZoneMeta.countEquivalentIDs(id); 842 } 843 844 /** 845 * Returns an ID in the equivalency group that 846 * includes the given ID. An equivalency group contains zones 847 * that have the same GMT offset and rules. 848 * 849 * <p>The given index must be in the range 0..n-1, where n is the 850 * value returned by <code>countEquivalentIDs(id)</code>. For 851 * some value of 'index', the returned value will be equal to the 852 * given id. If the given id is not a valid system time zone, or 853 * if 'index' is out of range, then returns an empty string. 854 * @param id a system time zone ID 855 * @param index a value from 0 to n-1, where n is the value 856 * returned by <code>countEquivalentIDs(id)</code> 857 * @return the ID of the index-th zone in the equivalency group 858 * containing 'id', or an empty string if 'id' is not a valid 859 * system ID or 'index' is out of range 860 * @see #countEquivalentIDs 861 */ getEquivalentID(String id, int index)862 public static String getEquivalentID(String id, int index) { 863 return ZoneMeta.getEquivalentID(id, index); 864 } 865 866 /** 867 * Gets the default <code>TimeZone</code> for this host. 868 * The source of the default <code>TimeZone</code> 869 * may vary with implementation. 870 * @return a default <code>TimeZone</code>. 871 */ getDefault()872 public static TimeZone getDefault() { 873 // Copy the reference to the current defaultZone, 874 // so it won't be affected by setDefault(). 875 TimeZone tmpDefaultZone = defaultZone; 876 877 if (tmpDefaultZone == null) { 878 synchronized (java.util.TimeZone.class) { 879 synchronized(TimeZone.class) { 880 tmpDefaultZone = defaultZone; 881 if (tmpDefaultZone == null) { 882 if (TZ_IMPL == TIMEZONE_JDK) { 883 tmpDefaultZone = new JavaTimeZone(); 884 } else { 885 java.util.TimeZone temp = java.util.TimeZone.getDefault(); 886 tmpDefaultZone = getFrozenTimeZone(temp.getID()); 887 } 888 defaultZone = tmpDefaultZone; 889 } 890 } 891 } 892 } 893 894 return tmpDefaultZone.cloneAsThawed(); 895 } 896 897 /** 898 * Sets the <code>TimeZone</code> that is returned by the <code>getDefault</code> 899 * method. This method also sets a Java TimeZone equivalent to the input <code>tz</code> 900 * as the JVM's default time zone if not null. If <code>tz</code> is null, next 901 * {@link #getDefault()} method invocation will reset the default time zone 902 * synchronized with the JVM's default at that time. 903 * 904 * @param tz the new default time zone 905 * @hide unsupported on OHOS 906 */ setDefault(TimeZone tz)907 public static synchronized void setDefault(TimeZone tz) { 908 // Set default ICU time zone, used by #getDefault() 909 setICUDefault(tz); 910 911 if (tz != null) { 912 // Keep java.util.TimeZone default in sync so java.util.Date 913 // can interoperate with ohos.global.icu.util classes. 914 java.util.TimeZone jdkZone = null; 915 if (tz instanceof JavaTimeZone) { 916 jdkZone = ((JavaTimeZone)tz).unwrap(); 917 } else if (tz instanceof ohos.global.icu.impl.OlsonTimeZone) { 918 // Because of the lack of APIs supporting historic 919 // zone offset/dst saving in JDK TimeZone, 920 // wrapping ICU TimeZone with JDK TimeZone will 921 // cause historic offset calculation in Calendar/Date. 922 // JDK calendar implementation calls getRawOffset() and 923 // getDSTSavings() when the instance of JDK TimeZone 924 // is not an instance of JDK internal TimeZone subclass 925 // (sun.util.calendar.ZoneInfo). Ticket#6459 926 String icuID = tz.getID(); 927 jdkZone = java.util.TimeZone.getTimeZone(icuID); 928 if (!icuID.equals(jdkZone.getID())) { 929 // If the ID was unknown, retry with the canonicalized 930 // ID instead. This will ensure that JDK 1.1.x 931 // compatibility IDs supported by ICU (but not 932 // necessarily supported by the platform) work. 933 // Ticket#11483 934 icuID = getCanonicalID(icuID); 935 jdkZone = java.util.TimeZone.getTimeZone(icuID); 936 if (!icuID.equals(jdkZone.getID())) { 937 // JDK does not know the ID.. 938 jdkZone = null; 939 } 940 } 941 } 942 if (jdkZone == null) { 943 jdkZone = TimeZoneAdapter.wrap(tz); 944 } 945 java.util.TimeZone.setDefault(jdkZone); 946 } 947 } 948 949 /** 950 * Sets the <code>TimeZone</code> that is returned by the <code>getDefault</code> 951 * method. If <code>tz</code> is null, next {@link #getDefault()} method invocation 952 * will reset the default time zone synchronized with the JVM's default at that time. 953 * Unlike {@link #setDefault(TimeZone)}, this method does not change the JVM's 954 * default time zone. 955 * 956 * @param tz the new default time zone 957 * @deprecated This API is ICU internal only. 958 * @hide draft / provisional / internal are hidden on OHOS 959 */ 960 @Deprecated setICUDefault(TimeZone tz)961 public static synchronized void setICUDefault(TimeZone tz) { 962 if (tz == null) { 963 defaultZone = null; 964 } else if (tz.isFrozen()) { 965 // No need to create a defensive copy 966 defaultZone = tz; 967 } else { 968 // Creates a defensive copy and freeze it 969 defaultZone = ((TimeZone)tz.clone()).freeze(); 970 } 971 } 972 973 /** 974 * Returns true if this zone has the same rule and offset as another zone. 975 * That is, if this zone differs only in ID, if at all. Returns false 976 * if the other zone is null. 977 * @param other the <code>TimeZone</code> object to be compared with 978 * @return true if the other zone is not null and is the same as this one, 979 * with the possible exception of the ID 980 */ hasSameRules(TimeZone other)981 public boolean hasSameRules(TimeZone other) { 982 return other != null && 983 getRawOffset() == other.getRawOffset() && 984 useDaylightTime() == other.useDaylightTime(); 985 } 986 987 /** 988 * Overrides clone. 989 */ 990 @Override clone()991 public Object clone() { 992 if (isFrozen()) { 993 return this; 994 } 995 return cloneAsThawed(); 996 } 997 998 /** 999 * Overrides equals. 1000 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise. 1001 */ 1002 @Override equals(Object obj)1003 public boolean equals(Object obj){ 1004 if (this == obj) return true; 1005 if (obj == null || getClass() != obj.getClass()) return false; 1006 return (ID.equals(((TimeZone)obj).ID)); 1007 } 1008 1009 /** 1010 * Overrides hashCode. 1011 * @return a hash code value for this object. 1012 */ 1013 @Override hashCode()1014 public int hashCode(){ 1015 return ID.hashCode(); 1016 } 1017 1018 /** 1019 * <strong>[icu]</strong> Returns the time zone data version currently used by ICU. 1020 * 1021 * @return the version string, such as "2007f" 1022 * @throws MissingResourceException if ICU time zone resource bundle 1023 * is missing or the version information is not available. 1024 */ getTZDataVersion()1025 public static String getTZDataVersion() { 1026 // The implementation had been moved to VersionInfo. 1027 return VersionInfo.getTZDataVersion(); 1028 } 1029 1030 /** 1031 * <strong>[icu]</strong> Returns the canonical system time zone ID or the normalized 1032 * custom time zone ID for the given time zone ID. 1033 * @param id The input time zone ID to be canonicalized. 1034 * @return The canonical system time zone ID or the custom time zone ID 1035 * in normalized format for the given time zone ID. When the given time zone ID 1036 * is neither a known system time zone ID nor a valid custom time zone ID, 1037 * null is returned. 1038 */ getCanonicalID(String id)1039 public static String getCanonicalID(String id) { 1040 return getCanonicalID(id, null); 1041 } 1042 1043 /** 1044 * <strong>[icu]</strong> Returns the canonical system time zone ID or the normalized 1045 * custom time zone ID for the given time zone ID. 1046 * @param id The input time zone ID to be canonicalized. 1047 * @param isSystemID When non-null boolean array is specified and 1048 * the given ID is a known system time zone ID, true is set to <code>isSystemID[0]</code> 1049 * @return The canonical system time zone ID or the custom time zone ID 1050 * in normalized format for the given time zone ID. When the given time zone ID 1051 * is neither a known system time zone ID nor a valid custom time zone ID, 1052 * null is returned. 1053 */ getCanonicalID(String id, boolean[] isSystemID)1054 public static String getCanonicalID(String id, boolean[] isSystemID) { 1055 String canonicalID = null; 1056 boolean systemTzid = false; 1057 if (id != null && id.length() != 0) { 1058 if (id.equals(TimeZone.UNKNOWN_ZONE_ID)) { 1059 // special case - Etc/Unknown is a canonical ID, but not system ID 1060 canonicalID = TimeZone.UNKNOWN_ZONE_ID; 1061 systemTzid = false; 1062 } else { 1063 canonicalID = ZoneMeta.getCanonicalCLDRID(id); 1064 if (canonicalID != null) { 1065 systemTzid = true; 1066 } else { 1067 canonicalID = ZoneMeta.getCustomID(id); 1068 } 1069 } 1070 } 1071 if (isSystemID != null) { 1072 isSystemID[0] = systemTzid; 1073 } 1074 return canonicalID; 1075 } 1076 1077 /** 1078 * <strong>[icu]</strong> Returns the region code associated with the given 1079 * system time zone ID. The region code is either ISO 3166 1080 * 2-letter country code or UN M.49 3-digit area code. 1081 * When the time zone is not associated with a specific location, 1082 * for example - "Etc/UTC", "EST5EDT", then this method returns 1083 * "001" (UN M.49 area code for World). 1084 * @param id the system time zone ID. 1085 * @return the region code associated with the given 1086 * system time zone ID. 1087 * @throws IllegalArgumentException if <code>id</code> is not a known system ID. 1088 * @see #getAvailableIDs(String) 1089 */ getRegion(String id)1090 public static String getRegion(String id) { 1091 String region = null; 1092 // "Etc/Unknown" is not a system time zone ID, 1093 // but in the zone data. 1094 if (!id.equals(UNKNOWN_ZONE_ID)) { 1095 region = ZoneMeta.getRegion(id); 1096 } 1097 if (region == null) { 1098 // unknown id 1099 throw new IllegalArgumentException("Unknown system zone id: " + id); 1100 } 1101 return region; 1102 } 1103 1104 /** 1105 * <strong>[icu]</strong> Converts a system time zone ID to an equivalent Windows time zone ID. For example, 1106 * Windows time zone ID "Pacific Standard Time" is returned for input "America/Los_Angeles". 1107 * 1108 * <p>There are system time zones that cannot be mapped to Windows zones. When the input 1109 * system time zone ID is unknown or unmappable to a Windows time zone, then this 1110 * method returns <code>null</code>. 1111 * 1112 * <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html"> 1113 * Zone-Tzid mapping data</a>. The mapping data is updated time to time. To get the latest changes, 1114 * please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data"> 1115 * Updating the Time Zone Data</a>. 1116 * 1117 * @param id A system time zone ID 1118 * @return A Windows time zone ID mapped from the input system time zone ID, 1119 * or <code>null</code> when the input ID is unknown or unmappable. 1120 * @see #getIDForWindowsID(String, String) 1121 */ getWindowsID(String id)1122 public static String getWindowsID(String id) { 1123 // canonicalize the input ID 1124 boolean[] isSystemID = {false}; 1125 id = getCanonicalID(id, isSystemID); 1126 if (!isSystemID[0]) { 1127 // mapping data is only applicable to tz database IDs 1128 return null; 1129 } 1130 1131 UResourceBundle top = UResourceBundle.getBundleInstance( 1132 ICUData.ICU_BASE_NAME, "windowsZones", ICUResourceBundle.ICU_DATA_CLASS_LOADER); 1133 UResourceBundle mapTimezones = top.get("mapTimezones"); 1134 1135 UResourceBundleIterator resitr = mapTimezones.getIterator(); 1136 while (resitr.hasNext()) { 1137 UResourceBundle winzone = resitr.next(); 1138 if (winzone.getType() != UResourceBundle.TABLE) { 1139 continue; 1140 } 1141 UResourceBundleIterator rgitr = winzone.getIterator(); 1142 while (rgitr.hasNext()) { 1143 UResourceBundle regionalData = rgitr.next(); 1144 if (regionalData.getType() != UResourceBundle.STRING) { 1145 continue; 1146 } 1147 String[] tzids = regionalData.getString().split(" "); 1148 for (String tzid : tzids) { 1149 if (tzid.equals(id)) { 1150 return winzone.getKey(); 1151 } 1152 } 1153 } 1154 } 1155 1156 return null; 1157 } 1158 1159 /** 1160 * <strong>[icu]</strong> Converts a Windows time zone ID to an equivalent system time zone ID 1161 * for a region. For example, system time zone ID "America/Los_Angeles" is returned 1162 * for input Windows ID "Pacific Standard Time" and region "US" (or <code>null</code>), 1163 * "America/Vancouver" is returned for the same Windows ID "Pacific Standard Time" and 1164 * region "CA". 1165 * 1166 * <p>Not all Windows time zones can be mapped to system time zones. When the input 1167 * Windows time zone ID is unknown or unmappable to a system time zone, then this 1168 * method returns <code>null</code>. 1169 * 1170 * <p>This implementation utilizes <a href="http://unicode.org/cldr/charts/supplemental/zone_tzid.html"> 1171 * Zone-Tzid mapping data</a>. The mapping data is updated time to time. To get the latest changes, 1172 * please read the ICU user guide section <a href="http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data"> 1173 * Updating the Time Zone Data</a>. 1174 * 1175 * @param winid A Windows time zone ID 1176 * @param region A region code, or <code>null</code> if no regional preference. 1177 * @return A system time zone ID mapped from the input Windows time zone ID, 1178 * or <code>null</code> when the input ID is unknown or unmappable. 1179 * @see #getWindowsID(String) 1180 */ getIDForWindowsID(String winid, String region)1181 public static String getIDForWindowsID(String winid, String region) { 1182 String id = null; 1183 1184 UResourceBundle top = UResourceBundle.getBundleInstance( 1185 ICUData.ICU_BASE_NAME, "windowsZones", ICUResourceBundle.ICU_DATA_CLASS_LOADER); 1186 UResourceBundle mapTimezones = top.get("mapTimezones"); 1187 1188 try { 1189 UResourceBundle zones = mapTimezones.get(winid); 1190 if (region != null) { 1191 try { 1192 id = zones.getString(region); 1193 if (id != null) { 1194 // first ID delimited by space is the default one 1195 int endIdx = id.indexOf(' '); 1196 if (endIdx > 0) { 1197 id = id.substring(0, endIdx); 1198 } 1199 } 1200 } catch (MissingResourceException e) { 1201 // no explicit region mapping found 1202 } 1203 } 1204 if (id == null) { 1205 id = zones.getString("001"); 1206 } 1207 } catch (MissingResourceException e) { 1208 // no mapping data found 1209 } 1210 1211 return id; 1212 } 1213 1214 // Freezable stuffs 1215 1216 /** 1217 * {@inheritDoc} 1218 */ 1219 @Override isFrozen()1220 public boolean isFrozen() { 1221 return false; 1222 } 1223 1224 /** 1225 * {@inheritDoc} 1226 */ 1227 @Override freeze()1228 public TimeZone freeze() { 1229 throw new UnsupportedOperationException("Needs to be implemented by the subclass."); 1230 } 1231 1232 /** 1233 * {@inheritDoc} 1234 */ 1235 @Override cloneAsThawed()1236 public TimeZone cloneAsThawed() { 1237 try { 1238 TimeZone other = (TimeZone) super.clone(); 1239 return other; 1240 } catch (CloneNotSupportedException e) { 1241 throw new ICUCloneNotSupportedException(e); 1242 } 1243 } 1244 1245 // =======================privates=============================== 1246 1247 /** 1248 * The string identifier of this <code>TimeZone</code>. This is a 1249 * programmatic identifier used internally to look up <code>TimeZone</code> 1250 * objects from the system table and also to map them to their localized 1251 * display names. <code>ID</code> values are unique in the system 1252 * table but may not be for dynamically created zones. 1253 * @serial 1254 */ 1255 private String ID; 1256 1257 /** 1258 * The default time zone, or null if not set. 1259 */ 1260 private static volatile TimeZone defaultZone = null; 1261 1262 /** 1263 * TimeZone implementation type 1264 */ 1265 private static int TZ_IMPL = TIMEZONE_ICU; 1266 1267 /** 1268 * TimeZone implementation type initialization 1269 */ 1270 private static final String TZIMPL_CONFIG_KEY = "ohos.global.icu.util.TimeZone.DefaultTimeZoneType"; 1271 private static final String TZIMPL_CONFIG_ICU = "ICU"; 1272 private static final String TZIMPL_CONFIG_JDK = "JDK"; 1273 1274 static { 1275 String type = ICUConfig.get(TZIMPL_CONFIG_KEY, TZIMPL_CONFIG_ICU); 1276 if (type.equalsIgnoreCase(TZIMPL_CONFIG_JDK)) { 1277 TZ_IMPL = TIMEZONE_JDK; 1278 } 1279 } 1280 1281 /* 1282 * ConstantZone is a private TimeZone subclass dedicated for the two TimeZone class 1283 * constants - TimeZone.GMT_ZONE and TimeZone.UNKNOWN_ZONE. Previously, these zones 1284 * are instances of SimpleTimeZone. However, when the SimpleTimeZone constructor and 1285 * TimeZone's static methods (such as TimeZone.getDefault()) are called from multiple 1286 * threads at the same time, it causes a deadlock by TimeZone's static initializer 1287 * and SimpleTimeZone's static initializer. To avoid this issue, these TimeZone 1288 * constants (GMT/UNKNOWN) must be implemented by a class not visible from users. 1289 * See ticket#11343. 1290 */ 1291 private static final class ConstantZone extends TimeZone { 1292 private static final long serialVersionUID = 1L; 1293 1294 private int rawOffset; 1295 ConstantZone(int rawOffset, String ID)1296 private ConstantZone(int rawOffset, String ID) { 1297 super(ID); 1298 this.rawOffset = rawOffset; 1299 } 1300 1301 @Override getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds)1302 public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) { 1303 return rawOffset; 1304 } 1305 1306 @Override setRawOffset(int offsetMillis)1307 public void setRawOffset(int offsetMillis) { 1308 if (isFrozen()) { 1309 throw new UnsupportedOperationException("Attempt to modify a frozen TimeZone instance."); 1310 } 1311 rawOffset = offsetMillis; 1312 } 1313 1314 @Override getRawOffset()1315 public int getRawOffset() { 1316 return rawOffset; 1317 } 1318 1319 @Override useDaylightTime()1320 public boolean useDaylightTime() { 1321 return false; 1322 } 1323 1324 @Override inDaylightTime(Date date)1325 public boolean inDaylightTime(Date date) { 1326 return false; 1327 } 1328 1329 private volatile transient boolean isFrozen = false; 1330 1331 @Override isFrozen()1332 public boolean isFrozen() { 1333 return isFrozen; 1334 } 1335 1336 @Override freeze()1337 public TimeZone freeze() { 1338 isFrozen = true; 1339 return this; 1340 } 1341 1342 @Override cloneAsThawed()1343 public TimeZone cloneAsThawed() { 1344 ConstantZone tz = (ConstantZone)super.cloneAsThawed(); 1345 tz.isFrozen = false; 1346 return tz; 1347 } 1348 } 1349 } 1350 1351 //eof 1352