409 }
410 int offset = getRawOffset();
411 if (daylight) {
412 offset += getDSTSavings();
413 }
414 return ZoneInfoFile.toCustomID(offset);
415 }
416
417 int index = daylight ? 3 : 1;
418 if (style == SHORT) {
419 index++;
420 }
421 return names[index];
422 }
423
424 private static class DisplayNames {
425 // Cache for managing display names per timezone per locale
426 // The structure is:
427 // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
428 private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
429 new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
430 }
431
432 private static final String[] getDisplayNames(String id, Locale locale) {
433 Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
434
435 SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
436 if (ref != null) {
437 Map<Locale, String[]> perLocale = ref.get();
438 if (perLocale != null) {
439 String[] names = perLocale.get(locale);
440 if (names != null) {
441 return names;
442 }
443 names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
444 if (names != null) {
445 perLocale.put(locale, names);
446 }
447 return names;
448 }
449 }
450
451 String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
452 if (names != null) {
453 Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
454 perLocale.put(locale, names);
455 ref = new SoftReference<Map<Locale, String[]>>(perLocale);
456 displayNames.put(id, ref);
457 }
458 return names;
459 }
460
461 /**
462 * Returns the amount of time to be added to local standard time
463 * to get local wall clock time.
464 *
465 * <p>The default implementation returns 3600000 milliseconds
466 * (i.e., one hour) if a call to {@link #useDaylightTime()}
467 * returns {@code true}. Otherwise, 0 (zero) is returned.
468 *
469 * <p>If an underlying {@code TimeZone} implementation subclass
470 * supports historical and future Daylight Saving Time schedule
471 * changes, this method returns the amount of saving time of the
472 * last known Daylight Saving Time rule that can be a future
473 * prediction.
474 *
475 * <p>If the amount of saving time at any given time stamp is
744 }
745
746 /**
747 * The null constant as a TimeZone.
748 */
749 static final TimeZone NO_TIMEZONE = null;
750
751 // =======================privates===============================
752
753 /**
754 * The string identifier of this <code>TimeZone</code>. This is a
755 * programmatic identifier used internally to look up <code>TimeZone</code>
756 * objects from the system table and also to map them to their localized
757 * display names. <code>ID</code> values are unique in the system
758 * table but may not be for dynamically created zones.
759 * @serial
760 */
761 private String ID;
762 private static volatile TimeZone defaultTimeZone;
763 private static final InheritableThreadLocal<TimeZone> defaultZoneTL
764 = new InheritableThreadLocal<TimeZone>();
765
766 static final String GMT_ID = "GMT";
767 private static final int GMT_ID_LENGTH = 3;
768
769 /**
770 * Parses a custom time zone identifier and returns a corresponding zone.
771 * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
772 *
773 * @param id a string of the <a href="#CustomID">custom ID form</a>.
774 * @return a newly created TimeZone with the given offset and
775 * no daylight saving time, or null if the id cannot be parsed.
776 */
777 private static final TimeZone parseCustomTimeZone(String id) {
778 int length;
779
780 // Error if the length of id isn't long enough or id doesn't
781 // start with "GMT".
782 if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
783 id.indexOf(GMT_ID) != 0) {
784 return null;
|
409 }
410 int offset = getRawOffset();
411 if (daylight) {
412 offset += getDSTSavings();
413 }
414 return ZoneInfoFile.toCustomID(offset);
415 }
416
417 int index = daylight ? 3 : 1;
418 if (style == SHORT) {
419 index++;
420 }
421 return names[index];
422 }
423
424 private static class DisplayNames {
425 // Cache for managing display names per timezone per locale
426 // The structure is:
427 // Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
428 private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
429 new ConcurrentHashMap<>();
430 }
431
432 private static final String[] getDisplayNames(String id, Locale locale) {
433 Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
434
435 SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
436 if (ref != null) {
437 Map<Locale, String[]> perLocale = ref.get();
438 if (perLocale != null) {
439 String[] names = perLocale.get(locale);
440 if (names != null) {
441 return names;
442 }
443 names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
444 if (names != null) {
445 perLocale.put(locale, names);
446 }
447 return names;
448 }
449 }
450
451 String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
452 if (names != null) {
453 Map<Locale, String[]> perLocale = new ConcurrentHashMap<>();
454 perLocale.put(locale, names);
455 ref = new SoftReference<>(perLocale);
456 displayNames.put(id, ref);
457 }
458 return names;
459 }
460
461 /**
462 * Returns the amount of time to be added to local standard time
463 * to get local wall clock time.
464 *
465 * <p>The default implementation returns 3600000 milliseconds
466 * (i.e., one hour) if a call to {@link #useDaylightTime()}
467 * returns {@code true}. Otherwise, 0 (zero) is returned.
468 *
469 * <p>If an underlying {@code TimeZone} implementation subclass
470 * supports historical and future Daylight Saving Time schedule
471 * changes, this method returns the amount of saving time of the
472 * last known Daylight Saving Time rule that can be a future
473 * prediction.
474 *
475 * <p>If the amount of saving time at any given time stamp is
744 }
745
746 /**
747 * The null constant as a TimeZone.
748 */
749 static final TimeZone NO_TIMEZONE = null;
750
751 // =======================privates===============================
752
753 /**
754 * The string identifier of this <code>TimeZone</code>. This is a
755 * programmatic identifier used internally to look up <code>TimeZone</code>
756 * objects from the system table and also to map them to their localized
757 * display names. <code>ID</code> values are unique in the system
758 * table but may not be for dynamically created zones.
759 * @serial
760 */
761 private String ID;
762 private static volatile TimeZone defaultTimeZone;
763 private static final InheritableThreadLocal<TimeZone> defaultZoneTL
764 = new InheritableThreadLocal<>();
765
766 static final String GMT_ID = "GMT";
767 private static final int GMT_ID_LENGTH = 3;
768
769 /**
770 * Parses a custom time zone identifier and returns a corresponding zone.
771 * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
772 *
773 * @param id a string of the <a href="#CustomID">custom ID form</a>.
774 * @return a newly created TimeZone with the given offset and
775 * no daylight saving time, or null if the id cannot be parsed.
776 */
777 private static final TimeZone parseCustomTimeZone(String id) {
778 int length;
779
780 // Error if the length of id isn't long enough or id doesn't
781 // start with "GMT".
782 if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
783 id.indexOf(GMT_ID) != 0) {
784 return null;
|