8234347: "Turkey" meta time zone does not generate composed localized names

8236548: Localized time zone name inconsistency between English and other locales

Reviewed-by: joehw, rriggs
This commit is contained in:
Naoto Sato 2020-02-12 08:25:35 -08:00
parent 2fbbce2b23
commit 5c3a01591c
10 changed files with 177 additions and 254 deletions

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -40,7 +40,6 @@ $(eval $(call IncludeCustomExtension, CompileTools.gmk))
# Use += to be able to add to this from a custom extension # Use += to be able to add to this from a custom extension
BUILD_TOOLS_SRC_DIRS += \ BUILD_TOOLS_SRC_DIRS += \
$(TOPDIR)/make/jdk/src/classes \ $(TOPDIR)/make/jdk/src/classes \
$(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes \
$(BUILDTOOLS_OUTPUTDIR)/interim_tzdb_classes \ $(BUILDTOOLS_OUTPUTDIR)/interim_tzdb_classes \
# #

View File

@ -1,52 +0,0 @@
#
# Copyright (c) 2015, 2018, 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
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
default: all
include $(SPEC)
include MakeBase.gmk
##########################################################################################
### CLDRConverter needs the JRE time zone names from the java.base source.
define cldrconverter_copytznames
$(call MakeTargetDir)
$(RM) '$@'
$(SED) -e "s/package sun.util.resources/package build.tools.cldrconverter/" \
-e "s/extends TimeZoneNamesBundle//" \
-e "s/protected final/static final/" \
< $(<) > $@
endef
$(eval $(call SetupCopyFiles,COPY_INTERIM_CLDRCONVERTER, \
SRC := $(TOPDIR)/src/java.base/share/classes/sun/util/resources, \
DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes/build/tools/cldrconverter, \
FILES := TimeZoneNames.java, \
MACRO := cldrconverter_copytznames))
##########################################################################################
all: $(COPY_INTERIM_CLDRCONVERTER)

View File

@ -75,9 +75,6 @@ interim-langtools:
interim-rmic: interim-rmic:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileInterimRmic.gmk) +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileInterimRmic.gmk)
interim-cldrconverter:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CopyInterimCLDRConverter.gmk)
interim-tzdb: interim-tzdb:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CopyInterimTZDB.gmk) +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CopyInterimTZDB.gmk)
@ -92,7 +89,7 @@ buildtools-hotspot:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileToolsHotspot.gmk) +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f CompileToolsHotspot.gmk)
ALL_TARGETS += buildtools-langtools interim-langtools \ ALL_TARGETS += buildtools-langtools interim-langtools \
interim-rmic interim-cldrconverter interim-tzdb buildtools-jdk buildtools-modules \ interim-rmic interim-tzdb buildtools-jdk buildtools-modules \
buildtools-hotspot buildtools-hotspot
################################################################################ ################################################################################
@ -677,7 +674,7 @@ else
interim-langtools: $(INTERIM_LANGTOOLS_GENSRC_TARGETS) interim-langtools: $(INTERIM_LANGTOOLS_GENSRC_TARGETS)
buildtools-jdk: interim-langtools interim-cldrconverter interim-tzdb buildtools-jdk: interim-langtools interim-tzdb
buildtools-hotspot: interim-langtools buildtools-hotspot: interim-langtools

View File

@ -294,7 +294,6 @@ class Bundle {
} }
// First, weed out any empty timezone or metazone names from myMap. // First, weed out any empty timezone or metazone names from myMap.
// Fill in any missing abbreviations if locale is "en".
for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) { for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
String key = it.next(); String key = it.next();
if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX) if (key.startsWith(CLDRConverter.TIMEZONE_ID_PREFIX)
@ -307,10 +306,6 @@ class Bundle {
it.remove(); it.remove();
continue; continue;
} }
if (id.equals("en")) {
fillInJREs(key, nameMap);
}
} }
} }
for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) { for (Iterator<String> it = myMap.keySet().iterator(); it.hasNext();) {
@ -636,42 +631,6 @@ class Bundle {
return null; return null;
} }
static List<Object[]> jreTimeZoneNames = Arrays.asList(TimeZoneNames.getContents());
private void fillInJREs(String key, Map<String, String> map) {
String tzid = null;
if (key.startsWith(CLDRConverter.METAZONE_ID_PREFIX)) {
// Look for tzid
String meta = key.substring(CLDRConverter.METAZONE_ID_PREFIX.length());
if (meta.equals("GMT")) {
tzid = meta;
} else {
for (String tz : CLDRConverter.handlerMetaZones.keySet()) {
if (CLDRConverter.handlerMetaZones.get(tz).equals(meta)) {
tzid = tz;
break;
}
}
}
} else {
tzid = key.substring(CLDRConverter.TIMEZONE_ID_PREFIX.length());
}
if (tzid != null) {
for (Object[] jreZone : jreTimeZoneNames) {
if (jreZone[0].equals(tzid)) {
for (int i = 0; i < ZONE_NAME_KEYS.length; i++) {
if (map.get(ZONE_NAME_KEYS[i]) == null) {
String[] jreNames = (String[])jreZone[1];
map.put(ZONE_NAME_KEYS[i], jreNames[i]);
}
}
break;
}
}
}
}
/** /**
* Perform a generic conversion of CLDR date-time format pattern letter based * Perform a generic conversion of CLDR date-time format pattern letter based
* on the support given by the SimpleDateFormat and the j.t.f.DateTimeFormatter * on the support given by the SimpleDateFormat and the j.t.f.DateTimeFormatter

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,6 @@
package build.tools.cldrconverter; package build.tools.cldrconverter;
import static build.tools.cldrconverter.Bundle.jreTimeZoneNames;
import build.tools.cldrconverter.BundleGenerator.BundleType; import build.tools.cldrconverter.BundleGenerator.BundleType;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -89,7 +88,9 @@ public class CLDRConverter {
static final String ZONE_NAME_PREFIX = "timezone.displayname."; static final String ZONE_NAME_PREFIX = "timezone.displayname.";
static final String METAZONE_ID_PREFIX = "metazone.id."; static final String METAZONE_ID_PREFIX = "metazone.id.";
static final String PARENT_LOCALE_PREFIX = "parentLocale."; static final String PARENT_LOCALE_PREFIX = "parentLocale.";
static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE";
static final String[] EMPTY_ZONE = {"", "", "", "", "", ""}; static final String[] EMPTY_ZONE = {"", "", "", "", "", ""};
static final String META_ETCUTC_ZONE_NAME = "ETC_UTC";
private static SupplementDataParseHandler handlerSuppl; private static SupplementDataParseHandler handlerSuppl;
private static LikelySubtagsParseHandler handlerLikelySubtags; private static LikelySubtagsParseHandler handlerLikelySubtags;
@ -686,60 +687,6 @@ public class CLDRConverter {
private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) { private static Map<String, Object> extractZoneNames(Map<String, Object> map, String id) {
Map<String, Object> names = new HashMap<>(); Map<String, Object> names = new HashMap<>();
// Copy over missing time zone ids from JRE for English locale
if (id.equals("en")) {
Map<String[], String> jreMetaMap = new HashMap<>();
jreTimeZoneNames.stream().forEach(e -> {
String tzid = (String)e[0];
String[] data = (String[])e[1];
if (map.get(TIMEZONE_ID_PREFIX + tzid) == null &&
handlerMetaZones.get(tzid) == null ||
handlerMetaZones.get(tzid) != null &&
map.get(METAZONE_ID_PREFIX + handlerMetaZones.get(tzid)) == null) {
// First, check the alias
String canonID = canonicalTZMap.get(tzid);
if (canonID != null && !tzid.equals(canonID)) {
Object value = map.get(TIMEZONE_ID_PREFIX + canonID);
if (value != null) {
names.put(tzid, value);
return;
} else {
String meta = handlerMetaZones.get(canonID);
if (meta != null) {
value = map.get(METAZONE_ID_PREFIX + meta);
if (value != null) {
names.put(tzid, meta);
return;
}
}
}
}
// Check the CLDR meta key
Optional<Map.Entry<String, String>> cldrMeta =
handlerMetaZones.getData().entrySet().stream()
.filter(me ->
Arrays.deepEquals(data,
(String[])map.get(METAZONE_ID_PREFIX + me.getValue())))
.findAny();
cldrMeta.ifPresentOrElse(meta -> names.put(tzid, meta.getValue()), () -> {
// Check the JRE meta key, add if there is not.
Optional<Map.Entry<String[], String>> jreMeta =
jreMetaMap.entrySet().stream()
.filter(jm -> Arrays.deepEquals(data, jm.getKey()))
.findAny();
jreMeta.ifPresentOrElse(meta -> names.put(tzid, meta.getValue()), () -> {
String metaName = "JRE_" + tzid.replaceAll("[/-]", "_");
names.put(METAZONE_ID_PREFIX + metaName, data);
names.put(tzid, metaName);
});
});
}
});
}
getAvailableZoneIds().stream().forEach(tzid -> { getAvailableZoneIds().stream().forEach(tzid -> {
// If the tzid is deprecated, get the data for the replacement id // If the tzid is deprecated, get the data for the replacement id
String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid)) String tzKey = Optional.ofNullable((String)handlerSupplMeta.get(tzid))
@ -747,7 +694,14 @@ public class CLDRConverter {
Object data = map.get(TIMEZONE_ID_PREFIX + tzKey); Object data = map.get(TIMEZONE_ID_PREFIX + tzKey);
if (data instanceof String[]) { if (data instanceof String[]) {
// 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(tzid, META_ETCUTC_ZONE_NAME);
names.put("UTC", META_ETCUTC_ZONE_NAME);
} else {
names.put(tzid, data); names.put(tzid, data);
}
} else { } else {
String meta = handlerMetaZones.get(tzKey); String meta = handlerMetaZones.get(tzKey);
if (meta != null) { if (meta != null) {
@ -765,23 +719,22 @@ public class CLDRConverter {
// exemplar cities. // exemplar cities.
Map<String, Object> exCities = map.entrySet().stream() Map<String, Object> exCities = map.entrySet().stream()
.filter(e -> e.getKey().startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX)) .filter(e -> e.getKey().startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX))
.collect(Collectors .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
.toMap(Map.Entry::getKey, Map.Entry::getValue));
names.putAll(exCities); names.putAll(exCities);
if (!id.equals("en") && // If there's no UTC entry at this point, add an empty one
!names.isEmpty()) { if (!names.isEmpty() && !names.containsKey("UTC")) {
// CLDR does not have UTC entry, so add it here. names.putIfAbsent(METAZONE_ID_PREFIX + META_EMPTY_ZONE_NAME, EMPTY_ZONE);
names.put("UTC", EMPTY_ZONE); names.put("UTC", META_EMPTY_ZONE_NAME);
// no metazone zones
Arrays.asList(handlerMetaZones.get(MetaZonesParseHandler.NO_METAZONE_KEY)
.split("\\s")).stream()
.forEach(tz -> {
names.put(tz, EMPTY_ZONE);
});
} }
// Finally some compatibility stuff
ZoneId.SHORT_IDS.entrySet().stream()
.filter(e -> !names.containsKey(e.getKey()) && names.containsKey(e.getValue()))
.forEach(e -> {
names.put(e.getKey(), names.get(e.getValue()));
});
return names; return names;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -4260,9 +4260,15 @@ public final class DateTimeFormatterBuilder {
char nextNextChar = text.charAt(position + 1); char nextNextChar = text.charAt(position + 1);
if (context.charEquals(nextChar, 'U') && context.charEquals(nextNextChar, 'T')) { if (context.charEquals(nextChar, 'U') && context.charEquals(nextNextChar, 'T')) {
if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) { if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) {
// There are localized zone texts that start with "UTC", e.g.
// "UTC\u221210:00" (MINUS SIGN instead of HYPHEN-MINUS) in French.
// Exclude those ZoneText cases.
if (!(this instanceof ZoneTextPrinterParser)) {
return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
} }
} else {
return parseOffsetBased(context, text, position, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO); return parseOffsetBased(context, text, position, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
}
} else if (context.charEquals(nextChar, 'G') && length >= position + 3 && } else if (context.charEquals(nextChar, 'G') && length >= position + 3 &&
context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) { context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) {
if (length >= position + 4 && context.charEquals(text.charAt(position + 3), '0')) { if (length >= position + 4 && context.charEquals(text.charAt(position + 3), '0')) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,6 @@ import java.util.Objects;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.stream.Collectors;
import sun.util.calendar.ZoneInfoFile; import sun.util.calendar.ZoneInfoFile;
import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleResources; import sun.util.locale.provider.LocaleResources;
@ -73,8 +72,6 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
@Override @Override
protected String[] getDisplayNameArray(String id, Locale locale) { protected String[] getDisplayNameArray(String id, Locale locale) {
// Use English for the ROOT locale
locale = locale.equals(Locale.ROOT) ? Locale.ENGLISH : locale;
String[] namesSuper = super.getDisplayNameArray(id, locale); String[] namesSuper = super.getDisplayNameArray(id, locale);
if (namesSuper == null) { if (namesSuper == null) {
@ -94,12 +91,12 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
case "": case "":
// Fill in empty elements // Fill in empty elements
deriveFallbackName(namesSuper, i, locale, deriveFallbackName(namesSuper, i, locale,
!exists(namesSuper, INDEX_DST_LONG)); !TimeZone.getTimeZone(id).useDaylightTime());
break; break;
case NO_INHERITANCE_MARKER: case NO_INHERITANCE_MARKER:
// CLDR's "no inheritance marker" // CLDR's "no inheritance marker"
namesSuper[i] = toGMTFormat(id, i == INDEX_DST_LONG || i == INDEX_DST_SHORT, namesSuper[i] = toGMTFormat(id, i == INDEX_DST_LONG || i == INDEX_DST_SHORT,
i % 2 != 0, locale); locale);
break; break;
default: default:
break; break;
@ -121,24 +118,19 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
@Override @Override
protected String[][] getZoneStrings(Locale locale) { protected String[][] getZoneStrings(Locale locale) {
// Use English for the ROOT locale
locale = locale.equals(Locale.ROOT) ? Locale.ENGLISH : locale;
String[][] ret = super.getZoneStrings(locale); String[][] ret = super.getZoneStrings(locale);
// Fill in for the empty names. // Fill in for the empty names.
// English names are prefilled for performance.
if (!locale.equals(Locale.ENGLISH) &&
!locale.equals(Locale.US)) {
for (int zoneIndex = 0; zoneIndex < ret.length; zoneIndex++) { for (int zoneIndex = 0; zoneIndex < ret.length; zoneIndex++) {
deriveFallbackNames(ret[zoneIndex], locale); deriveFallbackNames(ret[zoneIndex], locale);
} }
}
return ret; return ret;
} }
// Derive fallback time zone name according to LDML's logic // Derive fallback time zone name according to LDML's logic
private void deriveFallbackNames(String[] names, Locale locale) { private void deriveFallbackNames(String[] names, Locale locale) {
boolean noDST = !exists(names, INDEX_DST_LONG); boolean noDST = !TimeZone.getTimeZone(names[0]).useDaylightTime();
for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) {
deriveFallbackName(names, i, locale, noDST); deriveFallbackName(names, i, locale, noDST);
} }
@ -152,11 +144,25 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
// CLDR's "no inheritance marker" // CLDR's "no inheritance marker"
names[index] = toGMTFormat(id, names[index] = toGMTFormat(id,
index == INDEX_DST_LONG || index == INDEX_DST_SHORT, index == INDEX_DST_LONG || index == INDEX_DST_SHORT,
index % 2 != 0, locale); locale);
} }
return; return;
} }
// Check parent locale first
if (!exists(names, index)) {
CLDRLocaleProviderAdapter clpa = (CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR);
var cands = clpa.getCandidateLocales("", locale);
if (cands.size() > 1) {
var parentLoc = cands.get(1); // immediate parent locale
String[] parentNames = super.getDisplayNameArray(id, parentLoc);
if (parentNames != null && !parentNames[index].isEmpty()) {
names[index] = parentNames[index];
return;
}
}
}
// Check if COMPAT can substitute the name // Check if COMPAT can substitute the name
if (LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) { if (LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) {
String[] compatNames = (String[])LocaleProviderAdapter.forJRE() String[] compatNames = (String[])LocaleProviderAdapter.forJRE()
@ -173,21 +179,19 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
} }
} }
// Type Fallback
if (noDST && typeFallback(names, index)) {
return;
}
// Region Fallback // Region Fallback
if (regionFormatFallback(names, index, locale)) { if (regionFormatFallback(names, index, locale)) {
return; return;
} }
// Type Fallback
if (noDST && typeFallback(names, index)) {
return;
}
// last resort // last resort
if (!id.toUpperCase(Locale.ROOT).startsWith("UT")) {
names[index] = toGMTFormat(id, names[index] = toGMTFormat(id,
index == INDEX_DST_LONG || index == INDEX_DST_SHORT, index == INDEX_DST_LONG || index == INDEX_DST_SHORT,
index % 2 != 0,
locale); locale);
// aliases of "GMT" timezone. // aliases of "GMT" timezone.
if ((exists(names, INDEX_STD_LONG)) && (id.startsWith("Etc/") if ((exists(names, INDEX_STD_LONG)) && (id.startsWith("Etc/")
@ -206,7 +210,6 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
} }
} }
} }
}
private boolean exists(String[] names, int index) { private boolean exists(String[] names, int index) {
return Objects.nonNull(names) return Objects.nonNull(names)
@ -217,12 +220,12 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
private boolean typeFallback(String[] names, int index) { private boolean typeFallback(String[] names, int index) {
// check generic // check generic
int genIndex = INDEX_GEN_SHORT - index % 2; int genIndex = INDEX_GEN_SHORT - index % 2;
if (!exists(names, index) && exists(names, genIndex)) { if (!exists(names, index) && exists(names, genIndex) && !names[genIndex].startsWith("GMT")) {
names[index] = names[genIndex]; names[index] = names[genIndex];
} else { } else {
// check standard // check standard
int stdIndex = INDEX_STD_SHORT - index % 2; int stdIndex = INDEX_STD_SHORT - index % 2;
if (!exists(names, index) && exists(names, stdIndex)) { if (!exists(names, index) && exists(names, stdIndex) && !names[stdIndex].startsWith("GMT")) {
names[index] = names[stdIndex]; names[index] = names[stdIndex];
} }
} }
@ -235,6 +238,7 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l); LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l);
ResourceBundle fd = lr.getJavaTimeFormatData(); ResourceBundle fd = lr.getJavaTimeFormatData();
id = TimeZoneNameUtility.canonicalTZID(id).orElse(id);
String rgn = (String) lr.getTimeZoneNames("timezone.excity." + id); String rgn = (String) lr.getTimeZoneNames("timezone.excity." + id);
if (rgn == null && !id.startsWith("Etc") && !id.startsWith("SystemV")) { if (rgn == null && !id.startsWith("Etc") && !id.startsWith("SystemV")) {
int slash = id.lastIndexOf('/'); int slash = id.lastIndexOf('/');
@ -264,7 +268,7 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
return exists(names, index); return exists(names, index);
} }
private String toGMTFormat(String id, boolean daylight, boolean isShort, Locale l) { private String toGMTFormat(String id, boolean daylight, Locale l) {
TimeZone tz = ZoneInfoFile.getZoneInfo(id); TimeZone tz = ZoneInfoFile.getZoneInfo(id);
int offset = (tz.getRawOffset() + (daylight ? tz.getDSTSavings() : 0)) / 60000; int offset = (tz.getRawOffset() + (daylight ? tz.getDSTSavings() : 0)) / 60000;
LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l); LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l);
@ -283,7 +287,7 @@ public class CLDRTimeZoneNameProviderImpl extends TimeZoneNameProviderImpl {
offset = -offset; offset = -offset;
} }
hourFormat = hourFormat hourFormat = hourFormat
.replaceFirst("H+", (isShort ? "\\%1\\$d" : "\\%1\\$02d")) .replaceFirst("H+", "\\%1\\$02d")
.replaceFirst("m+", "\\%2\\$02d"); .replaceFirst("m+", "\\%2\\$02d");
return MessageFormat.format(gmtFormat, return MessageFormat.format(gmtFormat,
String.format(l, hourFormat, offset / 60, offset % 60)); String.format(l, hourFormat, offset / 60, offset % 60));

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,6 +24,7 @@
/* /*
* @test * @test
* @bug 8005471 8008577 8129881 8130845 8136518 8181157 8210490 8220037 * @bug 8005471 8008577 8129881 8130845 8136518 8181157 8210490 8220037
* 8234347 8236548
* @modules jdk.localedata * @modules jdk.localedata
* @run main/othervm -Djava.locale.providers=CLDR CLDRDisplayNamesTest * @run main/othervm -Djava.locale.providers=CLDR CLDRDisplayNamesTest
* @summary Make sure that localized time zone names of CLDR are used * @summary Make sure that localized time zone names of CLDR are used
@ -95,12 +96,14 @@ public class CLDRDisplayNamesTest {
} }
// for 8129881 // for 8129881
/* 8234347: CLDR Converter will not pre-fill short display names from COMPAT anymore.
tz = TimeZone.getTimeZone("Europe/Vienna"); tz = TimeZone.getTimeZone("Europe/Vienna");
String name = tz.getDisplayName(false, SHORT, Locale.ENGLISH); String name = tz.getDisplayName(false, SHORT, Locale.ENGLISH);
if (!"CET".equals(name)) { if (!"CET".equals(name)) {
System.err.printf("error: got '%s' expected 'CET' %n", name); System.err.printf("error: got '%s' expected 'CET' %n", name);
errors++; errors++;
} }
*/
// for 8130845 // for 8130845
SimpleDateFormat fmtROOT = new SimpleDateFormat("EEE MMM d hh:mm:ss z yyyy", Locale.ROOT); SimpleDateFormat fmtROOT = new SimpleDateFormat("EEE MMM d hh:mm:ss z yyyy", Locale.ROOT);
@ -109,7 +112,7 @@ public class CLDRDisplayNamesTest {
Locale originalLocale = Locale.getDefault(); Locale originalLocale = Locale.getDefault();
try { try {
Locale.setDefault(Locale.ROOT); Locale.setDefault(Locale.ROOT);
fmtROOT.parse("Thu Nov 13 04:35:51 AKST 2008"); fmtROOT.parse("Thu Nov 13 04:35:51 GMT-09:00 2008");
fmtUS.parse("Thu Nov 13 04:35:51 AKST 2008"); fmtUS.parse("Thu Nov 13 04:35:51 AKST 2008");
fmtUK.parse("Thu Nov 13 04:35:51 GMT-09:00 2008"); fmtUK.parse("Thu Nov 13 04:35:51 GMT-09:00 2008");
} catch (ParseException pe) { } catch (ParseException pe) {
@ -154,6 +157,7 @@ public class CLDRDisplayNamesTest {
// 8220037: Make sure CLDRConverter uniquely produces bundles, regardless of the // 8220037: Make sure CLDRConverter uniquely produces bundles, regardless of the
// source file enumeration order. // source file enumeration order.
/* 8234347: CLDR Converter will not pre-fill short display names from COMPAT anymore.
tz = TimeZone.getTimeZone("America/Argentina/La_Rioja"); tz = TimeZone.getTimeZone("America/Argentina/La_Rioja");
if (!"ARST".equals(tz.getDisplayName(true, TimeZone.SHORT, if (!"ARST".equals(tz.getDisplayName(true, TimeZone.SHORT,
new Locale.Builder() new Locale.Builder()
@ -163,6 +167,7 @@ public class CLDRDisplayNamesTest {
System.err.println("Short display name of \"" + tz.getID() + "\" was not \"ARST\""); System.err.println("Short display name of \"" + tz.getID() + "\" was not \"ARST\"");
errors++; errors++;
} }
*/
if (errors > 0) { if (errors > 0) {
throw new RuntimeException("test failed"); throw new RuntimeException("test failed");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 8134384 * @bug 8134384 8234347 8236548
* @summary Tests CLDR TimeZoneNames has English names for all tzids * @summary Tests CLDR TimeZoneNames has English names for all tzids
* @run main/othervm -Djava.locale.providers=CLDR Bug8134384 * @run main/othervm -Djava.locale.providers=CLDR Bug8134384
*/ */
@ -43,12 +43,10 @@ public class Bug8134384 {
String date1 = Date.from(Instant.parse("2015-06-21T00:00:00.00Z")).toString(); String date1 = Date.from(Instant.parse("2015-06-21T00:00:00.00Z")).toString();
testParse(Locale.ENGLISH, date1, tz); testParse(Locale.ENGLISH, date1, tz);
testParse(Locale.US, date1, tz); testParse(Locale.US, date1, tz);
testParse(Locale.ROOT, date1, tz);
// Winter solstice // Winter solstice
String date2 = Date.from(Instant.parse("2015-12-22T00:00:00.00Z")).toString(); String date2 = Date.from(Instant.parse("2015-12-22T00:00:00.00Z")).toString();
testParse(Locale.ENGLISH, date2, tz); testParse(Locale.ENGLISH, date2, tz);
testParse(Locale.US, date2, tz); testParse(Locale.US, date2, tz);
testParse(Locale.ROOT, date2, tz);
} }
} finally { } finally {
TimeZone.setDefault(original); TimeZone.setDefault(original);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,19 +23,22 @@
/* /*
* @test * @test
* @bug 8181157 8202537 * @bug 8181157 8202537 8234347 8236548
* @modules jdk.localedata * @modules jdk.localedata
* @summary Checks CLDR time zone names are generated correctly at runtime * @summary Checks CLDR time zone names are generated correctly at runtime
* @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest
*/ */
import static org.testng.Assert.assertEquals; import java.text.DateFormatSymbols;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.format.TextStyle; import java.time.format.TextStyle;
import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone; import java.util.TimeZone;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -51,91 +54,126 @@ public class TimeZoneNamesTest {
// on the CLDR data upgrade. // on the CLDR data upgrade.
// no "metazone" zones // no "metazone" zones
{"Asia/Srednekolymsk", Locale.US, "Srednekolymsk Time", {"Asia/Srednekolymsk", Locale.US, "Srednekolymsk Standard Time",
"SRET", "GMT+11:00",
"Srednekolymsk Daylight Time", "Srednekolymsk Daylight Time",
"SREDT", "GMT+11:00",
"Srednekolymsk Time", "Srednekolymsk Time",
"SRET"}, "GMT+11:00"},
{"Asia/Srednekolymsk", Locale.FRANCE, "Srednekolymsk (heure standard)", {"Asia/Srednekolymsk", Locale.FRANCE, "Srednekolymsk (heure standard)",
"UTC+11:00", "UTC+11:00",
"Srednekolymsk (heure standard)", "Srednekolymsk (heure d\u2019\u00e9t\u00e9)",
"UTC+11:00", "UTC+11:00",
"heure : Srednekolymsk", "heure : Srednekolymsk",
"UTC+11:00"}, "UTC+11:00"},
{"America/Punta_Arenas", Locale.US, "Punta Arenas Standard Time", {"America/Punta_Arenas", Locale.US, "Punta Arenas Standard Time",
"GMT-03:00", "GMT-03:00",
"Punta Arenas Standard Time", "Punta Arenas Daylight Time",
"GMT-03:00", "GMT-03:00",
"Punta Arenas Time", "Punta Arenas Time",
"GMT-03:00"}, "GMT-03:00"},
{"America/Punta_Arenas", Locale.FRANCE, "Punta Arenas (heure standard)", {"America/Punta_Arenas", Locale.FRANCE, "Punta Arenas (heure standard)",
"UTC\u221203:00", "UTC\u221203:00",
"Punta Arenas (heure standard)", "Punta Arenas (heure d\u2019\u00e9t\u00e9)",
"UTC\u221203:00", "UTC\u221203:00",
"heure : Punta Arenas", "heure : Punta Arenas",
"UTC\u221203:00"}, "UTC\u221203:00"},
{"Asia/Famagusta", Locale.US, "Eastern European Time", {"Asia/Famagusta", Locale.US, "Famagusta Standard Time",
"EET", "GMT+02:00",
"Eastern European Summer Time", "Famagusta Daylight Time",
"EEST", "GMT+03:00",
"Eastern European Time", "Famagusta Time",
"EET"}, "GMT+02:00"},
{"Asia/Famagusta", Locale.FRANCE, "Famagouste (heure standard)", {"Asia/Famagusta", Locale.FRANCE, "Famagouste (heure standard)",
"UTC+02:00", "UTC+02:00",
"Famagouste (heure standard)", "Famagouste (heure d\u2019\u00e9t\u00e9)",
"UTC+03:00", "UTC+03:00",
"heure : Famagouste", "heure : Famagouste",
"UTC+02:00"}, "UTC+02:00"},
{"Europe/Astrakhan", Locale.US, "Astrakhan Standard Time", {"Europe/Astrakhan", Locale.US, "Astrakhan Standard Time",
"GMT+04:00", "GMT+04:00",
"Astrakhan Standard Time", "Astrakhan Daylight Time",
"GMT+04:00", "GMT+04:00",
"Astrakhan Time", "Astrakhan Time",
"GMT+04:00"}, "GMT+04:00"},
{"Europe/Astrakhan", Locale.FRANCE, "Astrakhan (heure standard)", {"Europe/Astrakhan", Locale.FRANCE, "Astrakhan (heure standard)",
"UTC+04:00", "UTC+04:00",
"Astrakhan (heure standard)", "Astrakhan (heure d\u2019\u00e9t\u00e9)",
"UTC+04:00", "UTC+04:00",
"heure : Astrakhan", "heure : Astrakhan",
"UTC+04:00"}, "UTC+04:00"},
{"Europe/Saratov", Locale.US, "Saratov Standard Time", {"Europe/Saratov", Locale.US, "Saratov Standard Time",
"GMT+04:00", "GMT+04:00",
"Saratov Standard Time", "Saratov Daylight Time",
"GMT+04:00", "GMT+04:00",
"Saratov Time", "Saratov Time",
"GMT+04:00"}, "GMT+04:00"},
{"Europe/Saratov", Locale.FRANCE, "Saratov (heure standard)", {"Europe/Saratov", Locale.FRANCE, "Saratov (heure standard)",
"UTC+04:00", "UTC+04:00",
"Saratov (heure standard)", "Saratov (heure d\u2019\u00e9t\u00e9)",
"UTC+04:00", "UTC+04:00",
"heure : Saratov", "heure : Saratov",
"UTC+04:00"}, "UTC+04:00"},
{"Europe/Ulyanovsk", Locale.US, "Ulyanovsk Standard Time", {"Europe/Ulyanovsk", Locale.US, "Ulyanovsk Standard Time",
"GMT+04:00", "GMT+04:00",
"Ulyanovsk Standard Time", "Ulyanovsk Daylight Time",
"GMT+04:00", "GMT+04:00",
"Ulyanovsk Time", "Ulyanovsk Time",
"GMT+04:00"}, "GMT+04:00"},
{"Europe/Ulyanovsk", Locale.FRANCE, "Oulianovsk (heure standard)", {"Europe/Ulyanovsk", Locale.FRANCE, "Oulianovsk (heure standard)",
"UTC+04:00", "UTC+04:00",
"Oulianovsk (heure standard)", "Oulianovsk (heure d\u2019\u00e9t\u00e9)",
"UTC+04:00", "UTC+04:00",
"heure : Oulianovsk", "heure : Oulianovsk",
"UTC+04:00"}, "UTC+04:00"},
{"Pacific/Bougainville", Locale.US, "Bougainville Standard Time", {"Pacific/Bougainville", Locale.US, "Bougainville Standard Time",
"BST", "GMT+11:00",
"Bougainville Daylight Time", "Bougainville Daylight Time",
"BST", "GMT+11:00",
"Bougainville Time", "Bougainville Time",
"BT"}, "GMT+11:00"},
{"Pacific/Bougainville", Locale.FRANCE, "Bougainville (heure standard)", {"Pacific/Bougainville", Locale.FRANCE, "Bougainville (heure standard)",
"UTC+11:00", "UTC+11:00",
"Bougainville (heure standard)", "Bougainville (heure d\u2019\u00e9t\u00e9)",
"UTC+11:00", "UTC+11:00",
"heure : Bougainville", "heure : Bougainville",
"UTC+11:00"}, "UTC+11:00"},
{"Europe/Istanbul", Locale.US, "Istanbul Standard Time",
"GMT+03:00",
"Istanbul Daylight Time",
"GMT+03:00",
"Istanbul Time",
"GMT+03:00"},
{"Europe/Istanbul", Locale.FRANCE, "Istanbul (heure standard)",
"UTC+03:00",
"Istanbul (heure d\u2019\u00e9t\u00e9)",
"UTC+03:00",
"heure : Istanbul",
"UTC+03:00"},
{"Asia/Istanbul", Locale.US, "Istanbul Standard Time",
"GMT+03:00",
"Istanbul Daylight Time",
"GMT+03:00",
"Istanbul Time",
"GMT+03:00"},
{"Asia/Istanbul", Locale.FRANCE, "Istanbul (heure standard)",
"UTC+03:00",
"Istanbul (heure d\u2019\u00e9t\u00e9)",
"UTC+03:00",
"heure : Istanbul",
"UTC+03:00"},
{"Turkey", Locale.US, "Istanbul Standard Time",
"GMT+03:00",
"Istanbul Daylight Time",
"GMT+03:00",
"Istanbul Time",
"GMT+03:00"},
{"Turkey", Locale.FRANCE, "Istanbul (heure standard)",
"UTC+03:00",
"Istanbul (heure d\u2019\u00e9t\u00e9)",
"UTC+03:00",
"heure : Istanbul",
"UTC+03:00"},
}; };
} }
@ -154,4 +192,20 @@ public class TimeZoneNamesTest {
assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale), lgen); assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.FULL, locale), lgen);
assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale), sgen); assertEquals(ZoneId.of(tzid).getDisplayName(TextStyle.SHORT, locale), sgen);
} }
// Make sure getZoneStrings() returns non-empty string array
@Test
public void test_getZoneStrings() {
assertFalse(
Arrays.stream(Locale.getAvailableLocales())
.peek(l -> System.out.println("Locale: " + l))
.map(l -> DateFormatSymbols.getInstance(l).getZoneStrings())
.flatMap(zs -> Arrays.stream(zs))
.peek(names -> System.out.println(" tz: " + names[0]))
.flatMap(names -> Arrays.stream(names))
.filter(name -> Objects.isNull(name) || name.isEmpty())
.findAny()
.isPresent(),
"getZoneStrings() returned array containing non-empty string element(s)");
}
} }