1 /* 2 * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 6405639 8008577 8151876 27 * @summary Validate timezone display names in 28 * src/java.base/share/classes/sun/util/resources/TimeZoneNames.java. 29 * @modules java.base/sun.util.resources 30 * @compile -XDignore.symbol.file CheckDisplayNames.java 31 * @run main/othervm -Djava.locale.providers=COMPAT,SPI CheckDisplayNames 32 */ 33 34 import java.util.*; 35 import sun.util.resources.TimeZoneNames; 36 37 /** 38 * CheckDisplayNames checks all available time zones in the Java run 39 * time environment and sees if those have their display names besides doing 40 * some other test cases. It outputs time zones that don't have display names 41 * if -source option is specified. 42 * <blockquote> 43 * <pre> 44 * Usage: java CheckDisplayNames [-source] 45 * -source ... produces source code for editing TimeZoneNames.java. 46 * </pre> 47 * </blockquote> 48 */ 49 public class CheckDisplayNames { 50 51 private static boolean err = false; 52 private static boolean src = false; 53 54 private static Locale[] locales = Locale.getAvailableLocales(); 55 private static String[] zones = TimeZone.getAvailableIDs(); 56 private static List<String> newGMTzones = new ArrayList<>(); 57 58 public static void setNewGMTzones() { 59 for (String zone : zones) { 60 String shortName = TimeZone.getTimeZone(zone).getDisplayName(false, TimeZone.SHORT); 61 String longName = TimeZone.getTimeZone(zone).getDisplayName(false, TimeZone.LONG); 62 if (!(zone.contains("GMT+") || zone.contains("GMT-")) && shortName.equals(longName)) { 63 newGMTzones.add(TimeZone.getTimeZone(zone).getDisplayName()); 64 } 65 } 66 } 67 68 private static String[] zones_118 = { 69 "ACT", "Australia/Darwin", 70 "AET", "Australia/Sydney", 71 "AGT", "America/Buenos_Aires", 72 "ART", "Africa/Cairo", 73 "AST", "America/Anchorage", 74 "BET", "America/Sao_Paulo", 75 "BST", "Asia/Dacca", 76 "CAT", "Africa/Harare", 77 "CNT", "America/St_Johns", 78 "CST", "America/Chicago", 79 "CTT", "Asia/Shanghai", 80 "EAT", "Africa/Addis_Ababa", 81 "ECT", "Europe/Paris", 82 // "EET", "Africa/Istanbul", 83 "EST", "America/New_York", 84 "HST", "Pacific/Honolulu", 85 "IET", "America/Indiana/Indianapolis", 86 // Comment out for this test case fails as the result of L10N for hi_IN. 87 // "IST", "Asia/Calcutta", 88 "JST", "Asia/Tokyo", 89 // "MET", "Asia/Tehran", 90 "MIT", "Pacific/Apia", 91 "MST", "America/Denver", 92 "NET", "Asia/Yerevan", 93 "NST", "Pacific/Auckland", 94 "PLT", "Asia/Karachi", 95 "PNT", "America/Phoenix", 96 "PRT", "America/Puerto_Rico", 97 "PST", "America/Los_Angeles", 98 "SST", "Pacific/Guadalcanal", 99 "VST", "Asia/Saigon", 100 }; 101 102 103 public static void main(String[] argv) { 104 Locale reservedLocale = Locale.getDefault(); 105 try { 106 if (argv.length == 1 && "-source".equals(argv[0])) { 107 src = true; 108 } 109 110 setNewGMTzones(); 111 testDisplayNames(); 112 testRAWoffsetAndDisplayNames(); 113 test118DisplayNames(); 114 115 if (err) { 116 throw new RuntimeException( 117 "TimeZone display name validation failed."); 118 } else { 119 System.out.println( 120 "\nAll test passed.\nTotal number of valid TimeZone id is " 121 + zones.length); 122 } 123 } finally { 124 // restore the reserved locale 125 Locale.setDefault(reservedLocale); 126 } 127 128 } 129 130 /* 131 * Checks if each timezone ID has display names. If it doesn't and 132 * "-source" option was specified, source code is generated. 133 */ 134 private static void testDisplayNames() { 135 System.out.println("Checking if each entry in TimeZoneNames is a valid TimeZone ID"); 136 137 Locale.setDefault(Locale.US); 138 Enumeration data = new TimeZoneNames().getKeys(); 139 140 while (data.hasMoreElements()) { 141 String name = (String)data.nextElement(); 142 String id = TimeZone.getTimeZone(name).getID(); 143 if (!name.equals(id)) { 144 System.err.println("\t" + name + " doesn't seem to be a valid TimeZone ID."); 145 err = true; 146 } 147 } 148 149 System.out.println("Checking if each TimeZone ID has display names."); 150 151 for (int i = 0; i < zones.length; i++) { 152 String id = zones[i]; 153 154 if (id != null) { 155 if (id.startsWith("Etc/GMT")) { 156 continue; 157 } 158 if (id.indexOf("Riyadh8") != -1) { 159 continue; 160 } 161 if (id.equals("GMT0")) { 162 continue; 163 } 164 } 165 166 TimeZone tz = TimeZone.getTimeZone(id); 167 String name = tz.getDisplayName(); 168 169 if ((name == null || name.startsWith("GMT+") || name.startsWith("GMT-")) && !newGMTzones.contains(name)) { 170 if (src) { 171 System.out.println("\t {\"" + tz.getID() + "\", " + 172 "new String[] {\"Standard Time Name\", \"ST\",\n" + 173 "\t\t\t\t\t\t\"Daylight Time Name\", \"DT\"}},"); 174 } else { 175 System.err.println("\t" + tz.getID() + " doesn't seem to have display names"); 176 err = true; 177 } 178 } 179 } 180 } 181 182 /* 183 * Compares 184 * - raw DST offset 185 * - short display names in non-DST 186 * - short display names in DST 187 * - long display names in DST 188 * of two timezones whose long display names in non-DST are same. 189 * If one of these are different, there may be a bug. 190 */ 191 private static void testRAWoffsetAndDisplayNames() { 192 System.out.println("Checking if each entry in TimeZoneNames is a valid TimeZone ID"); 193 194 HashMap<String, TimeZone> map = new HashMap<String, TimeZone>(); 195 196 for (int i = 0; i < locales.length; i++) { 197 map.clear(); 198 199 for (int j = 0; j < zones.length; j++) { 200 TimeZone tz1 = TimeZone.getTimeZone(zones[j]); 201 String name = tz1.getDisplayName(false, TimeZone.LONG, locales[i]); 202 203 if (map.containsKey(name)) { 204 TimeZone tz2 = map.get(name); 205 206 int offset1 = tz1.getRawOffset(); 207 int offset2 = tz2.getRawOffset(); 208 if (offset1 != offset2) { 209 System.err.println("Two timezones which have the same long display name \"" + 210 name + "\" in non-DST have different DST offsets in " + 211 locales[i] + " locale.\n\tTimezone 1=" + 212 tz1.getID() + "(" + offset1 + ")\n\tTimezone 2=" + 213 tz2.getID() + "(" + offset2 + ")"); 214 } 215 216 String name1 = tz1.getDisplayName(false, TimeZone.SHORT, locales[i]); 217 String name2 = tz2.getDisplayName(false, TimeZone.SHORT, locales[i]); 218 if (!(name1.equals("GMT") && name2.equals("GMT")) && 219 !(name1.equals("CET") && name2.equals("MET")) && 220 !(name1.equals("MET") && name2.equals("CET"))) { 221 if (!name1.equals(name2)) { 222 System.err.println("Two timezones which have the same short display name \"" + 223 name + 224 "\" in non-DST have different short display names in non-DST in " + 225 locales[i] + " locale.\n\tTimezone 1=" + 226 tz1.getID() + "(" + name1 + ")\n\tTimezone 2=" + 227 tz2.getID() + "(" + name2 + ")"); 228 } 229 230 name1 = tz1.getDisplayName(true, TimeZone.SHORT, locales[i]); 231 name2 = tz2.getDisplayName(true, TimeZone.SHORT, locales[i]); 232 if (!name1.equals(name2)) { 233 System.err.println("Two timezones which have the same short display name \"" + 234 name + 235 "\" in non-DST have different short display names in DST in " + 236 locales[i] + " locale.\n\tTimezone 1=" + 237 tz1.getID() + "(" + name1 + ")\n\tTimezone 2=" + 238 tz2.getID() + "(" + name2 + ")"); 239 } 240 241 name1 = tz1.getDisplayName(true, TimeZone.LONG, locales[i]); 242 name2 = tz2.getDisplayName(true, TimeZone.LONG, locales[i]); 243 if (!name1.equals(name2)) { 244 System.err.println("Two timezones which have the same long display name \"" + 245 name + 246 "\" in non-DST have different long display names in DST in " + 247 locales[i] + " locale.\n\tTimezone 1=" + 248 tz1.getID() + "(" + name1 + ")\n\tTimezone 2=" + 249 tz2.getID() + "(" + name2 + ")"); 250 } 251 } 252 } else { 253 map.put(name, tz1); 254 } 255 } 256 } 257 } 258 259 /* 260 * Compares three-letter timezones' display names with corresponding 261 * "popular" timezones. 262 */ 263 private static void test118DisplayNames() { 264 System.out.println("Checking compatibility of Java 1.1.X's three-letter timezones"); 265 266 for (int i = 0; i < zones_118.length; i+=2) { 267 String id_118 = zones_118[i]; 268 String id_later = zones_118[i+1]; 269 String zone_118, zone_later, localename; 270 TimeZone tz_118 = TimeZone.getTimeZone(id_118); 271 TimeZone tz_later = TimeZone.getTimeZone(id_later); 272 273 for (int j = 0; j < locales.length; j++) { 274 localename = locales[j].toString(); 275 zone_118 = tz_118.getDisplayName(false, TimeZone.SHORT, locales[j]); 276 zone_later = tz_later.getDisplayName(false, TimeZone.SHORT, locales[j]); 277 check(id_118, id_later, zone_118, zone_later, "short", "non-DST", localename); 278 279 zone_118 = tz_118.getDisplayName(true, TimeZone.SHORT, locales[j]); 280 zone_later = tz_later.getDisplayName(true, TimeZone.SHORT, locales[j]); 281 check(id_118, id_later, zone_118, zone_later, "short", "DST", localename); 282 283 zone_118 = tz_118.getDisplayName(false, TimeZone.LONG, locales[j]); 284 zone_later = tz_later.getDisplayName(false, TimeZone.LONG, locales[j]); 285 check(id_118, id_later, zone_118, zone_later, "long", "non-DST", localename); 286 287 zone_118 = tz_118.getDisplayName(true, TimeZone.LONG, locales[j]); 288 zone_later = tz_later.getDisplayName(true, TimeZone.LONG, locales[j]); 289 check(id_118, id_later, zone_118, zone_later, "long", "DST", localename); 290 } 291 } 292 } 293 294 private static void check(String zoneID_118, String zoneID_later, 295 String zonename_118, String zonename_later, 296 String format, String dst, String loc) { 297 if (!zonename_118.equals(zonename_later)) { 298 System.err.println("JDK 118 TimeZone \"" + zoneID_118 + 299 "\" has a different " + format + 300 " display name from its equivalent timezone \"" + 301 zoneID_later + "\" in " + dst + " in " + loc + " locale."); 302 System.err.println(" Got: " + zonename_118 + ", Expected: " + 303 zonename_later); 304 err = true; 305 } 306 } 307 308 }