From ae5d36a29c443f0e028d67fb4b53735fe2d23b9f Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Thu, 7 May 2026 06:43:41 +0100 Subject: [PATCH 1/3] Backport 49a15be918673ee49c3a02287aa268a87419147a --- .../tools/cldrconverter/CLDRConverter.java | 38 +- .../resources/cldr/TimeZoneNamesTest.java | 339 ++++++++++-------- 2 files changed, 209 insertions(+), 168 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 55dd6a8d6ad..2085e631a63 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -787,10 +787,7 @@ private static Map extractZoneNames(Map map, Str String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid)) .orElse(tzid); // Follow link, if needed - String tzLink = null; - for (var k = tzKey; tzdbLinks.containsKey(k);) { - k = tzLink = tzdbLinks.get(k); - } + String tzLink = getTZDBLink(tzKey); if (tzLink == null && tzdbLinks.containsValue(tzKey)) { // reverse link search // this is needed as in tzdb, "America/Buenos_Aires" links to @@ -819,7 +816,7 @@ private static Map extractZoneNames(Map map, Str } else { // TZDB short names tznames = Arrays.copyOf(tznames, tznames.length); - fillTZDBShortNames(tzid, tznames); + fillTZDBShortNames(tzKey, tznames); names.put(tzid, tznames); } } else { @@ -832,11 +829,13 @@ private static Map extractZoneNames(Map map, Str String metaKey = METAZONE_ID_PREFIX + meta; data = map.get(metaKey); if (data instanceof String[] tznames) { - // TZDB short names - tznames = Arrays.copyOf((String[])names.getOrDefault(metaKey, tznames), 6); - fillTZDBShortNames(tzid, tznames); - // Keep the metazone prefix here. - names.putIfAbsent(metaKey, tznames); + if (isDefaultZone(meta, tzKey)) { + // Record the metazone names only from the default + // (001) zone, with short names filled from TZDB + tznames = Arrays.copyOf(tznames, tznames.length); + fillTZDBShortNames(tzKey, tznames); + names.put(metaKey, tznames); + } names.put(tzid, meta); if (tzLink != null && availableIds.contains(tzLink)) { names.put(tzLink, meta); @@ -1484,12 +1483,12 @@ private static String flipIfNeeded(boolean inVanguard, String format) { * Fill the TZDB short names if there is no name provided by the CLDR */ private static void fillTZDBShortNames(String tzid, String[] names) { - var val = tzdbShortNamesMap.get(tzdbLinks.getOrDefault(tzid, tzid)); + var val = tzdbShortNamesMap.getOrDefault(tzid, tzdbShortNamesMap.get(getTZDBLink(tzid))); if (val != null) { var format = val.split(NBSP)[0]; var rule = val.split(NBSP)[1]; IntStream.of(1, 3, 5).forEach(i -> { - if (names[i] == null) { + if (names[i] == null || names[i].isEmpty()) { if (format.contains("%s")) { names[i] = switch (i) { case 1 -> format.formatted(tzdbSubstLetters.get(rule + NBSP + STD)); @@ -1511,6 +1510,21 @@ private static void fillTZDBShortNames(String tzid, String[] names) { } } + private static boolean isDefaultZone(String meta, String tzid) { + String zone001 = handlerMetaZones.zidMap().get(meta); + var tzLink = getTZDBLink(tzid); + return canonicalTZMap.getOrDefault(tzid, tzid).equals(zone001) || + tzLink != null && canonicalTZMap.getOrDefault(tzLink, tzLink).equals(zone001); + } + + private static String getTZDBLink(String tzid) { + String tzLink = null; + for (var k = tzid; tzdbLinks.containsKey(k);) { + k = tzLink = tzdbLinks.get(k); + } + return tzLink; + } + /* * Convert TZDB offsets to JDK's offsets, eg, "-08" to "GMT-08:00". * If it cannot recognize the pattern, return the argument as is. diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index ed6fb2a58d8..ba17cf54c17 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 8322647 8174269 8346948 + * 8382020 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at * either build or runtime @@ -55,164 +56,190 @@ Object[][] sampleTZs() { // on the CLDR data upgrade. // no "metazone" zones - {"Asia/Srednekolymsk", Locale.US, "Srednekolymsk Standard Time", - "GMT+11:00", - "Srednekolymsk Daylight Time", - "GMT+12:00", - "Srednekolymsk Time", - "GMT+11:00"}, - {"Asia/Srednekolymsk", Locale.FRANCE, "Srednekolymsk (heure standard)", - "UTC+11:00", - "Srednekolymsk (heure d\u2019\u00e9t\u00e9)", - "UTC+12:00", - "heure : Srednekolymsk", - "UTC+11:00"}, - {"America/Punta_Arenas", Locale.US, "Punta Arenas Standard Time", - "GMT-03:00", - "Punta Arenas Daylight Time", - "GMT-02:00", - "Punta Arenas Time", - "GMT-03:00"}, - {"America/Punta_Arenas", Locale.FRANCE, "Punta Arenas (heure standard)", - "UTC\u221203:00", - "Punta Arenas (heure d\u2019\u00e9t\u00e9)", - "UTC\u221202:00", - "heure : Punta Arenas", - "UTC\u221203:00"}, - {"Asia/Famagusta", Locale.US, "Famagusta Standard Time", - "EET", - "Famagusta Daylight Time", - "EEST", - "Famagusta Time", - "EET"}, - {"Asia/Famagusta", Locale.FRANCE, "Famagouste (heure standard)", - "EET", - "Famagouste (heure d\u2019\u00e9t\u00e9)", - "EEST", - "heure : Famagouste", - "EET"}, - {"Europe/Astrakhan", Locale.US, "Astrakhan Standard Time", - "GMT+04:00", - "Astrakhan Daylight Time", - "GMT+05:00", - "Astrakhan Time", - "GMT+04:00"}, - {"Europe/Astrakhan", Locale.FRANCE, "Astrakhan (heure standard)", - "UTC+04:00", - "Astrakhan (heure d\u2019\u00e9t\u00e9)", - "UTC+05:00", - "heure : Astrakhan", - "UTC+04:00"}, - {"Europe/Saratov", Locale.US, "Saratov Standard Time", - "GMT+04:00", - "Saratov Daylight Time", - "GMT+05:00", - "Saratov Time", - "GMT+04:00"}, - {"Europe/Saratov", Locale.FRANCE, "Saratov (heure standard)", - "UTC+04:00", - "Saratov (heure d\u2019\u00e9t\u00e9)", - "UTC+05:00", - "heure : Saratov", - "UTC+04:00"}, - {"Europe/Ulyanovsk", Locale.US, "Ulyanovsk Standard Time", - "GMT+04:00", - "Ulyanovsk Daylight Time", - "GMT+05:00", - "Ulyanovsk Time", - "GMT+04:00"}, - {"Europe/Ulyanovsk", Locale.FRANCE, "Oulianovsk (heure standard)", - "UTC+04:00", - "Oulianovsk (heure d\u2019\u00e9t\u00e9)", - "UTC+05:00", - "heure : Oulianovsk", - "UTC+04:00"}, - {"Pacific/Bougainville", Locale.US, "Bougainville Standard Time", - "GMT+11:00", - "Bougainville Daylight Time", - "GMT+11:00", - "Bougainville Time", - "GMT+11:00"}, - {"Pacific/Bougainville", Locale.FRANCE, "Bougainville (heure standard)", - "UTC+11:00", - "Bougainville (heure d\u2019\u00e9t\u00e9)", - "UTC+11:00", - "heure : Bougainville", - "UTC+11:00"}, - {"Europe/Istanbul", Locale.US, "Istanbul Standard Time", - "GMT+03:00", - "Istanbul Daylight Time", - "GMT+04:00", - "Istanbul Time", - "GMT+03:00"}, - {"Europe/Istanbul", Locale.FRANCE, "Istanbul (heure standard)", - "UTC+03:00", - "Istanbul (heure d\u2019\u00e9t\u00e9)", - "UTC+04:00", - "heure : Istanbul", - "UTC+03:00"}, - {"Asia/Istanbul", Locale.US, "Istanbul Standard Time", - "GMT+03:00", - "Istanbul Daylight Time", - "GMT+04:00", - "Istanbul Time", - "GMT+03:00"}, - {"Asia/Istanbul", Locale.FRANCE, "Istanbul (heure standard)", - "UTC+03:00", - "Istanbul (heure d\u2019\u00e9t\u00e9)", - "UTC+04:00", - "heure : Istanbul", - "UTC+03:00"}, - {"Turkey", Locale.US, "Istanbul Standard Time", - "GMT+03:00", - "Istanbul Daylight Time", - "GMT+04:00", - "Istanbul Time", - "GMT+03:00"}, - {"Turkey", Locale.FRANCE, "Istanbul (heure standard)", - "UTC+03:00", - "Istanbul (heure d\u2019\u00e9t\u00e9)", - "UTC+04:00", - "heure : Istanbul", - "UTC+03:00"}, + {"Asia/Srednekolymsk", Locale.US, + "Srednekolymsk Standard Time", + "GMT+11:00", + "Srednekolymsk Daylight Time", + "GMT+12:00", + "Srednekolymsk Time", + "GMT+11:00"}, + {"Asia/Srednekolymsk", Locale.FRANCE, + "Srednekolymsk (heure standard)", + "UTC+11:00", + "Srednekolymsk (heure d\u2019\u00e9t\u00e9)", + "UTC+12:00", + "heure : Srednekolymsk", + "UTC+11:00"}, + {"America/Punta_Arenas", Locale.US, + "Punta Arenas Standard Time", + "GMT-03:00", + "Punta Arenas Daylight Time", + "GMT-02:00", + "Punta Arenas Time", + "GMT-03:00"}, + {"America/Punta_Arenas", Locale.FRANCE, + "Punta Arenas (heure standard)", + "UTC\u221203:00", + "Punta Arenas (heure d\u2019\u00e9t\u00e9)", + "UTC\u221202:00", + "heure : Punta Arenas", + "UTC\u221203:00"}, + {"Asia/Famagusta", Locale.US, + "Famagusta Standard Time", + "EET", + "Famagusta Daylight Time", + "EEST", + "Famagusta Time", + "EET"}, + {"Asia/Famagusta", Locale.FRANCE, + "Famagouste (heure standard)", + "EET", + "Famagouste (heure d\u2019\u00e9t\u00e9)", + "EEST", + "heure : Famagouste", + "EET"}, + {"Europe/Astrakhan", Locale.US, + "Astrakhan Standard Time", + "GMT+04:00", + "Astrakhan Daylight Time", + "GMT+05:00", + "Astrakhan Time", + "GMT+04:00"}, + {"Europe/Astrakhan", Locale.FRANCE, + "Astrakhan (heure standard)", + "UTC+04:00", + "Astrakhan (heure d\u2019\u00e9t\u00e9)", + "UTC+05:00", + "heure : Astrakhan", + "UTC+04:00"}, + {"Europe/Saratov", Locale.US, + "Saratov Standard Time", + "GMT+04:00", + "Saratov Daylight Time", + "GMT+05:00", + "Saratov Time", + "GMT+04:00"}, + {"Europe/Saratov", Locale.FRANCE, + "Saratov (heure standard)", + "UTC+04:00", + "Saratov (heure d\u2019\u00e9t\u00e9)", + "UTC+05:00", + "heure : Saratov", + "UTC+04:00"}, + {"Europe/Ulyanovsk", Locale.US, + "Ulyanovsk Standard Time", + "GMT+04:00", + "Ulyanovsk Daylight Time", + "GMT+05:00", + "Ulyanovsk Time", + "GMT+04:00"}, + {"Europe/Ulyanovsk", Locale.FRANCE, + "Oulianovsk (heure standard)", + "UTC+04:00", + "Oulianovsk (heure d\u2019\u00e9t\u00e9)", + "UTC+05:00", + "heure : Oulianovsk", + "UTC+04:00"}, + {"Pacific/Bougainville", Locale.US, + "Bougainville Standard Time", + "GMT+11:00", + "Bougainville Daylight Time", + "GMT+11:00", + "Bougainville Time", + "GMT+11:00"}, + {"Pacific/Bougainville", Locale.FRANCE, + "Bougainville (heure standard)", + "UTC+11:00", + "Bougainville (heure d\u2019\u00e9t\u00e9)", + "UTC+11:00", + "heure : Bougainville", + "UTC+11:00"}, + {"Europe/Istanbul", Locale.US, + "Istanbul Standard Time", + "GMT+03:00", + "Istanbul Daylight Time", + "GMT+04:00", + "Istanbul Time", + "GMT+03:00"}, + {"Europe/Istanbul", Locale.FRANCE, + "Istanbul (heure standard)", + "UTC+03:00", + "Istanbul (heure d\u2019\u00e9t\u00e9)", + "UTC+04:00", + "heure : Istanbul", + "UTC+03:00"}, + {"Asia/Istanbul", Locale.US, + "Istanbul Standard Time", + "GMT+03:00", + "Istanbul Daylight Time", + "GMT+04:00", + "Istanbul Time", + "GMT+03:00"}, + {"Asia/Istanbul", Locale.FRANCE, + "Istanbul (heure standard)", + "UTC+03:00", + "Istanbul (heure d\u2019\u00e9t\u00e9)", + "UTC+04:00", + "heure : Istanbul", + "UTC+03:00"}, + {"Turkey", Locale.US, + "Istanbul Standard Time", + "GMT+03:00", + "Istanbul Daylight Time", + "GMT+04:00", + "Istanbul Time", + "GMT+03:00"}, + {"Turkey", Locale.FRANCE, + "Istanbul (heure standard)", + "UTC+03:00", + "Istanbul (heure d\u2019\u00e9t\u00e9)", + "UTC+04:00", + "heure : Istanbul", + "UTC+03:00"}, // Short names derived from TZDB at build time - {"Europe/Lisbon", Locale.US, "Western European Standard Time", - "WET", - "Western European Summer Time", - "WEST", - "Western European Time", - "WET"}, - {"Atlantic/Azores", Locale.US, "Azores Standard Time", - "GMT-01:00", - "Azores Summer Time", - "GMT", - "Azores Time", - "GMT-01:00"}, - {"Australia/Perth", Locale.US, "Australian Western Standard Time", - "AWST", - "Australian Western Daylight Time", - "AWDT", - "Australian Western Time", - "AWT"}, - {"Africa/Harare", Locale.US, "Central Africa Time", - "CAT", - "Harare Daylight Time", - "CAT", - "Harare Time", - "CAT"}, - {"Europe/Dublin", Locale.US, "Greenwich Mean Time", - "GMT", - "Irish Standard Time", - "IST", - "Dublin Time", - "GMT"}, - {"Pacific/Gambier", Locale.US, "Gambier Time", - "GMT-09:00", - "Gambier Daylight Time", - "GMT-09:00", - "Gambier Time", - "GMT-09:00"}, + {"Europe/Lisbon", Locale.US, + "Western European Standard Time", + "WET", + "Western European Summer Time", + "WEST", + "Western European Time", + "WET"}, + {"Atlantic/Azores", Locale.US, + "Azores Standard Time", + "GMT-01:00", + "Azores Summer Time", + "GMT", + "Azores Time", + "GMT-01:00"}, + {"Australia/Perth", Locale.US, + "Australian Western Standard Time", + "AWST", + "Australian Western Daylight Time", + "AWDT", + "Australian Western Time", + "AWT"}, + {"Africa/Harare", Locale.US, + "Central Africa Time", + "CAT", + "Harare Daylight Time", + "CAT", + "Harare Time", + "CAT"}, + {"Europe/Dublin", Locale.US, + "Greenwich Mean Time", + "GMT", + "Irish Standard Time", + "IST", + "Dublin Time", + "GMT"}, + {"Pacific/Gambier", Locale.US, + "Gambier Time", + "GMT-09:00", + "Gambier Daylight Time", + "GMT-09:00", + "Gambier Time", + "GMT-09:00"}, }; } From 0aaec7920a027139c0f237e0bf81e9722f4a4823 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Fri, 15 May 2026 00:22:00 +0100 Subject: [PATCH 2/3] Backport JDK-8384043 --- .../tools/cldrconverter/CLDRConverter.java | 40 ++++++++++--------- .../resources/cldr/TimeZoneNamesTest.java | 23 ++++++++++- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 2085e631a63..da8eba96dc7 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -807,6 +807,13 @@ private static Map extractZoneNames(Map map, Str data = map.get(TIMEZONE_ID_PREFIX + tzLink); } + String meta = handlerMetaZones.get(tzKey); + if (meta == null && tzLink != null) { + // Check for tzLink + meta = handlerMetaZones.get(tzLink); + } + String metaKey = meta != null ? METAZONE_ID_PREFIX + meta : null; + if (data instanceof String[] tznames) { // Hack for UTC. UTC is an alias to Etc/UTC in CLDR if (tzid.equals("Etc/UTC") && !map.containsKey(TIMEZONE_ID_PREFIX + "UTC")) { @@ -818,24 +825,14 @@ private static Map extractZoneNames(Map map, Str tznames = Arrays.copyOf(tznames, tznames.length); fillTZDBShortNames(tzKey, tznames); names.put(tzid, tznames); + if (meta != null && map.get(metaKey) instanceof String[] metaNames) { + recordMetazone(names, meta, tzKey, metaNames); + } } } else { - String meta = handlerMetaZones.get(tzKey); - if (meta == null && tzLink != null) { - // Check for tzLink - meta = handlerMetaZones.get(tzLink); - } if (meta != null) { - String metaKey = METAZONE_ID_PREFIX + meta; - data = map.get(metaKey); - if (data instanceof String[] tznames) { - if (isDefaultZone(meta, tzKey)) { - // Record the metazone names only from the default - // (001) zone, with short names filled from TZDB - tznames = Arrays.copyOf(tznames, tznames.length); - fillTZDBShortNames(tzKey, tznames); - names.put(metaKey, tznames); - } + if (map.get(metaKey) instanceof String[] metaNames) { + recordMetazone(names, meta, tzKey, metaNames); names.put(tzid, meta); if (tzLink != null && availableIds.contains(tzLink)) { names.put(tzLink, meta); @@ -1510,11 +1507,18 @@ private static void fillTZDBShortNames(String tzid, String[] names) { } } - private static boolean isDefaultZone(String meta, String tzid) { + private static void recordMetazone(Map names, String meta, String tzid, String[] tznames) { String zone001 = handlerMetaZones.zidMap().get(meta); var tzLink = getTZDBLink(tzid); - return canonicalTZMap.getOrDefault(tzid, tzid).equals(zone001) || - tzLink != null && canonicalTZMap.getOrDefault(tzLink, tzLink).equals(zone001); + + // Record the metazone names only from the default + // (001) zone, with short names filled from TZDB + if (canonicalTZMap.getOrDefault(tzid, tzid).equals(zone001) || + tzLink != null && canonicalTZMap.getOrDefault(tzLink, tzLink).equals(zone001)) { + tznames = Arrays.copyOf(tznames, tznames.length); + fillTZDBShortNames(tzid, tznames); + names.put(METAZONE_ID_PREFIX + meta, tznames); + } } private static String getTZDBLink(String tzid) { diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index ba17cf54c17..3dba2930642 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -24,7 +24,7 @@ /* * @test * @bug 8181157 8202537 8234347 8236548 8261279 8322647 8174269 8346948 - * 8382020 + * 8382020 8384043 * @modules jdk.localedata * @summary Checks CLDR time zone names are generated correctly at * either build or runtime @@ -240,6 +240,27 @@ Object[][] sampleTZs() { "GMT-09:00", "Gambier Time", "GMT-09:00"}, + + // Hawaii/Aleutian + // + // Note that CLDR v48 only contains the standard names in "Hawaii" + // metazone. Other long names are synthesized, and short names are + // from TZDB. "America/Adak" reflects the "Hawaii_Aleutian" metazone + // names. + {"Pacific/Honolulu", Locale.US, + "Hawaii-Aleutian Standard Time", + "HST", + "Honolulu Daylight Time", + "HST", + "Honolulu Time", + "HST"}, + {"America/Adak", Locale.US, + "Hawaii-Aleutian Standard Time", + "HAST", + "Hawaii-Aleutian Daylight Time", + "HADT", + "Hawaii-Aleutian Time", + "HAT"}, }; } From 321980be47f1d68a1e797c27c8288732b1af2e84 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Fri, 15 May 2026 01:01:17 +0100 Subject: [PATCH 3/3] Fix TimeZoneNamesTest to use CLDR 47 data for Hawaii --- .../sun/util/resources/cldr/TimeZoneNamesTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index 3dba2930642..3d6b3896150 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -243,16 +243,16 @@ Object[][] sampleTZs() { // Hawaii/Aleutian // - // Note that CLDR v48 only contains the standard names in "Hawaii" - // metazone. Other long names are synthesized, and short names are - // from TZDB. "America/Adak" reflects the "Hawaii_Aleutian" metazone - // names. + // CLDR v47 does not contain CLDR-18531 + // so both Pacific/Honolulu and America/Adak + // share the same long names and differ only + // on the short names. {"Pacific/Honolulu", Locale.US, "Hawaii-Aleutian Standard Time", "HST", - "Honolulu Daylight Time", - "HST", - "Honolulu Time", + "Hawaii-Aleutian Daylight Time", + "HDT", + "Hawaii-Aleutian Time", "HST"}, {"America/Adak", Locale.US, "Hawaii-Aleutian Standard Time",