]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/dev/test/timezone/TimeZoneTest.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / dev / test / timezone / TimeZoneTest.java
1 /**\r
2  *******************************************************************************\r
3  * Copyright (C) 2000-2009, 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         // todo: check to see whether we can test for all of pst, pdt, pt\r
360         Object[] DATA = {\r
361             Boolean.FALSE, new Integer(TimeZone.SHORT), "PST",\r
362             Boolean.TRUE,  new Integer(TimeZone.SHORT), "PDT",\r
363             Boolean.FALSE, new Integer(TimeZone.LONG),  "Pacific Standard Time",\r
364             Boolean.TRUE,  new Integer(TimeZone.LONG),  "Pacific Daylight Time",\r
365         };\r
366 \r
367         for (int i=0; i<DATA.length; i+=3) {\r
368             name = zone.getDisplayName(((Boolean)DATA[i]).booleanValue(),\r
369                                        ((Integer)DATA[i+1]).intValue(),\r
370                                        Locale.ENGLISH);\r
371             if (!name.equals(DATA[i+2]))\r
372                 errln("Fail: Expected " + DATA[i+2] + "; got " + name);\r
373         }\r
374 \r
375         // Make sure that we don't display the DST name by constructing a fake\r
376         // PST zone that has DST all year long.\r
377         // dlf - this test is no longer relevant, we display generic time now\r
378         //    so the behavior of the timezone doesn't matter\r
379         SimpleTimeZone zone2 = new SimpleTimeZone(0, "PST");\r
380         zone2.setStartRule(Calendar.JANUARY, 1, 0);\r
381         zone2.setEndRule(Calendar.DECEMBER, 31, 86399999);\r
382         logln("Modified PST inDaylightTime->" + zone2.inDaylightTime(new Date()));\r
383         name = zone2.getDisplayName(Locale.ENGLISH);\r
384         logln("Modified PST->" + name);\r
385         if (!name.equals("Pacific Time"))\r
386             errln("Fail: Expected \"Pacific Time\"");\r
387 \r
388         // Make sure we get the default display format for Locales\r
389         // with no display name data.\r
390         Locale mt_MT = new Locale("mt", "MT");\r
391         name = zone.getDisplayName(mt_MT);\r
392         //*****************************************************************\r
393         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
394         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
395         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES\r
396         //*****************************************************************\r
397         logln("PST(mt_MT)->" + name);\r
398 \r
399         // Now be smart -- check to see if zh resource is even present.\r
400         // If not, we expect the en fallback behavior.\r
401 \r
402         // in icu4j 2.1 we know we have the zh_CN locale data, though it's incomplete\r
403 //    /"DateFormatZoneData", \r
404         UResourceBundle enRB = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,Locale.ENGLISH);\r
405         UResourceBundle mtRB = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, mt_MT);\r
406         boolean noZH = enRB == mtRB;\r
407 \r
408         if (noZH) {\r
409             logln("Warning: Not testing the mt_MT behavior because resource is absent");\r
410             if (!name.equals("Pacific Standard Time"))\r
411                 errln("Fail: Expected Pacific Standard Time for PST in mt_MT but got ");\r
412         }\r
413         // dlf - we will use generic time, or if unavailable, GMT for standard time in the zone \r
414         //     - we now (3.4.1) have localizations for this zone, so change test string\r
415         else if(!name.equals("Stati Uniti (Los Angeles)") &&\r
416             !name.equals("GMT-08:00") &&\r
417             !name.equals("GMT-8:00") &&\r
418             !name.equals("GMT-0800") &&\r
419             !name.equals("GMT-800")) {\r
420 \r
421             errln("Fail: got '" + name + "', expected GMT-08:00 or something similar\n" +\r
422                   "************************************************************\n" +\r
423                   "THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED\n" +\r
424                   "************************************************************");\r
425         }\r
426         \r
427         // Now try a non-existent zone\r
428         zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");\r
429         name = zone2.getDisplayName(Locale.ENGLISH);\r
430         logln("GMT+90min->" + name);\r
431         if (!name.equals("GMT+01:30") &&\r
432             !name.equals("GMT+1:30") &&\r
433             !name.equals("GMT+0130") &&\r
434             !name.equals("GMT+130"))\r
435             errln("Fail: Expected GMT+01:30 or something similar");\r
436         \r
437         // cover getDisplayName() - null arg\r
438         ULocale save = ULocale.getDefault();\r
439         ULocale.setDefault(ULocale.US);\r
440         name = zone2.getDisplayName();\r
441         logln("GMT+90min->" + name + "for default display locale");\r
442         if (!name.equals("GMT+01:30") &&\r
443             !name.equals("GMT+1:30") &&\r
444             !name.equals("GMT+0130") &&\r
445             !name.equals("GMT+130"))\r
446             errln("Fail: Expected GMT+01:30 or something similar");        \r
447         ULocale.setDefault(save);\r
448     }\r
449 \r
450 \r
451     public void TestDisplayName2() {\r
452         Date now = new Date();\r
453 \r
454         String[] timezones = {"America/Chicago", "Europe/Moscow", "Europe/Rome", "Asia/Shanghai", "WET" };\r
455         String[] locales = {"en", "fr", "de", "ja", "zh_TW", "zh_Hans" };\r
456         for (int j = 0; j < locales.length; ++j) {\r
457             ULocale locale = new ULocale(locales[j]);\r
458             for (int i = 0; i < timezones.length; ++i) {\r
459                 TimeZone tz = TimeZone.getTimeZone(timezones[i]);\r
460                 String displayName0 = tz.getDisplayName(locale); // doesn't work???\r
461                 SimpleDateFormat dt = new SimpleDateFormat("vvvv", locale);\r
462                 dt.setTimeZone(tz);\r
463                 String displayName1 = dt.format(now);  // date value _does_ matter if we fallback to GMT\r
464                 logln(locale.getDisplayName() + ", " + tz.getID() + ": " + displayName0);\r
465                 if (!displayName1.equals(displayName0)) {\r
466                     errln(locale.getDisplayName() + ", " + tz.getID() + \r
467                           ": expected " + displayName1 + " but got: " + displayName0);\r
468                 }\r
469             }\r
470         }\r
471     }\r
472 \r
473     public void TestGenericAPI() {\r
474         String id = "NewGMT";\r
475         int offset = 12345;\r
476 \r
477         SimpleTimeZone zone = new SimpleTimeZone(offset, id);\r
478         if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");\r
479 \r
480         TimeZone zoneclone = (TimeZone)zone.clone();\r
481         if (!zoneclone.equals(zone)) errln("FAIL: clone or operator== failed");\r
482         zoneclone.setID("abc");\r
483         if (zoneclone.equals(zone)) errln("FAIL: clone or operator!= failed");\r
484         // delete zoneclone;\r
485 \r
486         zoneclone = (TimeZone)zone.clone();\r
487         if (!zoneclone.equals(zone)) errln("FAIL: clone or operator== failed");\r
488         zoneclone.setRawOffset(45678);\r
489         if (zoneclone.equals(zone)) errln("FAIL: clone or operator!= failed");\r
490 \r
491         // C++ only\r
492         /*\r
493           SimpleTimeZone copy(*zone);\r
494           if (!(copy == *zone)) errln("FAIL: copy constructor or operator== failed");\r
495           copy = *(SimpleTimeZone*)zoneclone;\r
496           if (!(copy == *zoneclone)) errln("FAIL: assignment operator or operator== failed");\r
497           */\r
498 \r
499         TimeZone saveDefault = TimeZone.getDefault();\r
500         TimeZone.setDefault(zone);\r
501         TimeZone defaultzone = TimeZone.getDefault();\r
502         if (defaultzone == zone) errln("FAIL: Default object is identical, not clone");\r
503         if (!defaultzone.equals(zone)) errln("FAIL: Default object is not equal");\r
504         TimeZone.setDefault(saveDefault);\r
505         // delete defaultzone;\r
506         // delete zoneclone;\r
507 \r
508 //      // ICU 2.6 Coverage\r
509 //      logln(zone.toString());\r
510 //      logln(zone.getDisplayName());\r
511 //      SimpleTimeZoneAdapter stza = new SimpleTimeZoneAdapter((SimpleTimeZone) TimeZone.getTimeZone("GMT"));\r
512 //      stza.setID("Foo");\r
513 //      if (stza.hasSameRules(java.util.TimeZone.getTimeZone("GMT"))) {\r
514 //          errln("FAIL: SimpleTimeZoneAdapter.hasSameRules");\r
515 //      }\r
516 //      stza.setRawOffset(3000);\r
517 //      offset = stza.getOffset(GregorianCalendar.BC, 2001, Calendar.DECEMBER,\r
518 //                              25, Calendar.TUESDAY, 12*60*60*1000);\r
519 //      if (offset != 3000) {\r
520 //          errln("FAIL: SimpleTimeZoneAdapter.getOffset");\r
521 //      }\r
522 //      SimpleTimeZoneAdapter dup = (SimpleTimeZoneAdapter) stza.clone();\r
523 //      if (stza.hashCode() != dup.hashCode()) {\r
524 //          errln("FAIL: SimpleTimeZoneAdapter.hashCode");\r
525 //      }\r
526 //      if (!stza.equals(dup)) {\r
527 //          errln("FAIL: SimpleTimeZoneAdapter.equals");\r
528 //      }\r
529 //      logln(stza.toString());\r
530 \r
531         String tzver = TimeZone.getTZDataVersion();\r
532         if (tzver.length() != 5 /* 4 digits + 1 letter */) {\r
533             errln("FAIL: getTZDataVersion returned " + tzver);\r
534         } else {\r
535             logln("PASS: tzdata version: " + tzver);\r
536         }\r
537     }\r
538 \r
539     public void TestRuleAPI()\r
540     {\r
541         // ErrorCode status = ZERO_ERROR;\r
542 \r
543         int offset = (int)(60*60*1000*1.75); // Pick a weird offset\r
544         SimpleTimeZone zone = new SimpleTimeZone(offset, "TestZone");\r
545         if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");\r
546 \r
547         // Establish our expected transition times.  Do this with a non-DST\r
548         // calendar with the (above) declared local offset.\r
549         GregorianCalendar gc = new GregorianCalendar(zone);\r
550         gc.clear();\r
551         gc.set(1990, Calendar.MARCH, 1);\r
552         long marchOneStd = gc.getTime().getTime(); // Local Std time midnight\r
553         gc.clear();\r
554         gc.set(1990, Calendar.JULY, 1);\r
555         long julyOneStd = gc.getTime().getTime(); // Local Std time midnight\r
556 \r
557         // Starting and ending hours, WALL TIME\r
558         int startHour = (int)(2.25 * 3600000);\r
559         int endHour   = (int)(3.5  * 3600000);\r
560 \r
561         zone.setStartRule(Calendar.MARCH, 1, 0, startHour);\r
562         zone.setEndRule  (Calendar.JULY,  1, 0, endHour);\r
563 \r
564         gc = new GregorianCalendar(zone);\r
565         // if (failure(status, "new GregorianCalendar")) return;\r
566 \r
567         long marchOne = marchOneStd + startHour;\r
568         long julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time\r
569 \r
570         long expMarchOne = 636251400000L;\r
571         if (marchOne != expMarchOne)\r
572         {\r
573             errln("FAIL: Expected start computed as " + marchOne +\r
574                   " = " + new Date(marchOne));\r
575             logln("      Should be                  " + expMarchOne +\r
576                   " = " + new Date(expMarchOne));\r
577         }\r
578 \r
579         long expJulyOne = 646793100000L;\r
580         if (julyOne != expJulyOne)\r
581         {\r
582             errln("FAIL: Expected start computed as " + julyOne +\r
583                   " = " + new Date(julyOne));\r
584             logln("      Should be                  " + expJulyOne +\r
585                   " = " + new Date(expJulyOne));\r
586         }\r
587 \r
588         Calendar cal1 = Calendar.getInstance();\r
589         cal1.set(1990, Calendar.JANUARY, 1);\r
590         Calendar cal2 = Calendar.getInstance();\r
591         cal2.set(1990, Calendar.JUNE, 1);\r
592         _testUsingBinarySearch(zone, cal1.getTimeInMillis(),\r
593                                cal2.getTimeInMillis(), marchOne);\r
594         cal1.set(1990, Calendar.JUNE, 1);\r
595         cal2.set(1990, Calendar.DECEMBER, 31);\r
596         _testUsingBinarySearch(zone, cal1.getTimeInMillis(),\r
597                                cal2.getTimeInMillis(), julyOne);\r
598 \r
599         if (zone.inDaylightTime(new Date(marchOne - 1000)) ||\r
600             !zone.inDaylightTime(new Date(marchOne)))\r
601             errln("FAIL: Start rule broken");\r
602         if (!zone.inDaylightTime(new Date(julyOne - 1000)) ||\r
603             zone.inDaylightTime(new Date(julyOne)))\r
604             errln("FAIL: End rule broken");\r
605 \r
606         zone.setStartYear(1991);\r
607         if (zone.inDaylightTime(new Date(marchOne)) ||\r
608             zone.inDaylightTime(new Date(julyOne - 1000)))\r
609             errln("FAIL: Start year broken");\r
610 \r
611         // failure(status, "TestRuleAPI");\r
612         // delete gc;\r
613         // delete zone;\r
614     }\r
615 \r
616     void _testUsingBinarySearch(SimpleTimeZone tz, long min, long max, long expectedBoundary)\r
617     {\r
618         // ErrorCode status = ZERO_ERROR;\r
619         boolean startsInDST = tz.inDaylightTime(new Date(min));\r
620         // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;\r
621         if (tz.inDaylightTime(new Date(max)) == startsInDST) {\r
622             logln("Error: inDaylightTime(" + new Date(max) + ") != " + (!startsInDST));\r
623             return;\r
624         }\r
625         // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;\r
626         while ((max - min) > INTERVAL) {\r
627             long mid = (min + max) / 2;\r
628             if (tz.inDaylightTime(new Date(mid)) == startsInDST) {\r
629                 min = mid;\r
630             }\r
631             else {\r
632                 max = mid;\r
633             }\r
634             // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;\r
635         }\r
636         logln("Binary Search Before: " + min + " = " + new Date(min));\r
637         logln("Binary Search After:  " + max + " = " + new Date(max));\r
638         long mindelta = expectedBoundary - min;\r
639         // not used long maxdelta = max - expectedBoundary;\r
640         if (mindelta >= 0 &&\r
641             mindelta <= INTERVAL &&\r
642             mindelta >= 0 &&\r
643             mindelta <= INTERVAL)\r
644             logln("PASS: Expected bdry:  " + expectedBoundary + " = " + new Date(expectedBoundary));\r
645         else\r
646             errln("FAIL: Expected bdry:  " + expectedBoundary + " = " + new Date(expectedBoundary));\r
647     }\r
648 \r
649     static final int INTERVAL = 100;\r
650 \r
651     // Bug 006; verify the offset for a specific zone.\r
652     public void TestPRTOffset()\r
653     {\r
654         TimeZone tz = TimeZone.getTimeZone( "PRT" );\r
655         if( tz == null ) {\r
656             errln( "FAIL: TimeZone(PRT) is null" );\r
657         }\r
658         else{\r
659             if (tz.getRawOffset() != (-4*millisPerHour))\r
660                 warnln("FAIL: Offset for PRT should be -4, got " +\r
661                       tz.getRawOffset() / (double)millisPerHour);\r
662         }\r
663 \r
664     }\r
665 \r
666     // Test various calls\r
667     public void TestVariousAPI518()\r
668     {\r
669         TimeZone time_zone = TimeZone.getTimeZone("PST");\r
670         Calendar cal = Calendar.getInstance();\r
671         cal.set(1997, Calendar.APRIL, 30);\r
672         Date d = cal.getTime();\r
673 \r
674         logln("The timezone is " + time_zone.getID());\r
675 \r
676         if (time_zone.inDaylightTime(d) != true)\r
677             errln("FAIL: inDaylightTime returned false");\r
678 \r
679         if (time_zone.useDaylightTime() != true)\r
680             errln("FAIL: useDaylightTime returned false");\r
681 \r
682         if (time_zone.getRawOffset() != -8*millisPerHour)\r
683             errln( "FAIL: getRawOffset returned wrong value");\r
684 \r
685         GregorianCalendar gc = new GregorianCalendar();\r
686         gc.setTime(d);\r
687         if (time_zone.getOffset(GregorianCalendar.AD, gc.get(GregorianCalendar.YEAR), gc.get(GregorianCalendar.MONTH),\r
688                                 gc.get(GregorianCalendar.DAY_OF_MONTH),\r
689                                 gc.get(GregorianCalendar.DAY_OF_WEEK), 0)\r
690             != -7*millisPerHour)\r
691             errln("FAIL: getOffset returned wrong value");\r
692     }\r
693 \r
694     // Test getAvailableID API\r
695     public void TestGetAvailableIDs913()\r
696     {\r
697         StringBuffer buf = new StringBuffer("TimeZone.getAvailableIDs() = { ");\r
698         String[] s = TimeZone.getAvailableIDs();\r
699         for (int i=0; i<s.length; ++i)\r
700         {\r
701             if (i > 0) buf.append(", ");\r
702             buf.append(s[i]);\r
703         }\r
704         buf.append(" };");\r
705         logln(buf.toString());\r
706 \r
707         buf.setLength(0);\r
708         buf.append("TimeZone.getAvailableIDs(GMT+02:00) = { ");\r
709         s = TimeZone.getAvailableIDs(+2 * 60 * 60 * 1000);\r
710         for (int i=0; i<s.length; ++i)\r
711         {\r
712             if (i > 0) buf.append(", ");\r
713             buf.append(s[i]);\r
714         }\r
715         buf.append(" };");\r
716         logln(buf.toString());\r
717 \r
718         TimeZone tz = TimeZone.getTimeZone("PST");\r
719         if (tz != null)\r
720             logln("getTimeZone(PST) = " + tz.getID());\r
721         else\r
722             errln("FAIL: getTimeZone(PST) = null");\r
723 \r
724         tz = TimeZone.getTimeZone("America/Los_Angeles");\r
725         if (tz != null)\r
726             logln("getTimeZone(America/Los_Angeles) = " + tz.getID());\r
727         else\r
728             errln("FAIL: getTimeZone(PST) = null");\r
729 \r
730         // Bug 4096694\r
731         tz = TimeZone.getTimeZone("NON_EXISTENT");\r
732         if (tz == null)\r
733             errln("FAIL: getTimeZone(NON_EXISTENT) = null");\r
734         else if (!tz.getID().equals("GMT"))\r
735             errln("FAIL: getTimeZone(NON_EXISTENT) = " + tz.getID());\r
736     }\r
737 \r
738     /**\r
739      * Bug 4107276\r
740      */\r
741     public void TestDSTSavings() {\r
742         // It might be better to find a way to integrate this test into the main TimeZone\r
743         // tests above, but I don't have time to figure out how to do this (or if it's\r
744         // even really a good idea).  Let's consider that a future.  --rtg 1/27/98\r
745         SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "dstSavingsTest",\r
746                                                Calendar.MARCH, 1, 0, 0, Calendar.SEPTEMBER, 1, 0, 0,\r
747                                                (int)(0.5 * millisPerHour));\r
748 \r
749         if (tz.getRawOffset() != -5 * millisPerHour)\r
750             errln("Got back a raw offset of " + (tz.getRawOffset() / millisPerHour) +\r
751                   " hours instead of -5 hours.");\r
752         if (!tz.useDaylightTime())\r
753             errln("Test time zone should use DST but claims it doesn't.");\r
754         if (tz.getDSTSavings() != 0.5 * millisPerHour)\r
755             errln("Set DST offset to 0.5 hour, but got back " + (tz.getDSTSavings() /\r
756                                                                  millisPerHour) + " hours instead.");\r
757 \r
758         int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,\r
759                                   Calendar.THURSDAY, 10 * millisPerHour);\r
760         if (offset != -5 * millisPerHour)\r
761             errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "\r
762                   + (offset / millisPerHour) + " hours.");\r
763 \r
764         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,\r
765                               10 * millisPerHour);\r
766         if (offset != -4.5 * millisPerHour)\r
767             errln("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got "\r
768                   + (offset / millisPerHour) + " hours.");\r
769 \r
770         tz.setDSTSavings(millisPerHour);\r
771         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,\r
772                               Calendar.THURSDAY, 10 * millisPerHour);\r
773         if (offset != -5 * millisPerHour)\r
774             errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "\r
775                   + (offset / millisPerHour) + " hours.");\r
776 \r
777         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,\r
778                               10 * millisPerHour);\r
779         if (offset != -4 * millisPerHour)\r
780             errln("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got "\r
781                   + (offset / millisPerHour) + " hours.");\r
782     }\r
783 \r
784     /**\r
785      * Bug 4107570\r
786      */\r
787     public void TestAlternateRules() {\r
788         // Like TestDSTSavings, this test should probably be integrated somehow with the main\r
789         // test at the top of this class, but I didn't have time to figure out how to do that.\r
790         //                      --rtg 1/28/98\r
791 \r
792         SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "alternateRuleTest");\r
793 \r
794         // test the day-of-month API\r
795         tz.setStartRule(Calendar.MARCH, 10, 12 * millisPerHour);\r
796         tz.setEndRule(Calendar.OCTOBER, 20, 12 * millisPerHour);\r
797 \r
798         int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 5,\r
799                                   Calendar.THURSDAY, 10 * millisPerHour);\r
800         if (offset != -5 * millisPerHour)\r
801             errln("The offset for 10AM, 3/5/98 should have been -5 hours, but we got "\r
802                   + (offset / millisPerHour) + " hours.");\r
803 \r
804         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 15,\r
805                               Calendar.SUNDAY, 10 * millisPerHour);\r
806         if (offset != -4 * millisPerHour)\r
807             errln("The offset for 10AM, 3/15/98 should have been -4 hours, but we got "\r
808                   + (offset / millisPerHour) + " hours.");\r
809 \r
810         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,\r
811                               Calendar.THURSDAY, 10 * millisPerHour);\r
812         if (offset != -4 * millisPerHour)\r
813             errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "\r
814                   + (offset / millisPerHour) + " hours.");\r
815 \r
816         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 25,\r
817                               Calendar.SUNDAY, 10 * millisPerHour);\r
818         if (offset != -5 * millisPerHour)\r
819             errln("The offset for 10AM, 10/25/98 should have been -5 hours, but we got "\r
820                   + (offset / millisPerHour) + " hours.");\r
821 \r
822         // test the day-of-week-after-day-in-month API\r
823         tz.setStartRule(Calendar.MARCH, 10, Calendar.FRIDAY, 12 * millisPerHour, true);\r
824         tz.setEndRule(Calendar.OCTOBER, 20, Calendar.FRIDAY, 12 * millisPerHour, false);\r
825 \r
826         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 11,\r
827                               Calendar.WEDNESDAY, 10 * millisPerHour);\r
828         if (offset != -5 * millisPerHour)\r
829             errln("The offset for 10AM, 3/11/98 should have been -5 hours, but we got "\r
830                   + (offset / millisPerHour) + " hours.");\r
831 \r
832         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 14,\r
833                               Calendar.SATURDAY, 10 * millisPerHour);\r
834         if (offset != -4 * millisPerHour)\r
835             errln("The offset for 10AM, 3/14/98 should have been -4 hours, but we got "\r
836                   + (offset / millisPerHour) + " hours.");\r
837 \r
838         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,\r
839                               Calendar.THURSDAY, 10 * millisPerHour);\r
840         if (offset != -4 * millisPerHour)\r
841             errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "\r
842                   + (offset / millisPerHour) + " hours.");\r
843 \r
844         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 17,\r
845                               Calendar.SATURDAY, 10 * millisPerHour);\r
846         if (offset != -5 * millisPerHour)\r
847             errln("The offset for 10AM, 10/17/98 should have been -5 hours, but we got "\r
848                   + (offset / millisPerHour) + " hours.");\r
849     }\r
850 \r
851     public void TestEquivalencyGroups() {\r
852         String id = "America/Los_Angeles";\r
853         int n = TimeZone.countEquivalentIDs(id);\r
854         if (n < 2) {\r
855             errln("FAIL: countEquivalentIDs(" + id + ") returned " + n +\r
856                   ", expected >= 2");\r
857         }\r
858         for (int i=0; i<n; ++i) {\r
859             String s = TimeZone.getEquivalentID(id, i);\r
860             if (s.length() == 0) {\r
861                 errln("FAIL: getEquivalentID(" + id + ", " + i +\r
862                       ") returned \"" + s + "\", expected valid ID");\r
863             } else {\r
864                 logln("" + i + ":" + s);\r
865             }\r
866         }\r
867 \r
868         // JB#5480 - equivalent IDs should not be empty within range\r
869         String[] ids = TimeZone.getAvailableIDs();\r
870         for (int i = 0; i < ids.length; i++) {\r
871             int nEquiv = TimeZone.countEquivalentIDs(ids[i]);\r
872             // Each equivalent ID must not be empty\r
873             for (int j = 0; j < nEquiv; j++) {\r
874                 String equivID = TimeZone.getEquivalentID(ids[i], j);\r
875                 if (equivID.length() == 0) {\r
876                     errln("FAIL: getEquivalentID(" + ids[i] + ", " + i +\r
877                             ") returned \"" + equivID + "\", expected valid ID");\r
878                 }\r
879             }\r
880             // equivalent ID out of range must be empty\r
881             String outOfRangeID = TimeZone.getEquivalentID(ids[i], nEquiv);\r
882             if (outOfRangeID.length() != 0) {\r
883                 errln("FAIL: getEquivalentID(" + ids[i] + ", " + i +\r
884                         ") returned \"" + outOfRangeID + "\", expected empty string");\r
885             }\r
886         }\r
887     }\r
888 \r
889     public void TestCountries() {\r
890         // Make sure America/Los_Angeles is in the "US" group, and\r
891         // Asia/Tokyo isn't.  Vice versa for the "JP" group.\r
892 \r
893         String[] s = TimeZone.getAvailableIDs("US");\r
894         boolean la = false, tokyo = false;\r
895         String laZone = "America/Los_Angeles", tokyoZone = "Asia/Tokyo";\r
896 \r
897         for (int i=0; i<s.length; ++i) {\r
898             if (s[i].equals(laZone)) {\r
899                 la = true;\r
900             }\r
901             if (s[i].equals(tokyoZone)) {\r
902                 tokyo = true;\r
903             }\r
904         }\r
905         if (!la ) {\r
906             errln("FAIL: " + laZone + " in US = " + la);\r
907         }\r
908         if (tokyo) {\r
909             errln("FAIL: " + tokyoZone + " in US = " + tokyo);\r
910         }\r
911         s = TimeZone.getAvailableIDs("JP");\r
912         la = false; tokyo = false;\r
913 \r
914         for (int i=0; i<s.length; ++i) {\r
915             if (s[i].equals(laZone)) {\r
916                 la = true;\r
917             }\r
918             if (s[i].equals(tokyoZone)) {\r
919                 tokyo = true;\r
920             }\r
921         }\r
922         if (la) {\r
923             errln("FAIL: " + laZone + " in JP = " + la);\r
924         }\r
925         if (!tokyo) {\r
926             errln("FAIL: " + tokyoZone + " in JP = " + tokyo);\r
927         }\r
928     }\r
929 \r
930     public void TestFractionalDST() {\r
931         String tzName = "Australia/Lord_Howe"; // 30 min offset\r
932         java.util.TimeZone tz_java = java.util.TimeZone.getTimeZone(tzName);\r
933         int dst_java = 0;\r
934         try {\r
935             // hack so test compiles and runs in both JDK 1.3 and JDK 1.4\r
936             final Object[] args = new Object[0];\r
937             final Class[] argtypes = new Class[0];\r
938             java.lang.reflect.Method m = tz_java.getClass().getMethod("getDSTSavings", argtypes); \r
939             dst_java = ((Integer) m.invoke(tz_java, args)).intValue();\r
940             if (dst_java <= 0 || dst_java >= 3600000) { // didn't get the fractional time zone we wanted\r
941             errln("didn't get fractional time zone!");\r
942             }\r
943         } catch (NoSuchMethodException e) {\r
944             // see JDKTimeZone for the reason for this code\r
945             dst_java = 3600000;\r
946         } catch (IllegalAccessException e) {\r
947             // see JDKTimeZone for the reason for this code\r
948             errln(e.getMessage());\r
949             dst_java = 3600000;\r
950         } catch (InvocationTargetException e) {\r
951             // see JDKTimeZone for the reason for this code\r
952             errln(e.getMessage());\r
953             dst_java = 3600000;\r
954         } catch (SecurityException e) {\r
955             warnln(e.getMessage());\r
956             return;\r
957         }\r
958         \r
959         com.ibm.icu.util.TimeZone tz_icu = com.ibm.icu.util.TimeZone.getTimeZone(tzName);\r
960         int dst_icu = tz_icu.getDSTSavings();\r
961 \r
962         if (dst_java != dst_icu) {\r
963             warnln("java reports dst savings of " + dst_java +\r
964               " but icu reports " + dst_icu + \r
965               " for tz " + tz_icu.getID());\r
966         } else {\r
967             logln("both java and icu report dst savings of " + dst_java + " for tz " + tz_icu.getID());\r
968         }\r
969     }\r
970 \r
971     public void TestGetOffsetDate() {\r
972         Calendar cal = Calendar.getInstance();\r
973         cal.set(1997, Calendar.JANUARY, 30);\r
974         long date = cal.getTimeInMillis();\r
975 \r
976     TimeZone tz_icu = TimeZone.getTimeZone("America/Los_Angeles");\r
977     int offset = tz_icu.getOffset(date);\r
978     if (offset != -28800000) {\r
979         errln("expected offset -28800000, got: " + offset);\r
980     }\r
981 \r
982     cal.set(1997, Calendar.JULY, 30);\r
983     date = cal.getTimeInMillis();\r
984     offset = tz_icu.getOffset(date);\r
985     if (offset != -25200000) {\r
986         errln("expected offset -25200000, got: " + offset);\r
987     }\r
988     }\r
989 \r
990     // jb4484\r
991     public void TestSimpleTimeZoneSerialization() \r
992     {\r
993         SimpleTimeZone stz0 = new SimpleTimeZone(32400000, "MyTimeZone");\r
994         SimpleTimeZone stz1 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
995         SimpleTimeZone stz2 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
996         stz2.setRawOffset(0);\r
997         SimpleTimeZone stz3 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
998         stz3.setStartYear(100);\r
999         SimpleTimeZone stz4 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1000         stz4.setStartYear(1000);\r
1001         stz4.setDSTSavings(1800000);\r
1002         stz4.setStartRule(3, 4, 180000);\r
1003         stz4.setEndRule(6, 3, 4, 360000);\r
1004         SimpleTimeZone stz5 = new SimpleTimeZone(32400000, "Asia/Tokyo");\r
1005         stz5.setStartRule(2, 3, 4, 360000);\r
1006         stz5.setEndRule(6, 3, 4, 360000);\r
1007         \r
1008         SimpleTimeZone[] stzs = { stz0, stz1, stz2, stz3, stz4, stz5, };\r
1009 \r
1010         for (int i = 0; i < stzs.length; ++i) {\r
1011             SimpleTimeZone stz = stzs[i];\r
1012             try {\r
1013                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
1014                 ObjectOutputStream oos = new ObjectOutputStream(baos);\r
1015                 oos.writeObject(stz);\r
1016                 oos.close();\r
1017                 byte[] bytes = baos.toByteArray();\r
1018                 logln("id: " + stz.getID() + " length: " + bytes.length);\r
1019 \r
1020                 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
1021                 ObjectInputStream ois = new ObjectInputStream(bais);\r
1022 \r
1023                 SimpleTimeZone stzDeserialized = (SimpleTimeZone)ois.readObject();\r
1024                 ois.close();\r
1025 \r
1026                 assertEquals("time zones", stz, stzDeserialized);\r
1027             }\r
1028             catch (ClassCastException cce) {\r
1029                 cce.printStackTrace();\r
1030                 errln("could not deserialize SimpleTimeZone");\r
1031             }\r
1032             catch (IOException ioe) {\r
1033                 errln(ioe.getMessage());\r
1034             }\r
1035             catch (ClassNotFoundException cnfe) {\r
1036                 errln(cnfe.getMessage());\r
1037             }\r
1038         }\r
1039     }\r
1040 \r
1041     // jb4175\r
1042     /* Generated by org.unicode.cldr.tool.CountItems */\r
1043     private static final String[] timeZoneTestNames = {\r
1044         "America/Argentina/Buenos_Aires", "America/Buenos_Aires",\r
1045         "America/Argentina/Catamarca", "America/Catamarca",\r
1046         "America/Argentina/Cordoba", "America/Cordoba",\r
1047         "America/Argentina/Jujuy", "America/Jujuy",\r
1048         "America/Argentina/Mendoza", "America/Mendoza",\r
1049         "America/Atka", "America/Adak",\r
1050         "America/Ensenada", "America/Tijuana",\r
1051         "America/Fort_Wayne", "America/Indianapolis",\r
1052         "America/Indiana/Indianapolis", "America/Indianapolis",\r
1053         "America/Kentucky/Louisville", "America/Louisville",\r
1054         "America/Knox_IN", "America/Indiana/Knox",\r
1055         "America/Porto_Acre", "America/Rio_Branco",\r
1056         "America/Rosario", "America/Cordoba",\r
1057         "America/Virgin", "America/St_Thomas",\r
1058         "Asia/Ashkhabad", "Asia/Ashgabat",\r
1059         "Asia/Chungking", "Asia/Chongqing",\r
1060         "Asia/Dacca", "Asia/Dhaka",\r
1061         "Asia/Istanbul", "Europe/Istanbul",\r
1062         "Asia/Macao", "Asia/Macau",\r
1063         "Asia/Tel_Aviv", "Asia/Jerusalem",\r
1064         "Asia/Thimbu", "Asia/Thimphu",\r
1065         "Asia/Ujung_Pandang", "Asia/Makassar",\r
1066         "Asia/Ulan_Bator", "Asia/Ulaanbaatar",\r
1067         "Australia/ACT", "Australia/Sydney",\r
1068         "Australia/Canberra", "Australia/Sydney",\r
1069         "Australia/LHI", "Australia/Lord_Howe",\r
1070         "Australia/NSW", "Australia/Sydney",\r
1071         "Australia/North", "Australia/Darwin",\r
1072         "Australia/Queensland", "Australia/Brisbane",\r
1073         "Australia/South", "Australia/Adelaide",\r
1074         "Australia/Tasmania", "Australia/Hobart",\r
1075         "Australia/Victoria", "Australia/Melbourne",\r
1076         "Australia/West", "Australia/Perth",\r
1077         "Australia/Yancowinna", "Australia/Broken_Hill",\r
1078         "Brazil/Acre", "America/Rio_Branco",\r
1079         "Brazil/DeNoronha", "America/Noronha",\r
1080         "Brazil/East", "America/Sao_Paulo",\r
1081         "Brazil/West", "America/Manaus",\r
1082         "CST6CDT", "America/Chicago",\r
1083         "Canada/Atlantic", "America/Halifax",\r
1084         "Canada/Central", "America/Winnipeg",\r
1085         "Canada/East-Saskatchewan", "America/Regina",\r
1086         "Canada/Eastern", "America/Toronto",\r
1087         "Canada/Mountain", "America/Edmonton",\r
1088         "Canada/Newfoundland", "America/St_Johns",\r
1089         "Canada/Pacific", "America/Vancouver",\r
1090         "Canada/Saskatchewan", "America/Regina",\r
1091         "Canada/Yukon", "America/Whitehorse",\r
1092         "Chile/Continental", "America/Santiago",\r
1093         "Chile/EasterIsland", "Pacific/Easter",\r
1094         "Cuba", "America/Havana",\r
1095         "EST", "America/Indianapolis",\r
1096         "EST5EDT", "America/New_York",\r
1097         "Egypt", "Africa/Cairo",\r
1098         "Eire", "Europe/Dublin",\r
1099         "Etc/GMT+0", "Etc/GMT",\r
1100         "Etc/GMT-0", "Etc/GMT",\r
1101         "Etc/GMT0", "Etc/GMT",\r
1102         "Etc/Greenwich", "Etc/GMT",\r
1103         "Etc/UCT", "Etc/GMT",\r
1104         "Etc/UTC", "Etc/GMT",\r
1105         "Etc/Universal", "Etc/GMT",\r
1106         "Etc/Zulu", "Etc/GMT",\r
1107         "Europe/Nicosia", "Asia/Nicosia",\r
1108         "Europe/Tiraspol", "Europe/Chisinau",\r
1109         "GB", "Europe/London",\r
1110         "GB-Eire", "Europe/London",\r
1111         "GMT", "Etc/GMT",\r
1112         "GMT+0", "Etc/GMT",\r
1113         "GMT-0", "Etc/GMT",\r
1114         "GMT0", "Etc/GMT",\r
1115         "Greenwich", "Etc/GMT",\r
1116         "HST", "Pacific/Honolulu",\r
1117         "Hongkong", "Asia/Hong_Kong",\r
1118         "Iceland", "Atlantic/Reykjavik",\r
1119         "Iran", "Asia/Tehran",\r
1120         "Israel", "Asia/Jerusalem",\r
1121         "Jamaica", "America/Jamaica",\r
1122         "Japan", "Asia/Tokyo",\r
1123         "Kwajalein", "Pacific/Kwajalein",\r
1124         "Libya", "Africa/Tripoli",\r
1125         "MST", "America/Phoenix",\r
1126         "MST7MDT", "America/Denver",\r
1127         "Mexico/BajaNorte", "America/Tijuana",\r
1128         "Mexico/BajaSur", "America/Mazatlan",\r
1129         "Mexico/General", "America/Mexico_City",\r
1130         "NZ", "Pacific/Auckland",\r
1131         "NZ-CHAT", "Pacific/Chatham",\r
1132         "Navajo", "America/Shiprock", /* fixed from Mark's original */\r
1133         "PRC", "Asia/Shanghai",\r
1134         "PST8PDT", "America/Los_Angeles",\r
1135         "Pacific/Samoa", "Pacific/Pago_Pago",\r
1136         "Poland", "Europe/Warsaw",\r
1137         "Portugal", "Europe/Lisbon",\r
1138         "ROC", "Asia/Taipei",\r
1139         "ROK", "Asia/Seoul",\r
1140         "Singapore", "Asia/Singapore",\r
1141         "SystemV/AST4", "America/Puerto_Rico",\r
1142         "SystemV/AST4ADT", "America/Halifax",\r
1143         "SystemV/CST6", "America/Regina",\r
1144         "SystemV/CST6CDT", "America/Chicago",\r
1145         "SystemV/EST5", "America/Indianapolis",\r
1146         "SystemV/EST5EDT", "America/New_York",\r
1147         "SystemV/HST10", "Pacific/Honolulu",\r
1148         "SystemV/MST7", "America/Phoenix",\r
1149         "SystemV/MST7MDT", "America/Denver",\r
1150         "SystemV/PST8", "Pacific/Pitcairn",\r
1151         "SystemV/PST8PDT", "America/Los_Angeles",\r
1152         "SystemV/YST9", "Pacific/Gambier",\r
1153         "SystemV/YST9YDT", "America/Anchorage",\r
1154         "Turkey", "Europe/Istanbul",\r
1155         "UCT", "Etc/GMT",\r
1156         "US/Alaska", "America/Anchorage",\r
1157         "US/Aleutian", "America/Adak",\r
1158         "US/Arizona", "America/Phoenix",\r
1159         "US/Central", "America/Chicago",\r
1160         "US/East-Indiana", "America/Indianapolis",\r
1161         "US/Eastern", "America/New_York",\r
1162         "US/Hawaii", "Pacific/Honolulu",\r
1163         "US/Indiana-Starke", "America/Indiana/Knox",\r
1164         "US/Michigan", "America/Detroit",\r
1165         "US/Mountain", "America/Denver",\r
1166         "US/Pacific", "America/Los_Angeles",\r
1167         "US/Pacific-New", "America/Los_Angeles",\r
1168         "US/Samoa", "Pacific/Pago_Pago",\r
1169         "UTC", "Etc/GMT",\r
1170         "Universal", "Etc/GMT",\r
1171         "W-SU", "Europe/Moscow",\r
1172         "Zulu", "Etc/GMT",\r
1173     };\r
1174 \r
1175     public void TestOddTimeZoneNames() {\r
1176         for (int i = 0; i < timeZoneTestNames.length; i += 2) {\r
1177             String funkyName = timeZoneTestNames[i];\r
1178             String correctName = timeZoneTestNames[i+1];\r
1179 \r
1180             TimeZone ftz = TimeZone.getTimeZone(funkyName);\r
1181             TimeZone ctz = TimeZone.getTimeZone(correctName);\r
1182 \r
1183             String fdn = ftz.getDisplayName();\r
1184             long fro = ftz.getRawOffset();\r
1185             long fds = ftz.getDSTSavings();\r
1186             boolean fdy = ftz.useDaylightTime();\r
1187 \r
1188             String cdn = ctz.getDisplayName();\r
1189             long cro = ctz.getRawOffset();\r
1190             long cds = ctz.getDSTSavings();\r
1191             boolean cdy = ctz.useDaylightTime();\r
1192 \r
1193             if (!fdn.equals(cdn)) {\r
1194                 logln("display name (" + funkyName + ", " + correctName + ") expected: " + cdn + " but got: " + fdn);\r
1195             } else if (fro != cro) {\r
1196                 logln("offset (" + funkyName + ", " + correctName + ") expected: " + cro + " but got: " + fro);\r
1197             } else if (fds != cds) {\r
1198                 logln("daylight (" + funkyName + ", " + correctName + ") expected: " + cds + " but got: " + fds);\r
1199             } else if (fdy != cdy) {\r
1200                 logln("uses daylight (" + funkyName + ", " + correctName + ") expected: " + cdy + " but got: " + fdy);\r
1201             } else {\r
1202                 // no error, assume we're referencing the same internal java object\r
1203             }\r
1204         }\r
1205     }\r
1206     \r
1207     public void TestCoverage(){\r
1208         class StubTimeZone extends TimeZone{\r
1209             /**\r
1210              * For serialization\r
1211              */\r
1212             private static final long serialVersionUID = 8658654217433379343L;\r
1213             public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {return 0;}\r
1214             public void setRawOffset(int offsetMillis) {}\r
1215             public int getRawOffset() {return 0;}\r
1216             public boolean useDaylightTime() {return false;}\r
1217             public boolean inDaylightTime(Date date) {return false;}\r
1218         } \r
1219         StubTimeZone stub = new StubTimeZone();\r
1220         StubTimeZone stub2 = (StubTimeZone) stub.clone();\r
1221         if (stub.getDSTSavings() != 0){\r
1222             errln("TimeZone.getDSTSavings() should return 0");\r
1223         }\r
1224         if (!stub.hasSameRules(stub2)){\r
1225             errln("TimeZone.clone() object should hasSameRules");\r
1226      \r
1227         }\r
1228     }\r
1229     public void TestMark(){\r
1230         String tzid = "America/Argentina/ComodRivadavia";\r
1231         TimeZone tz = TimeZone.getTimeZone(tzid);\r
1232         int offset = tz.getOffset(new Date().getTime());\r
1233         logln(tzid + ":\t" + offset);\r
1234         List list = Arrays.asList(TimeZone.getAvailableIDs());\r
1235         if(!list.contains(tzid)){\r
1236             errln("Could create the time zone but it is not in getAvailableIDs");\r
1237         }\r
1238     }\r
1239     public void TestZoneMeta() {\r
1240         java.util.TimeZone save = java.util.TimeZone.getDefault();\r
1241         java.util.TimeZone newZone = java.util.TimeZone.getTimeZone("GMT-08:00");\r
1242         com.ibm.icu.util.TimeZone.setDefault(null);\r
1243         java.util.TimeZone.setDefault(newZone);\r
1244         SimpleTimeZone zone = new SimpleTimeZone(0, "GMT");\r
1245         com.ibm.icu.util.TimeZone defaultZone = com.ibm.icu.util.TimeZone.getDefault();\r
1246         if(defaultZone==null){\r
1247             errln("TimeZone.getDefault() failed for GMT-08:00");\r
1248         }\r
1249         if(zone==null){\r
1250             errln("SimpleTimeZone(0, GMT-08:00) failed for GMT-08:00");\r
1251         }\r
1252         //reset\r
1253         java.util.TimeZone.setDefault(save);\r
1254     }\r
1255 \r
1256     // Copied from the protected constant in TimeZone.\r
1257     private static final int MILLIS_PER_HOUR = 60*60*1000;\r
1258 \r
1259     //  Test that a transition at the end of February is handled correctly.\r
1260     public void TestFebruary() {\r
1261         // Time zone with daylight savings time from the first Sunday in November\r
1262         // to the last Sunday in February.\r
1263         // Similar to the new rule for Brazil (Sao Paulo) in tzdata2006n.\r
1264         //\r
1265         // Note: In tzdata2007h, the rule had changed, so no actual zones uses\r
1266         // lastSun in Feb anymore.\r
1267         SimpleTimeZone tz1 = new SimpleTimeZone(\r
1268                            -3 * MILLIS_PER_HOUR,                    // raw offset: 3h before (west of) GMT\r
1269                            "nov-feb",\r
1270                            Calendar.NOVEMBER, 1, Calendar.SUNDAY,   // start: November, first, Sunday\r
1271                            0,                                       //        midnight wall time\r
1272                            Calendar.FEBRUARY, -1, Calendar.SUNDAY,  // end:   February, last, Sunday\r
1273                            0);                                      //        midnight wall time\r
1274 \r
1275         // Now hardcode the same rules as for Brazil in tzdata 2006n, so that\r
1276         // we cover the intended code even when in the future zoneinfo hardcodes\r
1277         // these transition dates.\r
1278         SimpleTimeZone tz2= new SimpleTimeZone(\r
1279                            -3 * MILLIS_PER_HOUR,                    // raw offset: 3h before (west of) GMT\r
1280                            "nov-feb2",\r
1281                            Calendar.NOVEMBER, 1, -Calendar.SUNDAY,  // start: November, 1 or after, Sunday\r
1282                            0,                                       //        midnight wall time\r
1283                            Calendar.FEBRUARY, -29, -Calendar.SUNDAY,// end:   February, 29 or before, Sunday\r
1284                            0);                                      //        midnight wall time\r
1285 \r
1286         // Gregorian calendar with the UTC time zone for getting sample test date/times.\r
1287         GregorianCalendar gc = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));\r
1288         // "Unable to create the UTC calendar: %s"\r
1289 \r
1290         int[] data = {\r
1291             // UTC time (6 fields) followed by\r
1292             // expected time zone offset in hours after GMT (negative=before GMT).\r
1293             // int year, month, day, hour, minute, second, offsetHours\r
1294             2006, Calendar.NOVEMBER,  5, 02, 59, 59, -3,\r
1295             2006, Calendar.NOVEMBER,  5, 03, 00, 00, -2,\r
1296             2007, Calendar.FEBRUARY, 25, 01, 59, 59, -2,\r
1297             2007, Calendar.FEBRUARY, 25, 02, 00, 00, -3,\r
1298 \r
1299             2007, Calendar.NOVEMBER,  4, 02, 59, 59, -3,\r
1300             2007, Calendar.NOVEMBER,  4, 03, 00, 00, -2,\r
1301             2008, Calendar.FEBRUARY, 24, 01, 59, 59, -2,\r
1302             2008, Calendar.FEBRUARY, 24, 02, 00, 00, -3,\r
1303 \r
1304             2008, Calendar.NOVEMBER,  2, 02, 59, 59, -3,\r
1305             2008, Calendar.NOVEMBER,  2, 03, 00, 00, -2,\r
1306             2009, Calendar.FEBRUARY, 22, 01, 59, 59, -2,\r
1307             2009, Calendar.FEBRUARY, 22, 02, 00, 00, -3,\r
1308 \r
1309             2009, Calendar.NOVEMBER,  1, 02, 59, 59, -3,\r
1310             2009, Calendar.NOVEMBER,  1, 03, 00, 00, -2,\r
1311             2010, Calendar.FEBRUARY, 28, 01, 59, 59, -2,\r
1312             2010, Calendar.FEBRUARY, 28, 02, 00, 00, -3\r
1313         };\r
1314 \r
1315         TimeZone timezones[] = { tz1, tz2 };\r
1316 \r
1317         TimeZone tz;\r
1318         Date dt;\r
1319         int t, i, raw, dst;\r
1320         int[] offsets = new int[2]; // raw = offsets[0], dst = offsets[1]\r
1321         for (t = 0; t < timezones.length; ++t) {\r
1322             tz = timezones[t];\r
1323             for (i = 0; i < data.length; i+=7) {\r
1324                 gc.set(data[i], data[i+1], data[i+2],\r
1325                        data[i+3], data[i+4], data[i+5]);\r
1326                 dt = gc.getTime();\r
1327                 tz.getOffset(dt.getTime(), false, offsets);\r
1328                 raw = offsets[0];\r
1329                 dst = offsets[1];\r
1330                 if ((raw + dst) != data[i+6] * MILLIS_PER_HOUR) {\r
1331                     errln("test case " + t + "." + (i/7) + ": " +\r
1332                           "tz.getOffset(" + data[i] + "-" + (data[i+1] + 1) + "-" + data[i+2] + " " +\r
1333                           data[i+3] + ":" + data[i+4] + ":" + data[i+5] +\r
1334                           ") returns " + raw + "+" + dst + " != " + data[i+6] * MILLIS_PER_HOUR);\r
1335                 }\r
1336             }\r
1337         }\r
1338     }\r
1339 \r
1340     public void TestCanonicalID() {\r
1341         // Some canonical IDs in CLDR are defined as "Link"\r
1342         // in Olson tzdata.\r
1343         final String[][] excluded1 = {\r
1344                 {"America/Shiprock", "America/Denver"}, // America/Shiprock is defined as a Link to America/Denver in tzdata\r
1345                 {"America/Marigot", "America/Guadeloupe"},\r
1346                 {"America/St_Barthelemy", "America/Guadeloupe"},\r
1347                 {"Antarctica/South_Pole", "Antarctica/McMurdo"},\r
1348                 {"Atlantic/Jan_Mayen", "Europe/Oslo"},\r
1349                 {"Arctic/Longyearbyen", "Europe/Oslo"},\r
1350                 {"Europe/Guernsey", "Europe/London"},\r
1351                 {"Europe/Isle_of_Man", "Europe/London"},\r
1352                 {"Europe/Jersey", "Europe/London"},\r
1353                 {"Europe/Ljubljana", "Europe/Belgrade"},\r
1354                 {"Europe/Podgorica", "Europe/Belgrade"},\r
1355                 {"Europe/Sarajevo", "Europe/Belgrade"},\r
1356                 {"Europe/Skopje", "Europe/Belgrade"},\r
1357                 {"Europe/Zagreb", "Europe/Belgrade"},\r
1358                 {"Europe/Bratislava", "Europe/Prague"},\r
1359                 {"Europe/Mariehamn", "Europe/Helsinki"},\r
1360                 {"Europe/San_Marino", "Europe/Rome"},\r
1361                 {"Europe/Vatican", "Europe/Rome"},\r
1362         };\r
1363 \r
1364         // Following IDs are aliases of Etc/GMT in CLDR,\r
1365         // but Olson tzdata has 3 independent definitions\r
1366         // for Etc/GMT, Etc/UTC, Etc/UCT.\r
1367         // Until we merge them into one equivalent group\r
1368         // in zoneinfo.res, we exclude them in the test\r
1369         // below.\r
1370         final String[] excluded2 = {\r
1371                 "Etc/UCT", "UCT",\r
1372                 "Etc/UTC", "UTC",\r
1373                 "Etc/Universal", "Universal",\r
1374                 "Etc/Zulu", "Zulu",\r
1375         };\r
1376 \r
1377         // Walk through equivalency groups\r
1378         String[] ids = TimeZone.getAvailableIDs();\r
1379         for (int i = 0; i < ids.length; i++) {\r
1380             int nEquiv = TimeZone.countEquivalentIDs(ids[i]);\r
1381             if (nEquiv == 0) {\r
1382                 continue;\r
1383             }\r
1384             String canonicalID = null;\r
1385             boolean bFoundCanonical = false;\r
1386             // Make sure getCanonicalID returns the exact same result\r
1387             // for all entries within a same equivalency group with some\r
1388             // exceptions listed in exluded1.\r
1389             // Also, one of them must be canonical id.\r
1390             for (int j = 0; j < nEquiv; j++) {\r
1391                 String tmp = TimeZone.getEquivalentID(ids[i], j);\r
1392                 String tmpCanonical = TimeZone.getCanonicalID(tmp);\r
1393                 if (tmpCanonical == null) {\r
1394                     errln("FAIL: getCanonicalID(\"" + tmp + "\") returned null");\r
1395                     continue;\r
1396                 }\r
1397                 // Some exceptional cases\r
1398                 for (int k = 0; k < excluded1.length; k++) {\r
1399                     if (tmpCanonical.equals(excluded1[k][0])) {\r
1400                         tmpCanonical = excluded1[k][1];\r
1401                     }\r
1402                 }\r
1403 \r
1404                 if (j == 0) {\r
1405                     canonicalID = tmpCanonical;\r
1406                 } else if (!canonicalID.equals(tmpCanonical)) {\r
1407                     errln("FAIL: getCanonicalID(\"" + tmp + "\") returned " + tmpCanonical + " expected:" + canonicalID);\r
1408                 }\r
1409 \r
1410                 if (canonicalID.equals(tmp)) {\r
1411                     bFoundCanonical = true;\r
1412                 }\r
1413             }\r
1414             // At least one ID in an equvalency group must match the\r
1415             // canonicalID\r
1416             if (!bFoundCanonical) {\r
1417                 // test exclusion because of differences between Olson tzdata and CLDR\r
1418                 boolean isExcluded = false;\r
1419                 for (int k = 0; k < excluded1.length; k++) {\r
1420                     if (ids[i].equals(excluded2[k])) {\r
1421                         isExcluded = true;\r
1422                         break;\r
1423                     }\r
1424                 }\r
1425                 if (isExcluded) {\r
1426                     continue;\r
1427                 }\r
1428 \r
1429                 errln("FAIL: No timezone ids match the canonical ID " + canonicalID);\r
1430             }\r
1431         }\r
1432         // Testing some special cases\r
1433         final String[][] data = {\r
1434                 {"GMT-03", "GMT-03:00", null},\r
1435                 {"GMT+4", "GMT+04:00", null},\r
1436                 {"GMT-055", "GMT-00:55", null},\r
1437                 {"GMT+430", "GMT+04:30", null},\r
1438                 {"GMT-12:15", "GMT-12:15", null},\r
1439                 {"GMT-091015", "GMT-09:10:15", null},\r
1440                 {"GMT+1:90", null, null},\r
1441                 {"America/Argentina/Buenos_Aires", "America/Buenos_Aires", "true"},\r
1442                 {"bogus", null, null},\r
1443                 {"", null, null},\r
1444                 {null, null, null},\r
1445         };\r
1446         boolean[] isSystemID = new boolean[1];\r
1447         for (int i = 0; i < data.length; i++) {\r
1448             String canonical = TimeZone.getCanonicalID(data[i][0], isSystemID);\r
1449             if (canonical != null && !canonical.equals(data[i][1])\r
1450                     || canonical == null && data[i][1] != null) {\r
1451                 errln("FAIL: getCanonicalID(\"" + data[i][0] + "\") returned " + canonical\r
1452                         + " - expected: " + data[i][1]);\r
1453             }\r
1454             if ("true".equalsIgnoreCase(data[i][2]) != isSystemID[0]) {\r
1455                 errln("FAIL: getCanonicalID(\"" + data[i][0] + "\") set " + isSystemID[0]\r
1456                         + " to isSystemID");\r
1457             }\r
1458         }\r
1459     }\r
1460 \r
1461     public void TestSetDefault() {\r
1462         java.util.TimeZone save = java.util.TimeZone.getDefault();\r
1463 \r
1464         /*\r
1465          * America/Caracs (Venezuela) changed the base offset from -4:00 to\r
1466          * -4:30 on Dec 9, 2007.\r
1467          */\r
1468 \r
1469         TimeZone icuCaracas = TimeZone.getTimeZone("America/Caracas", TimeZone.TIMEZONE_ICU);\r
1470         java.util.TimeZone jdkCaracas = java.util.TimeZone.getTimeZone("America/Caracas");\r
1471 \r
1472         // Set JDK America/Caracas as the default\r
1473         java.util.TimeZone.setDefault(jdkCaracas);\r
1474 \r
1475         java.util.Calendar jdkCal = java.util.Calendar.getInstance();\r
1476         jdkCal.clear();\r
1477         jdkCal.set(2007, java.util.Calendar.JANUARY, 1);\r
1478 \r
1479         int rawOffset = jdkCal.get(java.util.Calendar.ZONE_OFFSET);\r
1480         int dstSavings = jdkCal.get(java.util.Calendar.DST_OFFSET);\r
1481 \r
1482         int[] offsets = new int[2];\r
1483         icuCaracas.getOffset(jdkCal.getTime().getTime()/*jdkCal.getTimeInMillis()*/, false, offsets);\r
1484 \r
1485         boolean isTimeZoneSynchronized = true;\r
1486 \r
1487         if (rawOffset != offsets[0] || dstSavings != offsets[1]) {\r
1488             // JDK time zone rule is out of sync...\r
1489             logln("Rule for JDK America/Caracas is not same with ICU.  Skipping the rest.");\r
1490             isTimeZoneSynchronized = false;\r
1491         }\r
1492 \r
1493         if (isTimeZoneSynchronized) {\r
1494             // If JDK America/Caracas uses the same rule with ICU,\r
1495             // the following code should work well.\r
1496             TimeZone.setDefault(icuCaracas);\r
1497 \r
1498             // Create a new JDK calendar instance again.\r
1499             // This calendar should reflect the new default\r
1500             // set by ICU TimeZone#setDefault.\r
1501             jdkCal = java.util.Calendar.getInstance();\r
1502             jdkCal.clear();\r
1503             jdkCal.set(2007, java.util.Calendar.JANUARY, 1);\r
1504 \r
1505             rawOffset = jdkCal.get(java.util.Calendar.ZONE_OFFSET);\r
1506             dstSavings = jdkCal.get(java.util.Calendar.DST_OFFSET);\r
1507 \r
1508             if (rawOffset != offsets[0] || dstSavings != offsets[1]) {\r
1509                 errln("ERROR: Got offset [raw:" + rawOffset + "/dst:" + dstSavings\r
1510                           + "] Expected [raw:" + offsets[0] + "/dst:" + offsets[1] + "]");\r
1511             }\r
1512         }\r
1513 \r
1514         // Restore the original JDK time zone\r
1515         java.util.TimeZone.setDefault(save);\r
1516     }\r
1517 \r
1518     /*\r
1519      * Test Display Names, choosing zones and lcoales where there are multiple\r
1520      * meta-zones defined.\r
1521      */\r
1522     public void TestDisplayNamesMeta() {\r
1523         final Integer TZSHORT = new Integer(TimeZone.SHORT);\r
1524         final Integer TZLONG = new Integer(TimeZone.LONG);\r
1525 \r
1526         final Object[][] zoneDisplayTestData = {\r
1527             //  zone id             locale  summer          format      expected display name\r
1528             {"Europe/London",       "en",   Boolean.FALSE,  TZSHORT,    "GMT"},\r
1529             {"Europe/London",       "en",   Boolean.FALSE,  TZLONG,     "Greenwich Mean Time"},\r
1530             {"Europe/London",       "en",   Boolean.TRUE,   TZSHORT,    "GMT+01:00" /*"BST"*/},\r
1531             {"Europe/London",       "en",   Boolean.TRUE,   TZLONG,     "British Summer Time"},\r
1532 \r
1533             {"America/Anchorage",   "en",   Boolean.FALSE,  TZSHORT,    "AKST"},\r
1534             {"America/Anchorage",   "en",   Boolean.FALSE,  TZLONG,     "Alaska Standard Time"},\r
1535             {"America/Anchorage",   "en",   Boolean.TRUE,   TZSHORT,    "AKDT"},\r
1536             {"America/Anchorage",   "en",   Boolean.TRUE,   TZLONG,     "Alaska Daylight Time"},\r
1537 \r
1538             // Southern Hemisphere, all data from meta:Australia_Western\r
1539             {"Australia/Perth",     "en",   Boolean.FALSE,  TZSHORT,    "GMT+08:00"/*"AWST"*/},\r
1540             {"Australia/Perth",     "en",   Boolean.FALSE,  TZLONG,     "Australian Western Standard Time"},\r
1541             {"Australia/Perth",     "en",   Boolean.TRUE,   TZSHORT,    "GMT+09:00"/*"AWDT"*/},\r
1542             {"Australia/Perth",     "en",   Boolean.TRUE,   TZLONG,     "Australian Western Daylight Time"},\r
1543 \r
1544             {"America/Sao_Paulo",   "en",   Boolean.FALSE,  TZSHORT,    "GMT-03:00"/*"BRT"*/},\r
1545             {"America/Sao_Paulo",   "en",   Boolean.FALSE,  TZLONG,     "Brasilia Time"},\r
1546             {"America/Sao_Paulo",   "en",   Boolean.TRUE,   TZSHORT,    "GMT-02:00"/*"BRST"*/},\r
1547             {"America/Sao_Paulo",   "en",   Boolean.TRUE,   TZLONG,     "Brasilia Summer Time"},\r
1548 \r
1549             // No Summer Time, but had it before 1983.\r
1550             {"Pacific/Honolulu",    "en",   Boolean.FALSE,  TZSHORT,    "HST"},\r
1551             {"Pacific/Honolulu",    "en",   Boolean.FALSE,  TZLONG,     "Hawaii-Aleutian Standard Time"},\r
1552             {"Pacific/Honolulu",    "en",   Boolean.TRUE,   TZSHORT,    "HST"},\r
1553             {"Pacific/Honolulu",    "en",   Boolean.TRUE,   TZLONG,     "Hawaii-Aleutian Standard Time"},\r
1554 \r
1555             // Northern, has Summer, not commonly used.\r
1556             {"Europe/Helsinki",     "en",   Boolean.FALSE,  TZSHORT,    "GMT+02:00"/*"EET"*/},\r
1557             {"Europe/Helsinki",     "en",   Boolean.FALSE,  TZLONG,     "Eastern European Time"},\r
1558             {"Europe/Helsinki",     "en",   Boolean.TRUE,   TZSHORT,    "GMT+03:00"/*"EEST"*/},\r
1559             {"Europe/Helsinki",     "en",   Boolean.TRUE,   TZLONG,     "Eastern European Summer Time"},\r
1560 \r
1561             // Repeating the test data for DST.  The test data below trigger the problem reported\r
1562             // by Ticket#6644\r
1563             {"Europe/London",       "en",   Boolean.TRUE,   TZSHORT,    "GMT+01:00" /*"BST"*/},\r
1564             {"Europe/London",       "en",   Boolean.TRUE,   TZLONG,     "British Summer Time"},\r
1565         };\r
1566 \r
1567         boolean isReferenceYear = true;\r
1568         GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));\r
1569         if (cal.get(Calendar.YEAR) != REFERENCE_YEAR) {\r
1570             isReferenceYear = false;\r
1571         }\r
1572         boolean isICUTimeZone = (TimeZone.getDefaultTimeZoneType() == TimeZone.TIMEZONE_ICU);\r
1573 \r
1574         boolean sawAnError = false;\r
1575         for (int testNum = 0; testNum < zoneDisplayTestData.length; testNum++) {\r
1576             ULocale locale = new ULocale((String)zoneDisplayTestData[testNum][1]);\r
1577             TimeZone zone = TimeZone.getTimeZone((String)zoneDisplayTestData[testNum][0]);\r
1578             String displayName = zone.getDisplayName(((Boolean)zoneDisplayTestData[testNum][2]).booleanValue(),\r
1579                     ((Integer)zoneDisplayTestData[testNum][3]).intValue());\r
1580             if (!displayName.equals(zoneDisplayTestData[testNum][4])) {\r
1581                 if (isReferenceYear\r
1582                                 && (isICUTimeZone || !((Boolean)zoneDisplayTestData[testNum][2]).booleanValue())) {\r
1583                     sawAnError = true;\r
1584                     errln("Incorrect time zone display name.  zone = "\r
1585                             + zoneDisplayTestData[testNum][0] + ",\n"\r
1586                             + "   locale = " + locale\r
1587                             + ",   style = " + (zoneDisplayTestData[testNum][3] == TZSHORT ? "SHORT" : "LONG")\r
1588                             + ",   Summertime = " + zoneDisplayTestData[testNum][2] + "\n"\r
1589                             + "   Expected " + zoneDisplayTestData[testNum][4]\r
1590                             + ",   Got " + displayName);\r
1591                 } else {\r
1592                     logln("Incorrect time zone display name.  zone = "\r
1593                             + zoneDisplayTestData[testNum][0] + ",\n"\r
1594                             + "   locale = " + locale\r
1595                             + ",   style = " + (zoneDisplayTestData[testNum][3] == TZSHORT ? "SHORT" : "LONG")\r
1596                             + ",   Summertime = " + zoneDisplayTestData[testNum][2] + "\n"\r
1597                             + "   Expected " + zoneDisplayTestData[testNum][4]\r
1598                             + ",   Got " + displayName);\r
1599                 }\r
1600             }\r
1601         }\r
1602         if (sawAnError) {\r
1603             logln("Note: Errors could be the result of changes to zoneStrings locale data");\r
1604         }\r
1605     }\r
1606 }\r
1607 \r
1608 //eof\r