/*
* Copyright (c) 2002, 2016, 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.
*
* 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.
*/
/*
* @test
* @bug 6405639 8008577 8151876
* @summary Validate timezone display names in
* src/java.base/share/classes/sun/util/resources/TimeZoneNames.java.
* @modules java.base/sun.util.resources
* @compile -XDignore.symbol.file CheckDisplayNames.java
* @run main/othervm -Djava.locale.providers=COMPAT,SPI CheckDisplayNames
*/
import java.util.*;
import sun.util.resources.TimeZoneNames;
/**
* CheckDisplayNames checks all available time zones in the Java run
* time environment and sees if those have their display names besides doing
* some other test cases. It outputs time zones that don't have display names
* if -source option is specified.
*
*
* Usage: java CheckDisplayNames [-source]
* -source ... produces source code for editing TimeZoneNames.java.
*
*
*/
public class CheckDisplayNames {
private static boolean err = false;
private static boolean src = false;
private static Locale[] locales = Locale.getAvailableLocales();
private static String[] zones = TimeZone.getAvailableIDs();
private static List newGMTzones = new ArrayList<>();
public static void setNewGMTzones() {
for (String zone : zones) {
String shortName = TimeZone.getTimeZone(zone).getDisplayName(false, TimeZone.SHORT);
String longName = TimeZone.getTimeZone(zone).getDisplayName(false, TimeZone.LONG);
if (!(zone.contains("GMT+") || zone.contains("GMT-")) && shortName.equals(longName)) {
newGMTzones.add(TimeZone.getTimeZone(zone).getDisplayName());
}
}
}
private static String[] zones_118 = {
"ACT", "Australia/Darwin",
"AET", "Australia/Sydney",
"AGT", "America/Buenos_Aires",
"ART", "Africa/Cairo",
"AST", "America/Anchorage",
"BET", "America/Sao_Paulo",
"BST", "Asia/Dacca",
"CAT", "Africa/Harare",
"CNT", "America/St_Johns",
"CST", "America/Chicago",
"CTT", "Asia/Shanghai",
"EAT", "Africa/Addis_Ababa",
"ECT", "Europe/Paris",
// "EET", "Africa/Istanbul",
"EST", "America/New_York",
"HST", "Pacific/Honolulu",
"IET", "America/Indiana/Indianapolis",
// Comment out for this test case fails as the result of L10N for hi_IN.
// "IST", "Asia/Calcutta",
"JST", "Asia/Tokyo",
// "MET", "Asia/Tehran",
"MIT", "Pacific/Apia",
"MST", "America/Denver",
"NET", "Asia/Yerevan",
"NST", "Pacific/Auckland",
"PLT", "Asia/Karachi",
"PNT", "America/Phoenix",
"PRT", "America/Puerto_Rico",
"PST", "America/Los_Angeles",
"SST", "Pacific/Guadalcanal",
"VST", "Asia/Saigon",
};
public static void main(String[] argv) {
Locale reservedLocale = Locale.getDefault();
try {
if (argv.length == 1 && "-source".equals(argv[0])) {
src = true;
}
setNewGMTzones();
testDisplayNames();
testRAWoffsetAndDisplayNames();
test118DisplayNames();
if (err) {
throw new RuntimeException(
"TimeZone display name validation failed.");
} else {
System.out.println(
"\nAll test passed.\nTotal number of valid TimeZone id is "
+ zones.length);
}
} finally {
// restore the reserved locale
Locale.setDefault(reservedLocale);
}
}
/*
* Checks if each timezone ID has display names. If it doesn't and
* "-source" option was specified, source code is generated.
*/
private static void testDisplayNames() {
System.out.println("Checking if each entry in TimeZoneNames is a valid TimeZone ID");
Locale.setDefault(Locale.US);
Enumeration data = new TimeZoneNames().getKeys();
while (data.hasMoreElements()) {
String name = (String)data.nextElement();
String id = TimeZone.getTimeZone(name).getID();
if (!name.equals(id)) {
System.err.println("\t" + name + " doesn't seem to be a valid TimeZone ID.");
err = true;
}
}
System.out.println("Checking if each TimeZone ID has display names.");
for (int i = 0; i < zones.length; i++) {
String id = zones[i];
if (id != null) {
if (id.startsWith("Etc/GMT")) {
continue;
}
if (id.indexOf("Riyadh8") != -1) {
continue;
}
if (id.equals("GMT0")) {
continue;
}
}
TimeZone tz = TimeZone.getTimeZone(id);
String name = tz.getDisplayName();
if ((name == null || name.startsWith("GMT+") || name.startsWith("GMT-")) && !newGMTzones.contains(name)) {
if (src) {
System.out.println("\t {\"" + tz.getID() + "\", " +
"new String[] {\"Standard Time Name\", \"ST\",\n" +
"\t\t\t\t\t\t\"Daylight Time Name\", \"DT\"}},");
} else {
System.err.println("\t" + tz.getID() + " doesn't seem to have display names");
err = true;
}
}
}
}
/*
* Compares
* - raw DST offset
* - short display names in non-DST
* - short display names in DST
* - long display names in DST
* of two timezones whose long display names in non-DST are same.
* If one of these are different, there may be a bug.
*/
private static void testRAWoffsetAndDisplayNames() {
System.out.println("Checking if each entry in TimeZoneNames is a valid TimeZone ID");
HashMap map = new HashMap();
for (int i = 0; i < locales.length; i++) {
map.clear();
for (int j = 0; j < zones.length; j++) {
TimeZone tz1 = TimeZone.getTimeZone(zones[j]);
String name = tz1.getDisplayName(false, TimeZone.LONG, locales[i]);
if (map.containsKey(name)) {
TimeZone tz2 = map.get(name);
int offset1 = tz1.getRawOffset();
int offset2 = tz2.getRawOffset();
if (offset1 != offset2) {
System.err.println("Two timezones which have the same long display name \"" +
name + "\" in non-DST have different DST offsets in " +
locales[i] + " locale.\n\tTimezone 1=" +
tz1.getID() + "(" + offset1 + ")\n\tTimezone 2=" +
tz2.getID() + "(" + offset2 + ")");
}
String name1 = tz1.getDisplayName(false, TimeZone.SHORT, locales[i]);
String name2 = tz2.getDisplayName(false, TimeZone.SHORT, locales[i]);
if (!(name1.equals("GMT") && name2.equals("GMT")) &&
!(name1.equals("CET") && name2.equals("MET")) &&
!(name1.equals("MET") && name2.equals("CET"))) {
if (!name1.equals(name2)) {
System.err.println("Two timezones which have the same short display name \"" +
name +
"\" in non-DST have different short display names in non-DST in " +
locales[i] + " locale.\n\tTimezone 1=" +
tz1.getID() + "(" + name1 + ")\n\tTimezone 2=" +
tz2.getID() + "(" + name2 + ")");
}
name1 = tz1.getDisplayName(true, TimeZone.SHORT, locales[i]);
name2 = tz2.getDisplayName(true, TimeZone.SHORT, locales[i]);
if (!name1.equals(name2)) {
System.err.println("Two timezones which have the same short display name \"" +
name +
"\" in non-DST have different short display names in DST in " +
locales[i] + " locale.\n\tTimezone 1=" +
tz1.getID() + "(" + name1 + ")\n\tTimezone 2=" +
tz2.getID() + "(" + name2 + ")");
}
name1 = tz1.getDisplayName(true, TimeZone.LONG, locales[i]);
name2 = tz2.getDisplayName(true, TimeZone.LONG, locales[i]);
if (!name1.equals(name2)) {
System.err.println("Two timezones which have the same long display name \"" +
name +
"\" in non-DST have different long display names in DST in " +
locales[i] + " locale.\n\tTimezone 1=" +
tz1.getID() + "(" + name1 + ")\n\tTimezone 2=" +
tz2.getID() + "(" + name2 + ")");
}
}
} else {
map.put(name, tz1);
}
}
}
}
/*
* Compares three-letter timezones' display names with corresponding
* "popular" timezones.
*/
private static void test118DisplayNames() {
System.out.println("Checking compatibility of Java 1.1.X's three-letter timezones");
for (int i = 0; i < zones_118.length; i+=2) {
String id_118 = zones_118[i];
String id_later = zones_118[i+1];
String zone_118, zone_later, localename;
TimeZone tz_118 = TimeZone.getTimeZone(id_118);
TimeZone tz_later = TimeZone.getTimeZone(id_later);
for (int j = 0; j < locales.length; j++) {
localename = locales[j].toString();
zone_118 = tz_118.getDisplayName(false, TimeZone.SHORT, locales[j]);
zone_later = tz_later.getDisplayName(false, TimeZone.SHORT, locales[j]);
check(id_118, id_later, zone_118, zone_later, "short", "non-DST", localename);
zone_118 = tz_118.getDisplayName(true, TimeZone.SHORT, locales[j]);
zone_later = tz_later.getDisplayName(true, TimeZone.SHORT, locales[j]);
check(id_118, id_later, zone_118, zone_later, "short", "DST", localename);
zone_118 = tz_118.getDisplayName(false, TimeZone.LONG, locales[j]);
zone_later = tz_later.getDisplayName(false, TimeZone.LONG, locales[j]);
check(id_118, id_later, zone_118, zone_later, "long", "non-DST", localename);
zone_118 = tz_118.getDisplayName(true, TimeZone.LONG, locales[j]);
zone_later = tz_later.getDisplayName(true, TimeZone.LONG, locales[j]);
check(id_118, id_later, zone_118, zone_later, "long", "DST", localename);
}
}
}
private static void check(String zoneID_118, String zoneID_later,
String zonename_118, String zonename_later,
String format, String dst, String loc) {
if (!zonename_118.equals(zonename_later)) {
System.err.println("JDK 118 TimeZone \"" + zoneID_118 +
"\" has a different " + format +
" display name from its equivalent timezone \"" +
zoneID_later + "\" in " + dst + " in " + loc + " locale.");
System.err.println(" Got: " + zonename_118 + ", Expected: " +
zonename_later);
err = true;
}
}
}