1 /*
  2  * Copyright (c) 2005, 2022, 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 6329116 6756569 6757131 6758988 6764308 6796489 6834474 6609737 6507067
 27  *      7039469 7090843 7103108 7103405 7158483 8008577 8059206 8064560 8072042
 28  *      8077685 8151876 8166875 8169191 8170316 8176044
 29  * @summary Make sure that timezone short display names are idenical to Olson's data.
 30  * @library /java/text/testlib
 31  * @build Bug6329116 TextFileReader
 32  * @run main/othervm -Djava.locale.providers=COMPAT,SPI Bug6329116
 33  */
 34 
 35 import java.io.*;
 36 import java.text.*;
 37 import java.util.*;
 38 
 39 public class Bug6329116 extends IntlTest {
 40 
 41     static Locale[] locales = Locale.getAvailableLocales();
 42     static String[] timezones = TimeZone.getAvailableIDs();
 43 
 44     public static void main(String[] args) throws IOException {
 45         if (bug6329116()) {
 46             throw new RuntimeException("At least one timezone display name is incorrect.");
 47         }
 48     }
 49 
 50     static boolean bug6329116() throws IOException {
 51         boolean err = false;
 52 
 53         HashMap<String, String> aliasTable = new HashMap<>();
 54         HashSet<String> timezoneTable = new HashSet<>();
 55         for (String t : timezones) {
 56             timezoneTable.add(t);
 57         }
 58 
 59         String line, key, value;
 60         StringTokenizer st;
 61 
 62         try (TextFileReader in = new TextFileReader("aliases.txt")) {
 63             while ((line = in.readLine()) != null) {
 64                 st = new StringTokenizer(line);
 65                 st.nextToken();
 66                 key = st.nextToken();
 67                 value = st.nextToken();
 68 
 69                 if (!value.equals("ROC")) {
 70                     if (aliasTable.containsKey(key)) {
 71                         aliasTable.put(key, aliasTable.get(key) + " " + value);
 72                     } else {
 73                         aliasTable.put(key, value);
 74                     }
 75                 }
 76             }
 77         }
 78 
 79         try (TextFileReader in = new TextFileReader("displaynames.txt")) {
 80             String timezoneID, expected, expected_DST, got;
 81             String[] aliases, tzs;
 82             TimeZone tz;
 83             while ((line = in.readLine()) != null) {
 84                 st = new StringTokenizer(line);
 85                 timezoneID = st.nextToken();
 86                 expected = st.nextToken();
 87                 if (st.hasMoreTokens()) {
 88                     expected_DST = st.nextToken();
 89                 } else {
 90                     expected_DST = null;
 91                 }
 92 
 93                 if (aliasTable.containsKey(timezoneID)) {
 94                     aliases = aliasTable.get(timezoneID).split(" ");
 95                     tzs = new String[1 + aliases.length];
 96                     System.arraycopy(aliases, 0, tzs, 1, aliases.length);
 97                     aliasTable.remove(timezoneID);
 98                 } else {
 99                     tzs = new String[1];
100                 }
101                 tzs[0] = timezoneID;
102 
103                 for (int j = 0; j < tzs.length; j++) {
104                     tz = TimeZone.getTimeZone(tzs[j]);
105 
106                     if (!tzs[j].equals(tz.getID())) {
107                         System.err.println(tzs[j] + " may not be a valid Timezone ID and \"" + tz.getID() + "\" was returned. Please check it.");
108                         err = true;
109                     }
110 
111                     timezoneTable.remove(tzs[j]);
112 
113                     for (int i = 0; i < locales.length; i++) {
114                         got = tz.getDisplayName(false, TimeZone.SHORT, locales[i]);
115                         if (!expected.equals(got) &&
116                             !expected.startsWith(got + "/") &&
117                             !expected.endsWith("/" + got)) {
118                             if (useLocalzedShortDisplayName(tz, locales[i], got, false)) {
119 /*
120                                 System.out.println(tzs[j] +
121                                                    ((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
122                                                    " seems to use a localized short display name" +
123                                                    ": original: " + expected +
124                                                    ": got: " + got + " for non-DST in " +
125                                                    locales[i] + " locale.");
126 */
127                             } else {
128                                 System.err.println(tzs[j] +
129                                                    ((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
130                                                    ": expected: " + expected +
131                                                    ": got: " + got + " for non-DST in " +
132                                                    locales[i] + " locale.");
133                                 err = true;
134                             }
135                         }
136 
137                         got = tz.getDisplayName(true, TimeZone.SHORT, locales[i]);
138                         if (expected_DST != null) {
139                             if (!expected_DST.equals(got) &&
140                                 !expected_DST.startsWith(got + "/") &&
141                                 !expected_DST.endsWith("/" + got)) {
142                                 if (tzs[j].equals("Europe/London") &&
143                                     locales[i].equals(new Locale("en", "IE"))) {
144                                     continue;
145                                 } else if (useLocalzedShortDisplayName(tz, locales[i], got, true)) {
146 /*
147                                 System.out.println(tzs[j] +
148                                     ((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
149                                     " seems to use a localized short display name" +
150                                     ": original: " + expected_DST +
151                                     ": got: " + got + " for DST in " +
152                                     locales[i] + " locale.");
153 */
154                                     continue;
155                                 }
156                                 System.err.println(tzs[j] +
157                                                    ((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
158                                                    ": expected: " + expected_DST +
159                                                    ": got: " + got + " for DST in " +
160                                                    locales[i] + " locale.");
161                                 err = true;
162                             }
163                         } else {
164                             // Some timezones don't have DST display names in Olson's data,
165                             // and we created them ourselves based on non-DST display names
166                             // to prepare potential use in the future.
167                             // Because there's no expected name, we don't judge if these
168                             // DST display names are correct but just compare them with
169                             // non-DST diplay names for checking with our eyes .
170                             if (!expected.equals(got) &&
171                                 !expected.startsWith(got + "/") &&
172                                 !expected.endsWith("/" + got)) {
173 /*
174                                 System.out.println("## " + tzs[j] +
175                                                    ((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
176                                                    ": expected: " + expected +
177                                                    ": got: " + got + " for DST in " +
178                                                    locales[i] + " locale.");
179 */
180                             }
181                         }
182                     }
183                 }
184             }
185         }
186 
187         if (!timezoneTable.isEmpty()) {
188             System.out.println("# Timezone(s) valid in JRE but untested in this test program:");
189             Iterator<String> it = timezoneTable.iterator();
190             while (it.hasNext()) {
191                 System.out.println(it.next());
192             }
193             System.out.println();
194         }
195 
196         if (!aliasTable.isEmpty()) {
197             System.out.println("# Timezone(s) exists in Olson's data as Link but unused in JRE:");
198             for (Map.Entry<String, String> entry : aliasTable.entrySet()) {
199                 System.out.println(entry);
200             }
201         }
202 
203         return err;
204     }
205 
206     static boolean useLocalzedShortDisplayName(TimeZone tz,
207                                                Locale locale,
208                                                String got,
209                                                boolean inDST) {
210         if (locale.getLanguage().equals("de")) {
211             String name = tz.getDisplayName(inDST, TimeZone.LONG, locale);
212             if (inDST) {
213                 if (("Mitteleurop\u00e4ische Sommerzeit".equals(name) && "MESZ".equals(got)) ||
214                     ("Osteurop\u00e4ische Sommerzeit".equals(name) && "OESZ".equals(got)) ||
215                     ("Westeurop\u00e4ische Sommerzeit".equals(name) && "WESZ".equals(got))) {
216                     return true;
217                 }
218             } else {
219                 if (("Mitteleurop\u00e4ische Zeit".equals(name) && "MEZ".equals(got)) ||
220                     ("Osteurop\u00e4ische Zeit".equals(name) && "OEZ".equals(got)) ||
221                     ("Westeurop\u00e4ische Zeit".equals(name) && "WEZ".equals(got))) {
222                     return true;
223                 }
224             }
225         } else if (locale.getLanguage().equals("zh") &&
226             (locale.getCountry().equals("TW") || locale.getCountry().equals("HK"))) {
227             String name = tz.getDisplayName(inDST, TimeZone.LONG, locale);
228             if (inDST) {
229                 if (("\u53f0\u7063\u590f\u4ee4\u6642\u9593".equals(name) && "TDT".equals(got))) {
230                     return true;
231                 }
232             } else {
233                 if (("\u53f0\u7063\u6a19\u6e96\u6642\u9593".equals(name) && "TST".equals(got))) {
234                     return true;
235                 }
236             }
237         }
238         // If we get a TimeZone with GMT+hh:mm format, we can ignore the offset value
239         if (tz.getDisplayName(Locale.ENGLISH).startsWith("GMT+") || tz.getDisplayName(Locale.ENGLISH).startsWith("GMT-")) {
240             return tz.getDisplayName().substring(0, 3).equals(got.substring(0, 3));
241         }
242 
243         return false;
244     }
245 
246 }