]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / tests / core / src / com / ibm / icu / dev / test / timezone / TimeZoneTest.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2000-2010, International Business Machines Corporation and    *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 \r
8 package com.ibm.icu.dev.test.timezone;\r
9 \r
10 import java.io.ByteArrayInputStream;\r
11 import java.io.ByteArrayOutputStream;\r
12 import java.io.IOException;\r
13 import java.io.ObjectInputStream;\r
14 import java.io.ObjectOutputStream;\r
15 import java.lang.reflect.InvocationTargetException;\r
16 import java.util.Arrays;\r
17 import java.util.Date;\r
18 import java.util.List;\r
19 import java.util.Locale;\r
20 \r
21 import com.ibm.icu.dev.test.TestFmwk;\r
22 import com.ibm.icu.impl.ICUResourceBundle;\r
23 import com.ibm.icu.text.SimpleDateFormat;\r
24 import com.ibm.icu.util.Calendar;\r
25 import com.ibm.icu.util.GregorianCalendar;\r
26 import com.ibm.icu.util.SimpleTimeZone;\r
27 import com.ibm.icu.util.TimeZone;\r
28 import com.ibm.icu.util.ULocale;\r
29 import com.ibm.icu.util.UResourceBundle;\r
30 \r
31 /**\r
32  * @test 1.22 99/09/21\r
33  * @bug 4028006 4044013 4096694 4107276 4107570 4112869 4130885\r
34  * @summary test TimeZone\r
35  * @build TimeZoneTest\r
36  */\r
37 public class TimeZoneTest extends TestFmwk\r
38 {\r
39     static final int millisPerHour = 3600000;\r
40 \r
41     // TODO: We should probably read following data at runtime, so we can update\r
42     // the these values every release with necessary data changes.\r
43 \r
44     // Some test case data is current date/tzdata version sensitive and producing errors\r
45     // when year/rule are changed.\r
46     static final int REFERENCE_YEAR = 2009;\r
47     static final String REFERENCE_DATA_VERSION = "2009d";\r
48 \r
49 \r
50 \r
51     public static void main(String[] args) throws Exception {\r
52         new TimeZoneTest().run(args);\r
53     }\r
54 \r
55     /**\r
56      * NOTE: As of ICU 2.8, the mapping of 3-letter legacy aliases\r
57      * to `real' Olson IDs is under control of the underlying JDK.\r
58      * This test may fail on one JDK and pass on another; don't be\r
59      * too concerned.  Alan\r
60      *\r
61      * Bug 4130885\r
62      * Certain short zone IDs, used since 1.1.x, are incorrect.\r
63      *  \r
64      * The worst of these is:\r
65      *\r
66      * "CAT" (Central African Time) should be GMT+2:00, but instead returns a\r
67      * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,\r
68      * or AZOST, depending on which zone is meant, but in no case is it CAT.\r
69      *\r
70      * Other wrong zone IDs:\r
71      *\r
72      * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,\r
73      * GMT-5:00. European Central time is abbreviated CEST.\r
74      *\r
75      * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,\r
76      * GMT-11:00. Solomon Island time is SBT.\r
77      *\r
78      * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for\r
79      * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.\r
80      *\r
81      * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in\r
82      * another bug.] It should be "AKST". AST is Atlantic Standard Time,\r
83      * GMT-4:00.\r
84      *\r
85      * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,\r
86      * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct\r
87      * from MST with daylight savings.\r
88      *\r
89      * In addition to these problems, a number of zones are FAKE. That is, they\r
90      * don't match what people use in the real world.\r
91      *\r
92      * FAKE zones:\r
93      *\r
94      * EET (should be EEST)\r
95      * ART (should be EEST)\r
96      * MET (should be IRST)\r
97      * NET (should be AMST)\r
98      * PLT (should be PKT)\r
99      * BST (should be BDT)\r
100      * VST (should be ICT)\r
101      * CTT (should be CST) +\r
102      * ACT (should be CST) +\r
103      * AET (should be EST) +\r
104      * MIT (should be WST) +\r
105      * IET (should be EST) +\r
106      * PRT (should be AST) +\r
107      * CNT (should be NST)\r
108      * AGT (should be ARST)\r
109      * BET (should be EST) +\r
110      *\r
111      * + A zone with the correct name already exists and means something\r
112      * else. E.g., EST usually indicates the US Eastern zone, so it cannot be\r
113      * used for Brazil (BET).\r
114      */\r
115     public void TestShortZoneIDs() throws Exception {\r
116 \r
117         // This test case is tzdata version sensitive.\r
118         boolean isNonReferenceTzdataVersion = false;\r
119         String tzdataVer = TimeZone.getTZDataVersion();\r
120         if (!tzdataVer.equals(REFERENCE_DATA_VERSION)) {\r
121             // Note: We want to display a warning message here if\r
122             // REFERENCE_DATA_VERSION is out of date - so we\r
123             // do not forget to update the value before GA.\r
124             isNonReferenceTzdataVersion = true;\r
125             logln("Warning: Active tzdata version (" + tzdataVer +\r
126                     ") does not match the reference tzdata version ("\r
127                     + REFERENCE_DATA_VERSION + ") for this test case data.");\r
128         }\r
129 \r
130         // Note: If the default TimeZone type is JDK, some time zones\r
131         // may differ from the test data below.  For example, "MST" on\r
132         // IBM JRE is an alias of "America/Denver" for supporting Java 1.1\r
133         // backward compatibility, while Olson tzdata (and ICU) treat it\r
134         // as -7hour fixed offset/no DST.\r
135         boolean isJDKTimeZone = (TimeZone.getDefaultTimeZoneType() == TimeZone.TIMEZONE_JDK);\r
136         if (isJDKTimeZone) {\r
137             logln("Warning: Using JDK TimeZone.  Some test cases may not return expected results.");\r
138         }\r
139 \r
140         // Note: useDaylightTime returns true if DST is observed\r
141         // in the time zone in the current calendar year.  The test\r
142         // data is valid for the date after the reference year below.\r
143         // If system clock is before the year, some test cases may\r
144         // fail.\r
145         GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));\r
146         cal.set(REFERENCE_YEAR, Calendar.JANUARY, 2); // day 2 in GMT\r
147 \r
148         boolean isDateBeforeReferenceYear = System.currentTimeMillis() < cal.getTimeInMillis();\r
149         if (isDateBeforeReferenceYear) {\r
150             logln("Warning: Past time is set to the system clock.  Some test cases may not return expected results.");\r
151         }\r
152 \r
153         ZoneDescriptor[] REFERENCE_LIST = {\r
154             new ZoneDescriptor("MIT", -660, false),\r
155             new ZoneDescriptor("HST", -600, false),\r
156             new ZoneDescriptor("AST", -540, true),\r
157             new ZoneDescriptor("PST", -480, true),\r
158             new ZoneDescriptor("PNT", -420, false),\r
159             new ZoneDescriptor("MST", -420, false),// updated Aug 2003 aliu\r
160             new ZoneDescriptor("CST", -360, true),\r
161             new ZoneDescriptor("IET", -300, true), // updated Feb 2006 srl\r
162             new ZoneDescriptor("EST", -300, false),// updated Aug 2003 aliu\r
163             new ZoneDescriptor("PRT", -240, false),\r
164             new ZoneDescriptor("CNT", -210, true),\r
165             new ZoneDescriptor("AGT", -180, true), // updated by tzdata 2007k\r
166             new ZoneDescriptor("BET", -180, true),\r
167             new ZoneDescriptor("GMT", 0, false),\r
168             new ZoneDescriptor("UTC", 0, false),\r
169             new ZoneDescriptor("ECT", 60, true),\r
170             new ZoneDescriptor("MET", 60, true),\r
171             new ZoneDescriptor("CAT", 120, false), // Africa/Harare\r
172             new ZoneDescriptor("ART", 120, true),\r
173             new ZoneDescriptor("EET", 120, true),\r
174             new ZoneDescriptor("EAT", 180, false),\r
175             new ZoneDescriptor("NET", 240, true),\r
176             new ZoneDescriptor("PLT", 300, false), // updated by tzdata 2008c - no DST after 2008\r
177             new ZoneDescriptor("IST", 330, false),\r
178             new ZoneDescriptor("BST", 360, false),\r
179             new ZoneDescriptor("VST", 420, false),\r
180             new ZoneDescriptor("CTT", 480, false), // updated Oct 2003 aliu\r
181             new ZoneDescriptor("JST", 540, false),\r
182             new ZoneDescriptor("ACT", 570, false), // updated Oct 2003 aliu\r
183             new ZoneDescriptor("AET", 600, true),\r
184             new ZoneDescriptor("SST", 660, false),\r
185             new ZoneDescriptor("NST", 720, true), // Pacific/Auckland\r
186 \r
187             new ZoneDescriptor("Etc/Unknown", 0, false),\r
188             new ZoneDescriptor("SystemV/AST4ADT", -240, true),\r
189             new ZoneDescriptor("SystemV/EST5EDT", -300, true),\r
190             new ZoneDescriptor("SystemV/CST6CDT", -360, true),\r
191             new ZoneDescriptor("SystemV/MST7MDT", -420, true),\r
192             new ZoneDescriptor("SystemV/PST8PDT", -480, true),\r
193             new ZoneDescriptor("SystemV/YST9YDT", -540, true),\r
194             new ZoneDescriptor("SystemV/AST4", -240, false),\r
195             new ZoneDescriptor("SystemV/EST5", -300, false),\r
196             new ZoneDescriptor("SystemV/CST6", -360, false),\r
197             new ZoneDescriptor("SystemV/MST7", -420, false),\r
198             new ZoneDescriptor("SystemV/PST8", -480, false),\r
199             new ZoneDescriptor("SystemV/YST9", -540, false),\r
200             new ZoneDescriptor("SystemV/HST10", -600, false),\r
201         };\r
202 \r
203         for (int i=0; i<REFERENCE_LIST.length; ++i) {\r
204             ZoneDescriptor referenceZone = REFERENCE_LIST[i];\r
205             ZoneDescriptor currentZone = new ZoneDescriptor(TimeZone.getTimeZone(referenceZone.getID()));\r
206             if (referenceZone.equals(currentZone)) {\r
207                 logln("ok " + referenceZone);\r
208             }\r
209             else {\r
210                 if (isNonReferenceTzdataVersion\r
211                         || isJDKTimeZone || isDateBeforeReferenceYear) {\r
212                     logln("Warning: Expected " + referenceZone +\r
213                             "; got " + currentZone);\r
214                 } else {\r
215                     errln("Fail: Expected " + referenceZone +\r
216                             "; got " + currentZone);\r
217                 }\r
218             }\r
219         }\r
220     }\r
221 \r
222     /**\r
223      * A descriptor for a zone; used to regress the short zone IDs.\r
224      */\r
225     static class ZoneDescriptor {\r
226         String id;\r
227         int offset; // In minutes\r
228         boolean daylight;\r
229 \r
230         ZoneDescriptor(TimeZone zone) {\r
231             this.id = zone.getID();\r
232             this.offset = zone.getRawOffset() / 60000;\r
233             this.daylight = zone.useDaylightTime();\r
234         }\r
235 \r
236         ZoneDescriptor(String id, int offset, boolean daylight) {\r
237             this.id = id;\r
238             this.offset = offset;\r
239             this.daylight = daylight;\r
240         }\r
241 \r
242         public String getID() { return id; }\r
243 \r
244         public boolean equals(Object o) {\r
245             ZoneDescriptor that = (ZoneDescriptor)o;\r
246             return that != null &&\r
247                 id.equals(that.id) &&\r
248                 offset == that.offset &&\r
249                 daylight == that.daylight;\r
250         }\r
251 \r
252         public String toString() {\r
253             int min = offset;\r
254             char sign = '+';\r
255             if (min < 0) { sign = '-'; min = -min; }\r
256 \r
257             return "Zone[\"" + id + "\", GMT" + sign + (min/60) + ':' +\r
258                 (min%60<10?"0":"") + (min%60) + ", " +\r
259                 (daylight ? "Daylight" : "Standard") + "]";\r
260         }\r
261 \r
262         public static int compare(Object o1, Object o2) {\r
263             ZoneDescriptor i1 = (ZoneDescriptor)o1;\r
264             ZoneDescriptor i2 = (ZoneDescriptor)o2;\r
265             if (i1.offset > i2.offset) return 1;\r
266             if (i1.offset < i2.offset) return -1;\r
267             if (i1.daylight && !i2.daylight) return 1;\r
268             if (!i1.daylight && i2.daylight) return -1;\r
269             return i1.id.compareTo(i2.id);\r
270         }\r
271     }\r
272 \r
273     /**\r
274      * As part of the VM fix (see CCC approved RFE 4028006, bug\r
275      * 4044013), TimeZone.getTimeZone() has been modified to recognize\r
276      * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and\r
277      * GMT[+-]hh.  Test this behavior here.\r
278      *\r
279      * Bug 4044013\r
280      */\r
281     public void TestCustomParse() {\r
282         String[] DATA = {\r
283             // ID               offset(sec)     output ID\r
284             "GMT",              "0",            "GMT",      // system ID\r
285             "GMT-YOUR.AD.HERE", "0",            "GMT",\r
286             "GMT0",             "0",            "GMT0",     // system ID\r
287             "GMT+0",            "0",            "GMT+0",    // system ID\r
288             "GMT+1",            "3600",         "GMT+01:00",\r
289             "GMT-0030",         "-1800",        "GMT-00:30",\r
290             "GMT+15:99",        "0",            "GMT",\r
291             "GMT+",             "0",            "GMT",\r
292             "GMT-",             "0",            "GMT",\r
293             "GMT+0:",           "0",            "GMT",\r
294             "GMT-:",            "0",            "GMT",\r
295             "GMT+0010",         "600",          "GMT+00:10",\r
296             "GMT-10",           "-36000",       "GMT-10:00",\r
297             "GMT+30",           "0",            "GMT",\r
298             "GMT-3:30",         "-12600",       "GMT-03:30",\r
299             "GMT-230",          "-9000",        "GMT-02:30",\r
300             "GMT+05:13:05",     "18785",        "GMT+05:13:05",\r
301             "GMT-71023",        "-25823",       "GMT-07:10:23",\r
302             "GMT+01:23:45:67",  "0",            "GMT",\r
303             "GMT+01:234",       "0",            "GMT",\r
304             "GMT-2:31:123",     "0",            "GMT",\r
305             "GMT+3:75",         "0",            "GMT",\r
306             "GMT-01010101",     "0",            "GMT",\r
307         };\r
308         for (int i = 0; i < DATA.length; i += 3) {\r
309             String id = DATA[i];\r
310             int offset = Integer.parseInt(DATA[i+1]);\r
311             String expId = DATA[i+2];\r
312 \r
313             TimeZone zone = TimeZone.getTimeZone(id);\r
314             String gotID = zone.getID();\r
315             int gotOffset = zone.getRawOffset()/1000;\r
316 \r
317             logln(id + " -> " + gotID + " " + gotOffset);\r
318 \r
319             if (offset != gotOffset) {\r
320                 errln("FAIL: Unexpected offset for " + id + " - returned:" + gotOffset + " expected:" + offset);\r
321             }\r
322             if (!expId.equals(gotID)) {\r
323                 if (TimeZone.getDefaultTimeZoneType() != TimeZone.TIMEZONE_ICU) {\r
324                     logln("ID for " + id + " - returned:" + gotID + " expected:" + expId);\r
325                 } else {\r
326                     errln("FAIL: Unexpected ID for " + id + " - returned:" + gotID + " expected:" + expId);\r
327                 }\r
328             }\r
329         }\r
330     }\r
331 \r
332     /**\r
333      * Test the basic functionality of the getDisplayName() API.\r
334      *\r
335      * Bug 4112869\r
336      * Bug 4028006\r
337      *\r
338      * See also API change request A41.\r
339      *\r
340      * 4/21/98 - make smarter, so the test works if the ext resources\r
341      * are present or not.\r
342      */\r
343     public void TestDisplayName() {\r
344         TimeZone zone = TimeZone.getTimeZone("PST");\r
345         String name = zone.getDisplayName(Locale.ENGLISH);\r
346         logln("PST->" + name);\r
347 \r
348         // dlf - we now (3.4.1) return generic time\r
349         if (!name.equals("Pacific Time"))\r
350             errln("Fail: Expected \"Pacific Time\", got " + name +\r
351                   " for " + zone);\r
352 \r
353         //*****************************************************************\r
354         // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
355         // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
356         // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
357         //*****************************************************************\r
358 \r
359         // Test to allow the user to choose to get all the forms \r
360         // (z, zzzz, Z, ZZZZ, v, vvvv)\r
361         // todo: check to see whether we can test for all of pst, pdt, pt\r
362         Object[] DATA = {\r
363             // z and zzzz\r
364             Boolean.FALSE, new Integer(TimeZone.SHORT), "PST",\r
365             Boolean.TRUE,  new Integer(TimeZone.SHORT), "PDT",\r
366             Boolean.FALSE, new Integer(TimeZone.LONG),  "Pacific Standard Time",\r
367             Boolean.TRUE,  new Integer(TimeZone.LONG),  "Pacific Daylight Time",                \r
368             // v and vvvv\r
369             Boolean.FALSE, new Integer(TimeZone.SHORT_GENERIC), "PT",\r
370             Boolean.TRUE,  new Integer(TimeZone.SHORT_GENERIC), "PT",\r
371             Boolean.FALSE, new Integer(TimeZone.LONG_GENERIC),  "Pacific Time",\r
372             Boolean.TRUE,  new Integer(TimeZone.LONG_GENERIC),  "Pacific Time",  \r
373             // z and ZZZZ\r
374             Boolean.FALSE, new Integer(TimeZone.SHORT_GMT), "-0800",\r
375             Boolean.TRUE,  new Integer(TimeZone.SHORT_GMT), "-0700",\r
376             Boolean.FALSE, new Integer(TimeZone.LONG_GMT),  "GMT-08:00",\r
377             Boolean.TRUE,  new Integer(TimeZone.LONG_GMT),  "GMT-07:00",              \r
378             // V and VVVV\r
379             Boolean.FALSE, new Integer(TimeZone.SHORT_COMMONLY_USED), "PST",\r
380             Boolean.TRUE,  new Integer(TimeZone.SHORT_COMMONLY_USED), "PDT",\r
381             Boolean.FALSE, new Integer(TimeZone.GENERIC_LOCATION),  "United States (Los Angeles)",\r
382             Boolean.TRUE,  new Integer(TimeZone.GENERIC_LOCATION),  "United States (Los Angeles)",\r
383         };\r
384 \r
385         for (int i=0; i<DATA.length; i+=3) {\r
386             name = zone.getDisplayName(((Boolean)DATA[i]).booleanValue(),\r
387                                        ((Integer)DATA[i+1]).intValue(),\r
388                                        Locale.ENGLISH);\r
389             if (!name.equals(DATA[i+2]))\r
390                 errln("Fail: Expected " + DATA[i+2] + "; got " + name);\r
391         }\r
392 \r
393         // Make sure that we don't display the DST name by constructing a fake\r
394         // PST zone that has DST all year long.\r
395         // dlf - this test is no longer relevant, we display generic time now\r
396         //    so the behavior of the timezone doesn't matter\r
397         SimpleTimeZone zone2 = new SimpleTimeZone(0, "PST");\r
398         zone2.setStartRule(Calendar.JANUARY, 1, 0);\r
399         zone2.setEndRule(Calendar.DECEMBER, 31, 86399999);\r
400         logln("Modified PST inDaylightTime->" + zone2.inDaylightTime(new Date()));\r
401         name = zone2.getDisplayName(Locale.ENGLISH);\r
402         logln("Modified PST->" + name);\r
403         if (!name.equals("Pacific Time"))\r
404             errln("Fail: Expected \"Pacific Time\"");\r
405 \r
406         // Make sure we get the default display format for Locales\r
407         // with no display name data.\r
408         Locale mt_MT = new Locale("mt", "MT");\r
409         name = zone.getDisplayName(mt_MT);\r
410         //*****************************************************************\r
411         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
412         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
413         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
414         //*****************************************************************\r
415         logln("PST(mt_MT)->" + name);\r
416 \r
417         // Now be smart -- check to see if zh resource is even present.\r
418         // If not, we expect the en fallback behavior.\r
419 \r
420         // in icu4j 2.1 we know we have the zh_CN locale data, though it's incomplete\r
421 //    /"DateFormatZoneData", \r
422         UResourceBundle enRB = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,Locale.ENGLISH);\r
423         UResourceBundle mtRB = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, mt_MT);\r
424         boolean noZH = enRB == mtRB;\r
425 \r
426         if (noZH) {\r
427             logln("Warning: Not testing the mt_MT behavior because resource is absent");\r
428             if (!name.equals("Pacific Standard Time"))\r
429                 errln("Fail: Expected Pacific Standard Time for PST in mt_MT but got ");\r
430         }\r
431         // dlf - we will use generic time, or if unavailable, GMT for standard time in the zone \r
432         //     - we now (3.4.1) have localizations for this zone, so change test string\r
433         else if(!name.equals("Stati Uniti (Los Angeles)") &&\r
434             !name.equals("GMT-08:00") &&\r
435             !name.equals("GMT-8:00") &&\r
436             !name.equals("GMT-0800") &&\r
437             !name.equals("GMT-800")) {\r
438 \r
439             errln("Fail: got '" + name + "', expected GMT-08:00 or something similar\n" +\r
440                   "************************************************************\n" +\r
441                   "THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED\n" +\r
442                   "************************************************************");\r
443         }\r
444         \r
445         // Now try a non-existent zone\r
446         zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");\r
447         name = zone2.getDisplayName(Locale.ENGLISH);\r
448         logln("GMT+90min->" + name);\r
449         if (!name.equals("GMT+01:30") &&\r
450             !name.equals("GMT+1:30") &&\r
451             !name.equals("GMT+0130") &&\r
452             !name.equals("GMT+130"))\r
453             errln("Fail: Expected GMT+01:30 or something similar");\r
454         \r
455         // cover getDisplayName() - null arg\r
456         ULocale save = ULocale.getDefault();\r
457         ULocale.setDefault(ULocale.US);\r
458         name = zone2.getDisplayName();\r
459         logln("GMT+90min->" + name + "for default display locale");\r
460         if (!name.equals("GMT+01:30") &&\r
461             !name.equals("GMT+1:30") &&\r
462             !name.equals("GMT+0130") &&\r
463             !name.equals("GMT+130"))\r
464             errln("Fail: Expected GMT+01:30 or something similar");        \r
465         ULocale.setDefault(save);\r
466  \r
467     }\r
468 \r
469 \r
470     public void TestDisplayName2() {\r
471         Date now = new Date();\r
472 \r
473         String[] timezones = {"America/Chicago", "Europe/Moscow", "Europe/Rome", "Asia/Shanghai", "WET" };\r
474         String[] locales = {"en", "fr", "de", "ja", "zh_TW", "zh_Hans" };\r
475         for (int j = 0; j < locales.length; ++j) {\r
476             ULocale locale = new ULocale(locales[j]);\r
477             for (int i = 0; i < timezones.length; ++i) {\r
478                 TimeZone tz = TimeZone.getTimeZone(timezones[i]);\r
479                 String displayName0 = tz.getDisplayName(locale); // doesn't work???\r
480                 SimpleDateFormat dt = new SimpleDateFormat("vvvv", locale);\r
481                 dt.setTimeZone(tz);\r
482                 String displayName1 = dt.format(now);  // date value _does_ matter if we fallback to GMT\r
483                 logln(locale.getDisplayName() + ", " + tz.getID() + ": " + displayName0);\r
484                 if (!displayName1.equals(displayName0)) {\r
485                     errln(locale.getDisplayName() + ", " + tz.getID() + \r
486                           ": expected " + displayName1 + " but got: " + displayName0);\r
487                 }\r
488             }\r
489         }\r
490     }\r
491 \r
492     public void TestGenericAPI() {\r
493         String id = "NewGMT";\r
494         int offset = 12345;\r
495 \r
496         SimpleTimeZone zone = new SimpleTimeZone(offset, id);\r
497         if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");\r
498 \r
499         TimeZone zoneclone = (TimeZone)zone.clone();\r
500         if (!zoneclone.equals(zone)) errln("FAIL: clone or operator== failed");\r
501         zoneclone.setID("abc");\r
502         if (zoneclone.equals(zone)) errln("FAIL: clone or operator!= failed");\r
503         // delete zoneclone;\r
504 \r
505         zoneclone = (TimeZone)zone.clone();\r
506         if (!zoneclone.equals(zone)) errln("FAIL: clone or operator== failed");\r
507         zoneclone.setRawOffset(45678);\r
508         if (zoneclone.equals(zone)) errln("FAIL: clone or operator!= failed");\r
509 \r
510         // C++ only\r
511         /*\r
512           SimpleTimeZone copy(*zone);\r
513           if (!(copy == *zone)) errln("FAIL: copy constructor or operator== failed");\r
514           copy = *(SimpleTimeZone*)zoneclone;\r
515           if (!(copy == *zoneclone)) errln("FAIL: assignment operator or operator== failed");\r
516           */\r
517 \r
518         TimeZone saveDefault = TimeZone.getDefault();\r
519         TimeZone.setDefault(zone);\r
520         TimeZone defaultzone = TimeZone.getDefault();\r
521         if (defaultzone == zone) errln("FAIL: Default object is identical, not clone");\r
522         if (!defaultzone.equals(zone)) errln("FAIL: Default object is not equal");\r
523         TimeZone.setDefault(saveDefault);\r
524         // delete defaultzone;\r
525         // delete zoneclone;\r
526 \r
527 //      // ICU 2.6 Coverage\r
528 //      logln(zone.toString());\r
529 //      logln(zone.getDisplayName());\r
530 //      SimpleTimeZoneAdapter stza = new SimpleTimeZoneAdapter((SimpleTimeZone) TimeZone.getTimeZone("GMT"));\r
531 //      stza.setID("Foo");\r
532 //      if (stza.hasSameRules(java.util.TimeZone.getTimeZone("GMT"))) {\r
533 //          errln("FAIL: SimpleTimeZoneAdapter.hasSameRules");\r
534 //      }\r
535 //      stza.setRawOffset(3000);\r
536 //      offset = stza.getOffset(GregorianCalendar.BC, 2001, Calendar.DECEMBER,\r
537 //                              25, Calendar.TUESDAY, 12*60*60*1000);\r
538 //      if (offset != 3000) {\r
539 //          errln("FAIL: SimpleTimeZoneAdapter.getOffset");\r
540 //      }\r
541 //      SimpleTimeZoneAdapter dup = (SimpleTimeZoneAdapter) stza.clone();\r
542 //      if (stza.hashCode() != dup.hashCode()) {\r
543 //          errln("FAIL: SimpleTimeZoneAdapter.hashCode");\r
544 //      }\r
545 //      if (!stza.equals(dup)) {\r
546 //          errln("FAIL: SimpleTimeZoneAdapter.equals");\r
547 //      }\r
548 //      logln(stza.toString());\r
549 \r
550         String tzver = TimeZone.getTZDataVersion();\r
551         if (tzver.length() != 5 /* 4 digits + 1 letter */) {\r
552             errln("FAIL: getTZDataVersion returned " + tzver);\r
553         } else {\r
554             logln("PASS: tzdata version: " + tzver);\r
555         }\r
556     }\r
557 \r
558     public void TestRuleAPI()\r
559     {\r
560         // ErrorCode status = ZERO_ERROR;\r
561 \r
562         int offset = (int)(60*60*1000*1.75); // Pick a weird offset\r
563         SimpleTimeZone zone = new SimpleTimeZone(offset, "TestZone");\r
564         if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");\r
565 \r
566         // Establish our expected transition times.  Do this with a non-DST\r
567         // calendar with the (above) declared local offset.\r
568         GregorianCalendar gc = new GregorianCalendar(zone);\r
569         gc.clear();\r
570         gc.set(1990, Calendar.MARCH, 1);\r
571         long marchOneStd = gc.getTime().getTime(); // Local Std time midnight\r
572         gc.clear();\r
573         gc.set(1990, Calendar.JULY, 1);\r
574         long julyOneStd = gc.getTime().getTime(); // Local Std time midnight\r
575 \r
576         // Starting and ending hours, WALL TIME\r
577         int startHour = (int)(2.25 * 3600000);\r
578         int endHour   = (int)(3.5  * 3600000);\r
579 \r
580         zone.setStartRule(Calendar.MARCH, 1, 0, startHour);\r
581         zone.setEndRule  (Calendar.JULY,  1, 0, endHour);\r
582 \r
583         gc = new GregorianCalendar(zone);\r
584         // if (failure(status, "new GregorianCalendar")) return;\r
585 \r
586         long marchOne = marchOneStd + startHour;\r
587         long julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time\r
588 \r
589         long expMarchOne = 636251400000L;\r
590         if (marchOne != expMarchOne)\r
591         {\r
592             errln("FAIL: Expected start computed as " + marchOne +\r
593                   " = " + new Date(marchOne));\r
594             logln("      Should be                  " + expMarchOne +\r
595                   " = " + new Date(expMarchOne));\r
596         }\r
597 \r
598         long expJulyOne = 646793100000L;\r
599         if (julyOne != expJulyOne)\r
600         {\r
601             errln("FAIL: Expected start computed as " + julyOne +\r
602                   " = " + new Date(julyOne));\r
603             logln("      Should be                  " + expJulyOne +\r
604                   " = " + new Date(expJulyOne));\r
605         }\r
606 \r
607         Calendar cal1 = Calendar.getInstance();\r
608         cal1.set(1990, Calendar.JANUARY, 1);\r
609         Calendar cal2 = Calendar.getInstance();\r
610         cal2.set(1990, Calendar.JUNE, 1);\r
611         _testUsingBinarySearch(zone, cal1.getTimeInMillis(),\r
612                                cal2.getTimeInMillis(), marchOne);\r
613         cal1.set(1990, Calendar.JUNE, 1);\r
614         cal2.set(1990, Calendar.DECEMBER, 31);\r
615         _testUsingBinarySearch(zone, cal1.getTimeInMillis(),\r
616                                cal2.getTimeInMillis(), julyOne);\r
617 \r
618         if (zone.inDaylightTime(new Date(marchOne - 1000)) ||\r
619             !zone.inDaylightTime(new Date(marchOne)))\r
620             errln("FAIL: Start rule broken");\r
621         if (!zone.inDaylightTime(new Date(julyOne - 1000)) ||\r
622             zone.inDaylightTime(new Date(julyOne)))\r
623             errln("FAIL: End rule broken");\r
624 \r
625         zone.setStartYear(1991);\r
626         if (zone.inDaylightTime(new Date(marchOne)) ||\r
627             zone.inDaylightTime(new Date(julyOne - 1000)))\r
628             errln("FAIL: Start year broken");\r
629 \r
630         // failure(status, "TestRuleAPI");\r
631         // delete gc;\r
632         // delete zone;\r
633     }\r
634 \r
635     void _testUsingBinarySearch(SimpleTimeZone tz, long min, long max, long expectedBoundary)\r
636     {\r
637         // ErrorCode status = ZERO_ERROR;\r
638         boolean startsInDST = tz.inDaylightTime(new Date(min));\r
639         // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;\r
640         if (tz.inDaylightTime(new Date(max)) == startsInDST) {\r
641             logln("Error: inDaylightTime(" + new Date(max) + ") != " + (!startsInDST));\r
642             return;\r
643         }\r
644         // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;\r
645         while ((max - min) > INTERVAL) {\r
646             long mid = (min + max) / 2;\r
647             if (tz.inDaylightTime(new Date(mid)) == startsInDST) {\r
648                 min = mid;\r
649             }\r
650             else {\r
651                 max = mid;\r
652             }\r
653             // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;\r
654         }\r
655         logln("Binary Search Before: " + min + " = " + new Date(min));\r
656         logln("Binary Search After:  " + max + " = " + new Date(max));\r
657         long mindelta = expectedBoundary - min;\r
658         // not used long maxdelta = max - expectedBoundary;\r
659         if (mindelta >= 0 &&\r
660             mindelta <= INTERVAL &&\r
661             mindelta >= 0 &&\r
662             mindelta <= INTERVAL)\r
663             logln("PASS: Expected bdry:  " + expectedBoundary + " = " + new Date(expectedBoundary));\r
664         else\r
665             errln("FAIL: Expected bdry:  " + expectedBoundary + " = " + new Date(expectedBoundary));\r
666     }\r
667 \r
668     static final int INTERVAL = 100;\r
669 \r
670     // Bug 006; verify the offset for a specific zone.\r
671     public void TestPRTOffset()\r
672     {\r
673         TimeZone tz = TimeZone.getTimeZone( "PRT" );\r
674         if( tz == null ) {\r
675             errln( "FAIL: TimeZone(PRT) is null" );\r
676         }\r
677         else{\r
678             if (tz.getRawOffset() != (-4*millisPerHour))\r
679                 warnln("FAIL: Offset for PRT should be -4, got " +\r
680                       tz.getRawOffset() / (double)millisPerHour);\r
681         }\r
682 \r
683     }\r
684 \r
685     // Test various calls\r
686     public void TestVariousAPI518()\r
687     {\r
688         TimeZone time_zone = TimeZone.getTimeZone("PST");\r
689         Calendar cal = Calendar.getInstance();\r
690         cal.set(1997, Calendar.APRIL, 30);\r
691         Date d = cal.getTime();\r
692 \r
693         logln("The timezone is " + time_zone.getID());\r
694 \r
695         if (time_zone.inDaylightTime(d) != true)\r
696             errln("FAIL: inDaylightTime returned false");\r
697 \r
698         if (time_zone.useDaylightTime() != true)\r
699             errln("FAIL: useDaylightTime returned false");\r
700 \r
701         if (time_zone.getRawOffset() != -8*millisPerHour)\r
702             errln( "FAIL: getRawOffset returned wrong value");\r
703 \r
704         GregorianCalendar gc = new GregorianCalendar();\r
705         gc.setTime(d);\r
706         if (time_zone.getOffset(GregorianCalendar.AD, gc.get(GregorianCalendar.YEAR), gc.get(GregorianCalendar.MONTH),\r
707                                 gc.get(GregorianCalendar.DAY_OF_MONTH),\r
708                                 gc.get(GregorianCalendar.DAY_OF_WEEK), 0)\r
709             != -7*millisPerHour)\r
710             errln("FAIL: getOffset returned wrong value");\r
711     }\r
712 \r
713     // Test getAvailableID API\r
714     public void TestGetAvailableIDs913()\r
715     {\r
716         StringBuffer buf = new StringBuffer("TimeZone.getAvailableIDs() = { ");\r
717         String[] s = TimeZone.getAvailableIDs();\r
718         for (int i=0; i<s.length; ++i)\r
719         {\r
720             if (i > 0) buf.append(", ");\r
721             buf.append(s[i]);\r
722         }\r
723         buf.append(" };");\r
724         logln(buf.toString());\r
725 \r
726         buf.setLength(0);\r
727         buf.append("TimeZone.getAvailableIDs(GMT+02:00) = { ");\r
728         s = TimeZone.getAvailableIDs(+2 * 60 * 60 * 1000);\r
729         for (int i=0; i<s.length; ++i)\r
730         {\r
731             if (i > 0) buf.append(", ");\r
732             buf.append(s[i]);\r
733         }\r
734         buf.append(" };");\r
735         logln(buf.toString());\r
736 \r
737         TimeZone tz = TimeZone.getTimeZone("PST");\r
738         if (tz != null)\r
739             logln("getTimeZone(PST) = " + tz.getID());\r
740         else\r
741             errln("FAIL: getTimeZone(PST) = null");\r
742 \r
743         tz = TimeZone.getTimeZone("America/Los_Angeles");\r
744         if (tz != null)\r
745             logln("getTimeZone(America/Los_Angeles) = " + tz.getID());\r
746         else\r
747             errln("FAIL: getTimeZone(PST) = null");\r
748 \r
749         // Bug 4096694\r
750         tz = TimeZone.getTimeZone("NON_EXISTENT");\r
751         if (tz == null)\r
752             errln("FAIL: getTimeZone(NON_EXISTENT) = null");\r
753         else if (!tz.getID().equals("GMT"))\r
754             errln("FAIL: getTimeZone(NON_EXISTENT) = " + tz.getID());\r
755     }\r
756 \r
757     /**\r
758      * Bug 4107276\r
759      */\r
760     public void TestDSTSavings() {\r
761         // It might be better to find a way to integrate this test into the main TimeZone\r
762         // tests above, but I don't have time to figure out how to do this (or if it's\r
763         // even really a good idea).  Let's consider that a future.  --rtg 1/27/98\r
764         SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "dstSavingsTest",\r
765                                                Calendar.MARCH, 1, 0, 0, Calendar.SEPTEMBER, 1, 0, 0,\r
766                                                (int)(0.5 * millisPerHour));\r
767 \r
768         if (tz.getRawOffset() != -5 * millisPerHour)\r
769             errln("Got back a raw offset of " + (tz.getRawOffset() / millisPerHour) +\r
770                   " hours instead of -5 hours.");\r
771         if (!tz.useDaylightTime())\r
772             errln("Test time zone should use DST but claims it doesn't.");\r
773         if (tz.getDSTSavings() != 0.5 * millisPerHour)\r
774             errln("Set DST offset to 0.5 hour, but got back " + (tz.getDSTSavings() /\r
775                                                                  millisPerHour) + " hours instead.");\r
776 \r
777         int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,\r
778                                   Calendar.THURSDAY, 10 * millisPerHour);\r
779         if (offset != -5 * millisPerHour)\r
780             errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "\r
781                   + (offset / millisPerHour) + " hours.");\r
782 \r
783         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,\r
784                               10 * millisPerHour);\r
785         if (offset != -4.5 * millisPerHour)\r
786             errln("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got "\r
787                   + (offset / millisPerHour) + " hours.");\r
788 \r
789         tz.setDSTSavings(millisPerHour);\r
790         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,\r
791                               Calendar.THURSDAY, 10 * millisPerHour);\r
792         if (offset != -5 * millisPerHour)\r
793             errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "\r
794                   + (offset / millisPerHour) + " hours.");\r
795 \r
796         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,\r
797                               10 * millisPerHour);\r
798         if (offset != -4 * millisPerHour)\r
799             errln("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got "\r
800                   + (offset / millisPerHour) + " hours.");\r
801     }\r
802 \r
803     /**\r
804      * Bug 4107570\r
805      */\r
806     public void TestAlternateRules() {\r
807         // Like TestDSTSavings, this test should probably be integrated somehow with the main\r
808         // test at the top of this class, but I didn't have time to figure out how to do that.\r
809         //                      --rtg 1/28/98\r
810 \r
811         SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "alternateRuleTest");\r
812 \r
813         // test the day-of-month API\r
814         tz.setStartRule(Calendar.MARCH, 10, 12 * millisPerHour);\r
815         tz.setEndRule(Calendar.OCTOBER, 20, 12 * millisPerHour);\r
816 \r
817         int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 5,\r
818                                   Calendar.THURSDAY, 10 * millisPerHour);\r
819         if (offset != -5 * millisPerHour)\r
820             errln("The offset for 10AM, 3/5/98 should have been -5 hours, but we got "\r
821                   + (offset / millisPerHour) + " hours.");\r
822 \r
823         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 15,\r
824                               Calendar.SUNDAY, 10 * millisPerHour);\r
825         if (offset != -4 * millisPerHour)\r
826             errln("The offset for 10AM, 3/15/98 should have been -4 hours, but we got "\r
827                   + (offset / millisPerHour) + " hours.");\r
828 \r
829         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,\r
830                               Calendar.THURSDAY, 10 * millisPerHour);\r
831         if (offset != -4 * millisPerHour)\r
832             errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "\r
833                   + (offset / millisPerHour) + " hours.");\r
834 \r
835         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 25,\r
836                               Calendar.SUNDAY, 10 * millisPerHour);\r
837         if (offset != -5 * millisPerHour)\r
838             errln("The offset for 10AM, 10/25/98 should have been -5 hours, but we got "\r
839                   + (offset / millisPerHour) + " hours.");\r
840 \r
841         // test the day-of-week-after-day-in-month API\r
842         tz.setStartRule(Calendar.MARCH, 10, Calendar.FRIDAY, 12 * millisPerHour, true);\r
843         tz.setEndRule(Calendar.OCTOBER, 20, Calendar.FRIDAY, 12 * millisPerHour, false);\r
844 \r
845         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 11,\r
846                               Calendar.WEDNESDAY, 10 * millisPerHour);\r
847         if (offset != -5 * millisPerHour)\r
848             errln("The offset for 10AM, 3/11/98 should have been -5 hours, but we got "\r
849                   + (offset / millisPerHour) + " hours.");\r
850 \r
851         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 14,\r
852                               Calendar.SATURDAY, 10 * millisPerHour);\r
853         if (offset != -4 * millisPerHour)\r
854             errln("The offset for 10AM, 3/14/98 should have been -4 hours, but we got "\r
855                   + (offset / millisPerHour) + " hours.");\r
856 \r
857         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,\r
858                               Calendar.THURSDAY, 10 * millisPerHour);\r
859         if (offset != -4 * millisPerHour)\r
860             errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "\r
861                   + (offset / millisPerHour) + " hours.");\r
862 \r
863         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 17,\r
864                               Calendar.SATURDAY, 10 * millisPerHour);\r
865         if (offset != -5 * millisPerHour)\r
866             errln("The offset for 10AM, 10/17/98 should have been -5 hours, but we got "\r
867                   + (offset / millisPerHour) + " hours.");\r
868     }\r
869 \r
870     public void TestEquivalencyGroups() {\r
871         String id = "America/Los_Angeles";\r
872         int n = TimeZone.countEquivalentIDs(id);\r
873         if (n < 2) {\r
874             errln("FAIL: countEquivalentIDs(" + id + ") returned " + n +\r
875                   ", expected >= 2");\r
876         }\r
877         for (int i=0; i<n; ++i) {\r
878             String s = TimeZone.getEquivalentID(id, i);\r
879             if (s.length() == 0) {\r
880                 errln("FAIL: getEquivalentID(" + id + ", " + i +\r
881                       ") returned \"" + s + "\", expected valid ID");\r
882             } else {\r
883                 logln("" + i + ":" + s);\r
884             }\r
885         }\r
886 \r
887         // JB#5480 - equivalent IDs should not be empty within range\r
888         String[] ids = TimeZone.getAvailableIDs();\r
889         for (int i = 0; i < ids.length; i++) {\r
890             int nEquiv = TimeZone.countEquivalentIDs(ids[i]);\r
891             // Each equivalent ID must not be empty\r
892             for (int j = 0; j < nEquiv; j++) {\r
893                 String equivID = TimeZone.getEquivalentID(ids[i], j);\r
894                 if (equivID.length() == 0) {\r
895                     errln("FAIL: getEquivalentID(" + ids[i] + ", " + i +\r
896                             ") returned \"" + equivID + "\", expected valid ID");\r
897                 }\r
898             }\r
899             // equivalent ID out of range must be empty\r
900             String outOfRangeID = TimeZone.getEquivalentID(ids[i], nEquiv);\r
901             if (outOfRangeID.length() != 0) {\r
902                 errln("FAIL: getEquivalentID(" + ids[i] + ", " + i +\r
903                         ") returned \"" + outOfRangeID + "\", expected empty string");\r
904             }\r
905         }\r
906     }\r
907 \r
908     public void TestCountries() {\r
909         // Make sure America/Los_Angeles is in the "US" group, and\r
910         // Asia/Tokyo isn't.  Vice versa for the "JP" group.\r
911 \r
912         String[] s = TimeZone.getAvailableIDs("US");\r
913         boolean la = false, tokyo = false;\r
914         String laZone = "America/Los_Angeles", tokyoZone = "Asia/Tokyo";\r
915 \r
916         for (int i=0; i<s.length; ++i) {\r
917             if (s[i].equals(laZone)) {\r
918                 la = true;\r
919             }\r
920             if (s[i].equals(tokyoZone)) {\r
921                 tokyo = true;\r
922             }\r
923         }\r
924         if (!la ) {\r
925             errln("FAIL: " + laZone + " in US = " + la);\r
926         }\r
927         if (tokyo) {\r
928             errln("FAIL: " + tokyoZone + " in US = " + tokyo);\r
929         }\r
930         s = TimeZone.getAvailableIDs("JP");\r
931         la = false; tokyo = false;\r
932 \r
933         for (int i=0; i<s.length; ++i) {\r
934             if (s[i].equals(laZone)) {\r
935                 la = true;\r
936             }\r
937             if (s[i].equals(tokyoZone)) {\r
938                 tokyo = true;\r
939             }\r
940         }\r
941         if (la) {\r
942             errln("FAIL: " + laZone + " in JP = " + la);\r
943         }\r
944         if (!tokyo) {\r
945             errln("FAIL: " + tokyoZone + " in JP = " + tokyo);\r
946         }\r
947     }\r
948 \r
949     public void TestFractionalDST() {\r
950         String tzName = "Australia/Lord_Howe"; // 30 min offset\r
951         java.util.TimeZone tz_java = java.util.TimeZone.getTimeZone(tzName);\r
952         int dst_java = 0;\r
953         try {\r
954             // hack so test compiles and runs in both JDK 1.3 and JDK 1.4\r
955             final Object[] args = new Object[0];\r
956             final Class[] argtypes = new Class[0];\r
957             java.lang.reflect.Method m = tz_java.getClass().getMethod("getDSTSavings", argtypes); \r
958             dst_java = ((Integer) m.invoke(tz_java, args)).intValue();\r
959             if (dst_java <= 0 || dst_java >= 3600000) { // didn't get the fractional time zone we wanted\r
960             errln("didn't get fractional time zone!");\r
961             }\r
962         } catch (NoSuchMethodException e) {\r
963             // see JDKTimeZone for the reason for this code\r
964             dst_java = 3600000;\r
965         } catch (IllegalAccessException e) {\r
966             // see JDKTimeZone for the reason for this code\r
967             errln(e.getMessage());\r
968             dst_java = 3600000;\r
969         } catch (InvocationTargetException e) {\r
970             // see JDKTimeZone for the reason for this code\r
971             errln(e.getMessage());\r
972             dst_java = 3600000;\r
973         } catch (SecurityException e) {\r
974             warnln(e.getMessage());\r
975             return;\r
976         }\r
977         \r
978         com.ibm.icu.util.TimeZone tz_icu = com.ibm.icu.util.TimeZone.getTimeZone(tzName);\r
979         int dst_icu = tz_icu.getDSTSavings();\r
980 \r
981         if (dst_java != dst_icu) {\r
982             warnln("java reports dst savings of " + dst_java +\r
983               " but icu reports " + dst_icu + \r
984               " for tz " + tz_icu.getID());\r
985         } else {\r
986             logln("both java and icu report dst savings of " + dst_java + " for tz " + tz_icu.getID());\r
987         }\r
988     }\r
989 \r
990     public void TestGetOffsetDate() {\r
991         Calendar cal = Calendar.getInstance();\r
992         cal.set(1997, Calendar.JANUARY, 30);\r
993         long date = cal.getTimeInMillis();\r
994 \r
995     TimeZone tz_icu = TimeZone.getTimeZone("America/Los_Angeles");\r
996     int offset = tz_icu.getOffset(date);\r
997     if (offset != -28800000) {\r
998         errln("expected offset -28800000, got: " + offset);\r
999     }\r
1000 \r
1001     cal.set(1997, Calendar.JULY, 30);\r
1002     date = cal.getTimeInMillis();\r
1003     offset = tz_icu.getOffset(date);\r
1004     if (offset != -25200000) {\r
1005         errln("expected offset -25200000, got: " + offset);\r
1006     }\r
1007     }\r
1008 \r
1009     // jb4484\r
1010     public void TestSimpleTimeZoneSerialization() \r
1011     {\r
1012         SimpleTimeZone stz0 = new SimpleTimeZone(32400000, "MyTimeZone");\r
1013         SimpleTimeZone stz1 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1014         SimpleTimeZone stz2 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1015         stz2.setRawOffset(0);\r
1016         SimpleTimeZone stz3 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1017         stz3.setStartYear(100);\r
1018         SimpleTimeZone stz4 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1019         stz4.setStartYear(1000);\r
1020         stz4.setDSTSavings(1800000);\r
1021         stz4.setStartRule(3, 4, 180000);\r
1022         stz4.setEndRule(6, 3, 4, 360000);\r
1023         SimpleTimeZone stz5 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1024         stz5.setStartRule(2, 3, 4, 360000);\r
1025         stz5.setEndRule(6, 3, 4, 360000);\r
1026         \r
1027         SimpleTimeZone[] stzs = { stz0, stz1, stz2, stz3, stz4, stz5, };\r
1028 \r
1029         for (int i = 0; i < stzs.length; ++i) {\r
1030             SimpleTimeZone stz = stzs[i];\r
1031             try {\r
1032                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
1033                 ObjectOutputStream oos = new ObjectOutputStream(baos);\r
1034                 oos.writeObject(stz);\r
1035                 oos.close();\r
1036                 byte[] bytes = baos.toByteArray();\r
1037                 logln("id: " + stz.getID() + " length: " + bytes.length);\r
1038 \r
1039                 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
1040                 ObjectInputStream ois = new ObjectInputStream(bais);\r
1041 \r
1042                 SimpleTimeZone stzDeserialized = (SimpleTimeZone)ois.readObject();\r
1043                 ois.close();\r
1044 \r
1045                 assertEquals("time zones", stz, stzDeserialized);\r
1046             }\r
1047             catch (ClassCastException cce) {\r
1048                 cce.printStackTrace();\r
1049                 errln("could not deserialize SimpleTimeZone");\r
1050             }\r
1051             catch (IOException ioe) {\r
1052                 errln(ioe.getMessage());\r
1053             }\r
1054             catch (ClassNotFoundException cnfe) {\r
1055                 errln(cnfe.getMessage());\r
1056             }\r
1057         }\r
1058     }\r
1059 \r
1060     // jb4175\r
1061     /* Generated by org.unicode.cldr.tool.CountItems */\r
1062     private static final String[] timeZoneTestNames = {\r
1063         "America/Argentina/Buenos_Aires", "America/Buenos_Aires",\r
1064         "America/Argentina/Catamarca", "America/Catamarca",\r
1065         "America/Argentina/Cordoba", "America/Cordoba",\r
1066         "America/Argentina/Jujuy", "America/Jujuy",\r
1067         "America/Argentina/Mendoza", "America/Mendoza",\r
1068         "America/Atka", "America/Adak",\r
1069         "America/Ensenada", "America/Tijuana",\r
1070         "America/Fort_Wayne", "America/Indianapolis",\r
1071         "America/Indiana/Indianapolis", "America/Indianapolis",\r
1072         "America/Kentucky/Louisville", "America/Louisville",\r
1073         "America/Knox_IN", "America/Indiana/Knox",\r
1074         "America/Porto_Acre", "America/Rio_Branco",\r
1075         "America/Rosario", "America/Cordoba",\r
1076         "America/Virgin", "America/St_Thomas",\r
1077         "Asia/Ashkhabad", "Asia/Ashgabat",\r
1078         "Asia/Chungking", "Asia/Chongqing",\r
1079         "Asia/Dacca", "Asia/Dhaka",\r
1080         "Asia/Istanbul", "Europe/Istanbul",\r
1081         "Asia/Macao", "Asia/Macau",\r
1082         "Asia/Tel_Aviv", "Asia/Jerusalem",\r
1083         "Asia/Thimbu", "Asia/Thimphu",\r
1084         "Asia/Ujung_Pandang", "Asia/Makassar",\r
1085         "Asia/Ulan_Bator", "Asia/Ulaanbaatar",\r
1086         "Australia/ACT", "Australia/Sydney",\r
1087         "Australia/Canberra", "Australia/Sydney",\r
1088         "Australia/LHI", "Australia/Lord_Howe",\r
1089         "Australia/NSW", "Australia/Sydney",\r
1090         "Australia/North", "Australia/Darwin",\r
1091         "Australia/Queensland", "Australia/Brisbane",\r
1092         "Australia/South", "Australia/Adelaide",\r
1093         "Australia/Tasmania", "Australia/Hobart",\r
1094         "Australia/Victoria", "Australia/Melbourne",\r
1095         "Australia/West", "Australia/Perth",\r
1096         "Australia/Yancowinna", "Australia/Broken_Hill",\r
1097         "Brazil/Acre", "America/Rio_Branco",\r
1098         "Brazil/DeNoronha", "America/Noronha",\r
1099         "Brazil/East", "America/Sao_Paulo",\r
1100         "Brazil/West", "America/Manaus",\r
1101         "CST6CDT", "America/Chicago",\r
1102         "Canada/Atlantic", "America/Halifax",\r
1103         "Canada/Central", "America/Winnipeg",\r
1104         "Canada/East-Saskatchewan", "America/Regina",\r
1105         "Canada/Eastern", "America/Toronto",\r
1106         "Canada/Mountain", "America/Edmonton",\r
1107         "Canada/Newfoundland", "America/St_Johns",\r
1108         "Canada/Pacific", "America/Vancouver",\r
1109         "Canada/Saskatchewan", "America/Regina",\r
1110         "Canada/Yukon", "America/Whitehorse",\r
1111         "Chile/Continental", "America/Santiago",\r
1112         "Chile/EasterIsland", "Pacific/Easter",\r
1113         "Cuba", "America/Havana",\r
1114         "EST", "America/Indianapolis",\r
1115         "EST5EDT", "America/New_York",\r
1116         "Egypt", "Africa/Cairo",\r
1117         "Eire", "Europe/Dublin",\r
1118         "Etc/GMT+0", "Etc/GMT",\r
1119         "Etc/GMT-0", "Etc/GMT",\r
1120         "Etc/GMT0", "Etc/GMT",\r
1121         "Etc/Greenwich", "Etc/GMT",\r
1122         "Etc/UCT", "Etc/GMT",\r
1123         "Etc/UTC", "Etc/GMT",\r
1124         "Etc/Universal", "Etc/GMT",\r
1125         "Etc/Zulu", "Etc/GMT",\r
1126         "Europe/Nicosia", "Asia/Nicosia",\r
1127         "Europe/Tiraspol", "Europe/Chisinau",\r
1128         "GB", "Europe/London",\r
1129         "GB-Eire", "Europe/London",\r
1130         "GMT", "Etc/GMT",\r
1131         "GMT+0", "Etc/GMT",\r
1132         "GMT-0", "Etc/GMT",\r
1133         "GMT0", "Etc/GMT",\r
1134         "Greenwich", "Etc/GMT",\r
1135         "HST", "Pacific/Honolulu",\r
1136         "Hongkong", "Asia/Hong_Kong",\r
1137         "Iceland", "Atlantic/Reykjavik",\r
1138         "Iran", "Asia/Tehran",\r
1139         "Israel", "Asia/Jerusalem",\r
1140         "Jamaica", "America/Jamaica",\r
1141         "Japan", "Asia/Tokyo",\r
1142         "Kwajalein", "Pacific/Kwajalein",\r
1143         "Libya", "Africa/Tripoli",\r
1144         "MST", "America/Phoenix",\r
1145         "MST7MDT", "America/Denver",\r
1146         "Mexico/BajaNorte", "America/Tijuana",\r
1147         "Mexico/BajaSur", "America/Mazatlan",\r
1148         "Mexico/General", "America/Mexico_City",\r
1149         "NZ", "Pacific/Auckland",\r
1150         "NZ-CHAT", "Pacific/Chatham",\r
1151         "Navajo", "America/Shiprock", /* fixed from Mark's original */\r
1152         "PRC", "Asia/Shanghai",\r
1153         "PST8PDT", "America/Los_Angeles",\r
1154         "Pacific/Samoa", "Pacific/Pago_Pago",\r
1155         "Poland", "Europe/Warsaw",\r
1156         "Portugal", "Europe/Lisbon",\r
1157         "ROC", "Asia/Taipei",\r
1158         "ROK", "Asia/Seoul",\r
1159         "Singapore", "Asia/Singapore",\r
1160         "SystemV/AST4", "America/Puerto_Rico",\r
1161         "SystemV/AST4ADT", "America/Halifax",\r
1162         "SystemV/CST6", "America/Regina",\r
1163         "SystemV/CST6CDT", "America/Chicago",\r
1164         "SystemV/EST5", "America/Indianapolis",\r
1165         "SystemV/EST5EDT", "America/New_York",\r
1166         "SystemV/HST10", "Pacific/Honolulu",\r
1167         "SystemV/MST7", "America/Phoenix",\r
1168         "SystemV/MST7MDT", "America/Denver",\r
1169         "SystemV/PST8", "Pacific/Pitcairn",\r
1170         "SystemV/PST8PDT", "America/Los_Angeles",\r
1171         "SystemV/YST9", "Pacific/Gambier",\r
1172         "SystemV/YST9YDT", "America/Anchorage",\r
1173         "Turkey", "Europe/Istanbul",\r
1174         "UCT", "Etc/GMT",\r
1175         "US/Alaska", "America/Anchorage",\r
1176         "US/Aleutian", "America/Adak",\r
1177         "US/Arizona", "America/Phoenix",\r
1178         "US/Central", "America/Chicago",\r
1179         "US/East-Indiana", "America/Indianapolis",\r
1180         "US/Eastern", "America/New_York",\r
1181         "US/Hawaii", "Pacific/Honolulu",\r
1182         "US/Indiana-Starke", "America/Indiana/Knox",\r
1183         "US/Michigan", "America/Detroit",\r
1184         "US/Mountain", "America/Denver",\r
1185         "US/Pacific", "America/Los_Angeles",\r
1186         "US/Pacific-New", "America/Los_Angeles",\r
1187         "US/Samoa", "Pacific/Pago_Pago",\r
1188         "UTC", "Etc/GMT",\r
1189         "Universal", "Etc/GMT",\r
1190         "W-SU", "Europe/Moscow",\r
1191         "Zulu", "Etc/GMT",\r
1192     };\r
1193 \r
1194     public void TestOddTimeZoneNames() {\r
1195         for (int i = 0; i < timeZoneTestNames.length; i += 2) {\r
1196             String funkyName = timeZoneTestNames[i];\r
1197             String correctName = timeZoneTestNames[i+1];\r
1198 \r
1199             TimeZone ftz = TimeZone.getTimeZone(funkyName);\r
1200             TimeZone ctz = TimeZone.getTimeZone(correctName);\r
1201 \r
1202             String fdn = ftz.getDisplayName();\r
1203             long fro = ftz.getRawOffset();\r
1204             long fds = ftz.getDSTSavings();\r
1205             boolean fdy = ftz.useDaylightTime();\r
1206 \r
1207             String cdn = ctz.getDisplayName();\r
1208             long cro = ctz.getRawOffset();\r
1209             long cds = ctz.getDSTSavings();\r
1210             boolean cdy = ctz.useDaylightTime();\r
1211 \r
1212             if (!fdn.equals(cdn)) {\r
1213                 logln("display name (" + funkyName + ", " + correctName + ") expected: " + cdn + " but got: " + fdn);\r
1214             } else if (fro != cro) {\r
1215                 logln("offset (" + funkyName + ", " + correctName + ") expected: " + cro + " but got: " + fro);\r
1216             } else if (fds != cds) {\r
1217                 logln("daylight (" + funkyName + ", " + correctName + ") expected: " + cds + " but got: " + fds);\r
1218             } else if (fdy != cdy) {\r
1219                 logln("uses daylight (" + funkyName + ", " + correctName + ") expected: " + cdy + " but got: " + fdy);\r
1220             } else {\r
1221                 // no error, assume we're referencing the same internal java object\r
1222             }\r
1223         }\r
1224     }\r
1225     \r
1226     public void TestCoverage(){\r
1227         class StubTimeZone extends TimeZone{\r
1228             /**\r
1229              * For serialization\r
1230              */\r
1231             private static final long serialVersionUID = 8658654217433379343L;\r
1232             public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {return 0;}\r
1233             public void setRawOffset(int offsetMillis) {}\r
1234             public int getRawOffset() {return 0;}\r
1235             public boolean useDaylightTime() {return false;}\r
1236             public boolean inDaylightTime(Date date) {return false;}\r
1237         } \r
1238         StubTimeZone stub = new StubTimeZone();\r
1239         StubTimeZone stub2 = (StubTimeZone) stub.clone();\r
1240         if (stub.getDSTSavings() != 0){\r
1241             errln("TimeZone.getDSTSavings() should return 0");\r
1242         }\r
1243         if (!stub.hasSameRules(stub2)){\r
1244             errln("TimeZone.clone() object should hasSameRules");\r
1245      \r
1246         }\r
1247     }\r
1248     public void TestMark(){\r
1249         String tzid = "America/Argentina/ComodRivadavia";\r
1250         TimeZone tz = TimeZone.getTimeZone(tzid);\r
1251         int offset = tz.getOffset(new Date().getTime());\r
1252         logln(tzid + ":\t" + offset);\r
1253         List list = Arrays.asList(TimeZone.getAvailableIDs());\r
1254         if(!list.contains(tzid)){\r
1255             errln("Could create the time zone but it is not in getAvailableIDs");\r
1256         }\r
1257     }\r
1258     public void TestZoneMeta() {\r
1259         java.util.TimeZone save = java.util.TimeZone.getDefault();\r
1260         java.util.TimeZone newZone = java.util.TimeZone.getTimeZone("GMT-08:00");\r
1261         com.ibm.icu.util.TimeZone.setDefault(null);\r
1262         java.util.TimeZone.setDefault(newZone);\r
1263         SimpleTimeZone zone = new SimpleTimeZone(0, "GMT");\r
1264         com.ibm.icu.util.TimeZone defaultZone = com.ibm.icu.util.TimeZone.getDefault();\r
1265         if(defaultZone==null){\r
1266             errln("TimeZone.getDefault() failed for GMT-08:00");\r
1267         }\r
1268         if(zone==null){\r
1269             errln("SimpleTimeZone(0, GMT-08:00) failed for GMT-08:00");\r
1270         }\r
1271         //reset\r
1272         java.util.TimeZone.setDefault(save);\r
1273     }\r
1274 \r
1275     // Copied from the protected constant in TimeZone.\r
1276     private static final int MILLIS_PER_HOUR = 60*60*1000;\r
1277 \r
1278     //  Test that a transition at the end of February is handled correctly.\r
1279     public void TestFebruary() {\r
1280         // Time zone with daylight savings time from the first Sunday in November\r
1281         // to the last Sunday in February.\r
1282         // Similar to the new rule for Brazil (Sao Paulo) in tzdata2006n.\r
1283         //\r
1284         // Note: In tzdata2007h, the rule had changed, so no actual zones uses\r
1285         // lastSun in Feb anymore.\r
1286         SimpleTimeZone tz1 = new SimpleTimeZone(\r
1287                            -3 * MILLIS_PER_HOUR,                    // raw offset: 3h before (west of) GMT\r
1288                            "nov-feb",\r
1289                            Calendar.NOVEMBER, 1, Calendar.SUNDAY,   // start: November, first, Sunday\r
1290                            0,                                       //        midnight wall time\r
1291                            Calendar.FEBRUARY, -1, Calendar.SUNDAY,  // end:   February, last, Sunday\r
1292                            0);                                      //        midnight wall time\r
1293 \r
1294         // Now hardcode the same rules as for Brazil in tzdata 2006n, so that\r
1295         // we cover the intended code even when in the future zoneinfo hardcodes\r
1296         // these transition dates.\r
1297         SimpleTimeZone tz2= new SimpleTimeZone(\r
1298                            -3 * MILLIS_PER_HOUR,                    // raw offset: 3h before (west of) GMT\r
1299                            "nov-feb2",\r
1300                            Calendar.NOVEMBER, 1, -Calendar.SUNDAY,  // start: November, 1 or after, Sunday\r
1301                            0,                                       //        midnight wall time\r
1302                            Calendar.FEBRUARY, -29, -Calendar.SUNDAY,// end:   February, 29 or before, Sunday\r
1303                            0);                                      //        midnight wall time\r
1304 \r
1305         // Gregorian calendar with the UTC time zone for getting sample test date/times.\r
1306         GregorianCalendar gc = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));\r
1307         // "Unable to create the UTC calendar: %s"\r
1308 \r
1309         int[] data = {\r
1310             // UTC time (6 fields) followed by\r
1311             // expected time zone offset in hours after GMT (negative=before GMT).\r
1312             // int year, month, day, hour, minute, second, offsetHours\r
1313             2006, Calendar.NOVEMBER,  5, 02, 59, 59, -3,\r
1314             2006, Calendar.NOVEMBER,  5, 03, 00, 00, -2,\r
1315             2007, Calendar.FEBRUARY, 25, 01, 59, 59, -2,\r
1316             2007, Calendar.FEBRUARY, 25, 02, 00, 00, -3,\r
1317 \r
1318             2007, Calendar.NOVEMBER,  4, 02, 59, 59, -3,\r
1319             2007, Calendar.NOVEMBER,  4, 03, 00, 00, -2,\r
1320             2008, Calendar.FEBRUARY, 24, 01, 59, 59, -2,\r
1321             2008, Calendar.FEBRUARY, 24, 02, 00, 00, -3,\r
1322 \r
1323             2008, Calendar.NOVEMBER,  2, 02, 59, 59, -3,\r
1324             2008, Calendar.NOVEMBER,  2, 03, 00, 00, -2,\r
1325             2009, Calendar.FEBRUARY, 22, 01, 59, 59, -2,\r
1326             2009, Calendar.FEBRUARY, 22, 02, 00, 00, -3,\r
1327 \r
1328             2009, Calendar.NOVEMBER,  1, 02, 59, 59, -3,\r
1329             2009, Calendar.NOVEMBER,  1, 03, 00, 00, -2,\r
1330             2010, Calendar.FEBRUARY, 28, 01, 59, 59, -2,\r
1331             2010, Calendar.FEBRUARY, 28, 02, 00, 00, -3\r
1332         };\r
1333 \r
1334         TimeZone timezones[] = { tz1, tz2 };\r
1335 \r
1336         TimeZone tz;\r
1337         Date dt;\r
1338         int t, i, raw, dst;\r
1339         int[] offsets = new int[2]; // raw = offsets[0], dst = offsets[1]\r
1340         for (t = 0; t < timezones.length; ++t) {\r
1341             tz = timezones[t];\r
1342             for (i = 0; i < data.length; i+=7) {\r
1343                 gc.set(data[i], data[i+1], data[i+2],\r
1344                        data[i+3], data[i+4], data[i+5]);\r
1345                 dt = gc.getTime();\r
1346                 tz.getOffset(dt.getTime(), false, offsets);\r
1347                 raw = offsets[0];\r
1348                 dst = offsets[1];\r
1349                 if ((raw + dst) != data[i+6] * MILLIS_PER_HOUR) {\r
1350                     errln("test case " + t + "." + (i/7) + ": " +\r
1351                           "tz.getOffset(" + data[i] + "-" + (data[i+1] + 1) + "-" + data[i+2] + " " +\r
1352                           data[i+3] + ":" + data[i+4] + ":" + data[i+5] +\r
1353                           ") returns " + raw + "+" + dst + " != " + data[i+6] * MILLIS_PER_HOUR);\r
1354                 }\r
1355             }\r
1356         }\r
1357     }\r
1358 \r
1359     public void TestCanonicalID() {\r
1360         // Some canonical IDs in CLDR are defined as "Link"\r
1361         // in Olson tzdata.\r
1362         final String[][] excluded1 = {\r
1363                 {"America/Shiprock", "America/Denver"}, // America/Shiprock is defined as a Link to America/Denver in tzdata\r
1364                 {"America/Marigot", "America/Guadeloupe"},\r
1365                 {"America/St_Barthelemy", "America/Guadeloupe"},\r
1366                 {"Antarctica/South_Pole", "Antarctica/McMurdo"},\r
1367                 {"Atlantic/Jan_Mayen", "Europe/Oslo"},\r
1368                 {"Arctic/Longyearbyen", "Europe/Oslo"},\r
1369                 {"Europe/Guernsey", "Europe/London"},\r
1370                 {"Europe/Isle_of_Man", "Europe/London"},\r
1371                 {"Europe/Jersey", "Europe/London"},\r
1372                 {"Europe/Ljubljana", "Europe/Belgrade"},\r
1373                 {"Europe/Podgorica", "Europe/Belgrade"},\r
1374                 {"Europe/Sarajevo", "Europe/Belgrade"},\r
1375                 {"Europe/Skopje", "Europe/Belgrade"},\r
1376                 {"Europe/Zagreb", "Europe/Belgrade"},\r
1377                 {"Europe/Bratislava", "Europe/Prague"},\r
1378                 {"Europe/Mariehamn", "Europe/Helsinki"},\r
1379                 {"Europe/San_Marino", "Europe/Rome"},\r
1380                 {"Europe/Vatican", "Europe/Rome"},\r
1381         };\r
1382 \r
1383         // Following IDs are aliases of Etc/GMT in CLDR,\r
1384         // but Olson tzdata has 3 independent definitions\r
1385         // for Etc/GMT, Etc/UTC, Etc/UCT.\r
1386         // Until we merge them into one equivalent group\r
1387         // in zoneinfo.res, we exclude them in the test\r
1388         // below.\r
1389         final String[] excluded2 = {\r
1390                 "Etc/UCT", "UCT",\r
1391                 "Etc/UTC", "UTC",\r
1392                 "Etc/Universal", "Universal",\r
1393                 "Etc/Zulu", "Zulu",\r
1394         };\r
1395 \r
1396         // Walk through equivalency groups\r
1397         String[] ids = TimeZone.getAvailableIDs();\r
1398         for (int i = 0; i < ids.length; i++) {\r
1399             int nEquiv = TimeZone.countEquivalentIDs(ids[i]);\r
1400             if (nEquiv == 0) {\r
1401                 continue;\r
1402             }\r
1403             String canonicalID = null;\r
1404             boolean bFoundCanonical = false;\r
1405             // Make sure getCanonicalID returns the exact same result\r
1406             // for all entries within a same equivalency group with some\r
1407             // exceptions listed in exluded1.\r
1408             // Also, one of them must be canonical id.\r
1409             for (int j = 0; j < nEquiv; j++) {\r
1410                 String tmp = TimeZone.getEquivalentID(ids[i], j);\r
1411                 String tmpCanonical = TimeZone.getCanonicalID(tmp);\r
1412                 if (tmpCanonical == null) {\r
1413                     errln("FAIL: getCanonicalID(\"" + tmp + "\") returned null");\r
1414                     continue;\r
1415                 }\r
1416                 // Some exceptional cases\r
1417                 for (int k = 0; k < excluded1.length; k++) {\r
1418                     if (tmpCanonical.equals(excluded1[k][0])) {\r
1419                         tmpCanonical = excluded1[k][1];\r
1420                     }\r
1421                 }\r
1422 \r
1423                 if (j == 0) {\r
1424                     canonicalID = tmpCanonical;\r
1425                 } else if (!canonicalID.equals(tmpCanonical)) {\r
1426                     errln("FAIL: getCanonicalID(\"" + tmp + "\") returned " + tmpCanonical + " expected:" + canonicalID);\r
1427                 }\r
1428 \r
1429                 if (canonicalID.equals(tmp)) {\r
1430                     bFoundCanonical = true;\r
1431                 }\r
1432             }\r
1433             // At least one ID in an equvalency group must match the\r
1434             // canonicalID\r
1435             if (!bFoundCanonical) {\r
1436                 // test exclusion because of differences between Olson tzdata and CLDR\r
1437                 boolean isExcluded = false;\r
1438                 for (int k = 0; k < excluded1.length; k++) {\r
1439                     if (ids[i].equals(excluded2[k])) {\r
1440                         isExcluded = true;\r
1441                         break;\r
1442                     }\r
1443                 }\r
1444                 if (isExcluded) {\r
1445                     continue;\r
1446                 }\r
1447 \r
1448                 errln("FAIL: No timezone ids match the canonical ID " + canonicalID);\r
1449             }\r
1450         }\r
1451         // Testing some special cases\r
1452         final String[][] data = {\r
1453                 {"GMT-03", "GMT-03:00", null},\r
1454                 {"GMT+4", "GMT+04:00", null},\r
1455                 {"GMT-055", "GMT-00:55", null},\r
1456                 {"GMT+430", "GMT+04:30", null},\r
1457                 {"GMT-12:15", "GMT-12:15", null},\r
1458                 {"GMT-091015", "GMT-09:10:15", null},\r
1459                 {"GMT+1:90", null, null},\r
1460                 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires", "true"},\r
1461                 {"bogus", null, null},\r
1462                 {"", null, null},\r
1463                 {null, null, null},\r
1464         };\r
1465         boolean[] isSystemID = new boolean[1];\r
1466         for (int i = 0; i < data.length; i++) {\r
1467             String canonical = TimeZone.getCanonicalID(data[i][0], isSystemID);\r
1468             if (canonical != null && !canonical.equals(data[i][1])\r
1469                     || canonical == null && data[i][1] != null) {\r
1470                 errln("FAIL: getCanonicalID(\"" + data[i][0] + "\") returned " + canonical\r
1471                         + " - expected: " + data[i][1]);\r
1472             }\r
1473             if ("true".equalsIgnoreCase(data[i][2]) != isSystemID[0]) {\r
1474                 errln("FAIL: getCanonicalID(\"" + data[i][0] + "\") set " + isSystemID[0]\r
1475                         + " to isSystemID");\r
1476             }\r
1477         }\r
1478     }\r
1479 \r
1480     public void TestSetDefault() {\r
1481         java.util.TimeZone save = java.util.TimeZone.getDefault();\r
1482 \r
1483         /*\r
1484          * America/Caracs (Venezuela) changed the base offset from -4:00 to\r
1485          * -4:30 on Dec 9, 2007.\r
1486          */\r
1487 \r
1488         TimeZone icuCaracas = TimeZone.getTimeZone("America/Caracas", TimeZone.TIMEZONE_ICU);\r
1489         java.util.TimeZone jdkCaracas = java.util.TimeZone.getTimeZone("America/Caracas");\r
1490 \r
1491         // Set JDK America/Caracas as the default\r
1492         java.util.TimeZone.setDefault(jdkCaracas);\r
1493 \r
1494         java.util.Calendar jdkCal = java.util.Calendar.getInstance();\r
1495         jdkCal.clear();\r
1496         jdkCal.set(2007, java.util.Calendar.JANUARY, 1);\r
1497 \r
1498         int rawOffset = jdkCal.get(java.util.Calendar.ZONE_OFFSET);\r
1499         int dstSavings = jdkCal.get(java.util.Calendar.DST_OFFSET);\r
1500 \r
1501         int[] offsets = new int[2];\r
1502         icuCaracas.getOffset(jdkCal.getTime().getTime()/*jdkCal.getTimeInMillis()*/, false, offsets);\r
1503 \r
1504         boolean isTimeZoneSynchronized = true;\r
1505 \r
1506         if (rawOffset != offsets[0] || dstSavings != offsets[1]) {\r
1507             // JDK time zone rule is out of sync...\r
1508             logln("Rule for JDK America/Caracas is not same with ICU.  Skipping the rest.");\r
1509             isTimeZoneSynchronized = false;\r
1510         }\r
1511 \r
1512         if (isTimeZoneSynchronized) {\r
1513             // If JDK America/Caracas uses the same rule with ICU,\r
1514             // the following code should work well.\r
1515             TimeZone.setDefault(icuCaracas);\r
1516 \r
1517             // Create a new JDK calendar instance again.\r
1518             // This calendar should reflect the new default\r
1519             // set by ICU TimeZone#setDefault.\r
1520             jdkCal = java.util.Calendar.getInstance();\r
1521             jdkCal.clear();\r
1522             jdkCal.set(2007, java.util.Calendar.JANUARY, 1);\r
1523 \r
1524             rawOffset = jdkCal.get(java.util.Calendar.ZONE_OFFSET);\r
1525             dstSavings = jdkCal.get(java.util.Calendar.DST_OFFSET);\r
1526 \r
1527             if (rawOffset != offsets[0] || dstSavings != offsets[1]) {\r
1528                 errln("ERROR: Got offset [raw:" + rawOffset + "/dst:" + dstSavings\r
1529                           + "] Expected [raw:" + offsets[0] + "/dst:" + offsets[1] + "]");\r
1530             }\r
1531         }\r
1532 \r
1533         // Restore the original JDK time zone\r
1534         java.util.TimeZone.setDefault(save);\r
1535     }\r
1536 \r
1537     /*\r
1538      * Test Display Names, choosing zones and lcoales where there are multiple\r
1539      * meta-zones defined.\r
1540      */\r
1541     public void TestDisplayNamesMeta() {\r
1542         final Integer TZSHORT = new Integer(TimeZone.SHORT);\r
1543         final Integer TZLONG = new Integer(TimeZone.LONG);\r
1544 \r
1545         final Object[][] zoneDisplayTestData = {\r
1546             //  zone id             locale  summer          format      expected display name\r
1547             {"Europe/London",       "en",   Boolean.FALSE,  TZSHORT,    "GMT"},\r
1548             {"Europe/London",       "en",   Boolean.FALSE,  TZLONG,     "Greenwich Mean Time"},\r
1549             {"Europe/London",       "en",   Boolean.TRUE,   TZSHORT,    "GMT+01:00" /*"BST"*/},\r
1550             {"Europe/London",       "en",   Boolean.TRUE,   TZLONG,     "British Summer Time"},\r
1551 \r
1552             {"America/Anchorage",   "en",   Boolean.FALSE,  TZSHORT,    "AKST"},\r
1553             {"America/Anchorage",   "en",   Boolean.FALSE,  TZLONG,     "Alaska Standard Time"},\r
1554             {"America/Anchorage",   "en",   Boolean.TRUE,   TZSHORT,    "AKDT"},\r
1555             {"America/Anchorage",   "en",   Boolean.TRUE,   TZLONG,     "Alaska Daylight Time"},\r
1556 \r
1557             // Southern Hemisphere, all data from meta:Australia_Western\r
1558             {"Australia/Perth",     "en",   Boolean.FALSE,  TZSHORT,    "GMT+08:00"/*"AWST"*/},\r
1559             {"Australia/Perth",     "en",   Boolean.FALSE,  TZLONG,     "Australian Western Standard Time"},\r
1560             {"Australia/Perth",     "en",   Boolean.TRUE,   TZSHORT,    "GMT+09:00"/*"AWDT"*/},\r
1561             {"Australia/Perth",     "en",   Boolean.TRUE,   TZLONG,     "Australian Western Daylight Time"},\r
1562 \r
1563             {"America/Sao_Paulo",   "en",   Boolean.FALSE,  TZSHORT,    "GMT-03:00"/*"BRT"*/},\r
1564             {"America/Sao_Paulo",   "en",   Boolean.FALSE,  TZLONG,     "Brasilia Time"},\r
1565             {"America/Sao_Paulo",   "en",   Boolean.TRUE,   TZSHORT,    "GMT-02:00"/*"BRST"*/},\r
1566             {"America/Sao_Paulo",   "en",   Boolean.TRUE,   TZLONG,     "Brasilia Summer Time"},\r
1567 \r
1568             // No Summer Time, but had it before 1983.\r
1569             {"Pacific/Honolulu",    "en",   Boolean.FALSE,  TZSHORT,    "HST"},\r
1570             {"Pacific/Honolulu",    "en",   Boolean.FALSE,  TZLONG,     "Hawaii-Aleutian Standard Time"},\r
1571             {"Pacific/Honolulu",    "en",   Boolean.TRUE,   TZSHORT,    "HST"},\r
1572             {"Pacific/Honolulu",    "en",   Boolean.TRUE,   TZLONG,     "Hawaii-Aleutian Standard Time"},\r
1573 \r
1574             // Northern, has Summer, not commonly used.\r
1575             {"Europe/Helsinki",     "en",   Boolean.FALSE,  TZSHORT,    "GMT+02:00"/*"EET"*/},\r
1576             {"Europe/Helsinki",     "en",   Boolean.FALSE,  TZLONG,     "Eastern European Time"},\r
1577             {"Europe/Helsinki",     "en",   Boolean.TRUE,   TZSHORT,    "GMT+03:00"/*"EEST"*/},\r
1578             {"Europe/Helsinki",     "en",   Boolean.TRUE,   TZLONG,     "Eastern European Summer Time"},\r
1579 \r
1580             // Repeating the test data for DST.  The test data below trigger the problem reported\r
1581             // by Ticket#6644\r
1582             {"Europe/London",       "en",   Boolean.TRUE,   TZSHORT,    "GMT+01:00" /*"BST"*/},\r
1583             {"Europe/London",       "en",   Boolean.TRUE,   TZLONG,     "British Summer Time"},\r
1584         };\r
1585 \r
1586         boolean isReferenceYear = true;\r
1587         GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));\r
1588         if (cal.get(Calendar.YEAR) != REFERENCE_YEAR) {\r
1589             isReferenceYear = false;\r
1590         }\r
1591         boolean isICUTimeZone = (TimeZone.getDefaultTimeZoneType() == TimeZone.TIMEZONE_ICU);\r
1592 \r
1593         boolean sawAnError = false;\r
1594         for (int testNum = 0; testNum < zoneDisplayTestData.length; testNum++) {\r
1595             ULocale locale = new ULocale((String)zoneDisplayTestData[testNum][1]);\r
1596             TimeZone zone = TimeZone.getTimeZone((String)zoneDisplayTestData[testNum][0]);\r
1597             String displayName = zone.getDisplayName(((Boolean)zoneDisplayTestData[testNum][2]).booleanValue(),\r
1598                     ((Integer)zoneDisplayTestData[testNum][3]).intValue());\r
1599             if (!displayName.equals(zoneDisplayTestData[testNum][4])) {\r
1600                 if (isReferenceYear\r
1601                         && (isICUTimeZone || !((Boolean)zoneDisplayTestData[testNum][2]).booleanValue())) {\r
1602                     sawAnError = true;\r
1603                     errln("Incorrect time zone display name.  zone = "\r
1604                             + zoneDisplayTestData[testNum][0] + ",\n"\r
1605                             + "   locale = " + locale\r
1606                             + ",   style = " + (zoneDisplayTestData[testNum][3] == TZSHORT ? "SHORT" : "LONG")\r
1607                             + ",   Summertime = " + zoneDisplayTestData[testNum][2] + "\n"\r
1608                             + "   Expected " + zoneDisplayTestData[testNum][4]\r
1609                             + ",   Got " + displayName);\r
1610                 } else {\r
1611                     logln("Incorrect time zone display name.  zone = "\r
1612                             + zoneDisplayTestData[testNum][0] + ",\n"\r
1613                             + "   locale = " + locale\r
1614                             + ",   style = " + (zoneDisplayTestData[testNum][3] == TZSHORT ? "SHORT" : "LONG")\r
1615                             + ",   Summertime = " + zoneDisplayTestData[testNum][2] + "\n"\r
1616                             + "   Expected " + zoneDisplayTestData[testNum][4]\r
1617                             + ",   Got " + displayName);\r
1618                 }\r
1619             }\r
1620         }\r
1621         if (sawAnError) {\r
1622             logln("Note: Errors could be the result of changes to zoneStrings locale data");\r
1623         }\r
1624     }\r
1625 }\r
1626 \r
1627 //eof\r