diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 49ed1c3aaa828..e7699b0348181 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -34,6 +34,7 @@ import java.time.*; import java.util.*; import java.util.ResourceBundle.Control; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -123,6 +124,9 @@ public class CLDRConverter { static Map pluralRules; static Map dayPeriodRules; + // TZDB Short Names Map + private static Map tzdbShortNamesMap; + static enum DraftType { UNCONFIRMED, PROVISIONAL, @@ -284,6 +288,9 @@ public static void main(String[] args) throws Exception { pluralRules = generateRules(handlerPlurals); dayPeriodRules = generateRules(handlerDayPeriodRule); + // TZDB short names map + tzdbShortNamesMap = generateTZDBShortNamesMap(); + List bundles = readBundleList(); convertBundles(bundles); @@ -757,21 +764,25 @@ private static Map extractZoneNames(Map map, Str .orElse(tzid); Object data = map.get(TIMEZONE_ID_PREFIX + tzKey); - if (data instanceof String[]) { + 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")) { - names.put(METAZONE_ID_PREFIX + META_ETCUTC_ZONE_NAME, data); + names.put(METAZONE_ID_PREFIX + META_ETCUTC_ZONE_NAME, tznames); names.put(tzid, META_ETCUTC_ZONE_NAME); names.put("UTC", META_ETCUTC_ZONE_NAME); } else { - names.put(tzid, data); + // TZDB short names + fillTZDBShortNames(tzid, tznames); + names.put(tzid, tznames); } } else { String meta = handlerMetaZones.get(tzKey); if (meta != null) { String metaKey = METAZONE_ID_PREFIX + meta; data = map.get(metaKey); - if (data instanceof String[]) { + if (data instanceof String[] tznames) { + // TZDB short names + fillTZDBShortNames(tzid, tznames); // Keep the metazone prefix here. names.put(metaKey, data); names.put(tzid, meta); @@ -1246,6 +1257,87 @@ private static Map coverageLevelsMap() throws Exception { return covMap; } + private static Map generateTZDBShortNamesMap() throws IOException { + final Map shortNameMap = HashMap.newHashMap(1024); + Files.walk(Path.of(tzDataDir), 1, FileVisitOption.FOLLOW_LINKS) + .map(Path::toFile) + .filter(File::isFile) + .forEach(f -> { + try { + String zone = null; + String format = null; + for (var line : Files.readAllLines(f.toPath())) { + if (line.contains("#STDOFF")) continue; + line = line.replaceAll("[ \t]*#.*", ""); + if (line.startsWith("Zone")) { + var s = line.split("[ \t]+", -1); + zone = s[1]; + format = s[4]; + } else { + if (zone != null) { + if (line.isBlank()) { + shortNameMap.put(zone, format); + zone = null; + format = null; + } else { + format = line.split("[ \t]+", -1)[3]; + } + } + } + + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }); + return shortNameMap; + } + // + private static void fillTZDBShortNames(String tzid, String[] names) { + var format = tzdbShortNamesMap.get(tzid); + if (format != null) { + IntStream.of(1, 3, 5).forEach(i -> { + if (names[i] == null) { + names[i] = getTZDBShortName(format, i); + } + }); + } + } + + // fmt could be either + // X%sT, +XX/+YY, or +XX + private static final String getTZDBShortName(String f, int i) { + if (f.contains("%s")) { + return switch (i) { + case 1 -> f.formatted("S"); + case 3 -> f.formatted("D"); + case 5 -> f.formatted(""); + default -> throw new InternalError(); + }; + } else if (f.contains("/")) { + return switch (i) { + case 1, 5 -> convertGMTName(f.substring(0, f.indexOf("/"))); + case 3 -> convertGMTName(f.substring(f.indexOf("/") + 1)); + default -> throw new InternalError(); + }; + } else { + return convertGMTName(f); + } + } + + private final static Pattern OFFSET_PATTERN = Pattern.compile(("([-+]\\d{2})(\\d{2})*")); + private static String convertGMTName(String f) { + var m = OFFSET_PATTERN.matcher(f); + + if (m.matches()) { + var hour = m.group(1); + var min = m.group(2); + return "GMT" + hour + (min != null ? ":" + min : ":00"); + } else { + return f; + } + } + // for debug static void dumpMap(Map map) { map.entrySet().stream() diff --git a/make/modules/jdk.localedata/Gensrc.gmk b/make/modules/jdk.localedata/Gensrc.gmk index fc0e09dd8bb53..f57585f5d76db 100644 --- a/make/modules/jdk.localedata/Gensrc.gmk +++ b/make/modules/jdk.localedata/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ TARGETS += $(GENSRC_LOCALEDATA) CLDR_DATA_DIR := $(TOPDIR)/make/data/cldr/common GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata CLDR_GEN_DONE := $(GENSRC_DIR)/_cldr-gensrc.marker +TZ_DATA_DIR := $(MODULE_SRC)/../java.base/share/data/tzdata $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(wildcard $(CLDR_DATA_DIR)/main/*.xml) \ @@ -47,7 +48,8 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(TOOL_CLDRCONVERTER) -base $(CLDR_DATA_DIR) \ -baselocales "en-US" \ -year $(COPYRIGHT_YEAR) \ - -o $(GENSRC_DIR)) + -o $(GENSRC_DIR) \ + -tzdatadir $(TZ_DATA_DIR)) $(TOUCH) $@ TARGETS += $(CLDR_GEN_DONE)