]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/tests/core/src/com/ibm/icu/dev/test/timezone/TimeZoneBoundaryTest.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / tests / core / src / com / ibm / icu / dev / test / timezone / TimeZoneBoundaryTest.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 package com.ibm.icu.dev.test.timezone;\r
8 import java.util.Date;\r
9 \r
10 import com.ibm.icu.dev.test.TestFmwk;\r
11 import com.ibm.icu.text.DateFormat;\r
12 import com.ibm.icu.util.Calendar;\r
13 import com.ibm.icu.util.SimpleTimeZone;\r
14 import com.ibm.icu.util.TimeZone;\r
15 \r
16 /**\r
17  * A test which discovers the boundaries of DST programmatically and verifies\r
18  * that they are correct.\r
19  */\r
20 public class TimeZoneBoundaryTest extends TestFmwk\r
21 {\r
22     static final int ONE_SECOND = 1000;\r
23     static final int ONE_MINUTE = 60*ONE_SECOND;\r
24     static final int ONE_HOUR = 60*ONE_MINUTE;\r
25     static final long ONE_DAY = 24*ONE_HOUR;\r
26     static final long ONE_YEAR = (long)(365.25 * ONE_DAY);\r
27     static final long SIX_MONTHS = ONE_YEAR / 2;\r
28 \r
29     static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};\r
30 \r
31     // These values are empirically determined to be correct\r
32     static final long PST_1997_BEG  = 860320800000L;\r
33     static final long PST_1997_END  = 877856400000L;\r
34 \r
35     // Minimum interval for binary searches in ms; should be no larger\r
36     // than 1000.\r
37     static final long INTERVAL = 10; // Milliseconds\r
38 \r
39     // [3Jan01 Liu] Updated for 2000f data\r
40     static final String AUSTRALIA = "Australia/Adelaide";\r
41     static final long AUSTRALIA_1997_BEG = 877797000000L;\r
42     static final long AUSTRALIA_1997_END = 859653000000L;\r
43     \r
44     public static void main(String[] args) throws Exception {\r
45         new TimeZoneBoundaryTest().run(args);\r
46     }\r
47 \r
48     /**\r
49      * Date.toString().substring() Boundary Test\r
50      * Look for a DST changeover to occur within 6 months of the given Date.\r
51      * The initial Date.toString() should yield a string containing the\r
52      * startMode as a SUBSTRING.  The boundary will be tested to be\r
53      * at the expectedBoundary value.\r
54      */\r
55     void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary)\r
56     {\r
57         // Given a date with a year start, find the Daylight onset\r
58         // and end.  The given date should be 1/1/xx in some year.\r
59 \r
60         if (d.toString().indexOf(startMode) == -1)\r
61         {\r
62             logln("Error: " + startMode + " not present in " + d);\r
63         }\r
64 \r
65         // Use a binary search, assuming that we have a Standard\r
66         // time at the midpoint.\r
67         long min = d.getTime();\r
68         long max = min + SIX_MONTHS;\r
69 \r
70         while ((max - min) >  INTERVAL)\r
71         {\r
72             long mid = (min + max) >> 1;\r
73             String s = new Date(mid).toString();\r
74             // logln(s);\r
75             if (s.indexOf(startMode) != -1)\r
76             {\r
77                 min = mid;\r
78             }\r
79             else\r
80             {\r
81                 max = mid;\r
82             }\r
83         }\r
84 \r
85         logln("Date Before: " + showDate(min));\r
86         logln("Date After:  " + showDate(max));\r
87         long mindelta = expectedBoundary - min;\r
88         // not used long maxdelta = max - expectedBoundary;\r
89         if (mindelta >= 0 && mindelta <= INTERVAL &&\r
90             mindelta >= 0 && mindelta <= INTERVAL)\r
91             logln("PASS: Expected boundary at " + expectedBoundary);\r
92         else\r
93             errln("FAIL: Expected boundary at " + expectedBoundary);\r
94     }\r
95 \r
96     // This test cannot be compiled until the inDaylightTime() method of GregorianCalendar\r
97     // becomes public.\r
98     //    static void findDaylightBoundaryUsingCalendar(Date d, boolean startsInDST)\r
99     //    {\r
100     //  // Given a date with a year start, find the Daylight onset\r
101     //  // and end.  The given date should be 1/1/xx in some year.\r
102     //\r
103     //  GregorianCalendar cal = new GregorianCalendar();\r
104     //  cal.setTime(d);\r
105     //  if (cal.inDaylightTime() != startsInDST)\r
106     //  {\r
107     //      logln("Error: inDaylightTime(" + d + ") != " + startsInDST);\r
108     //  }\r
109     //\r
110     //  // Use a binary search, assuming that we have a Standard\r
111     //  // time at the midpoint.\r
112     //  long min = d.getTime();\r
113     //  long max = min + (long)(365.25 / 2 * 24*60*60*1000);\r
114     //\r
115     //  while ((max - min) >  INTERVAL)\r
116     //  {\r
117     //      long mid = (min + max) >> 1;\r
118     //      cal.setTime(new Date(mid));\r
119     //      if (cal.inDaylightTime() == startsInDST)\r
120     //      {\r
121     //      min = mid;\r
122     //      }\r
123     //      else\r
124     //      {\r
125     //      max = mid;\r
126     //      }\r
127     //  }\r
128     //\r
129     //  logln("Calendar Before: " + showDate(min));\r
130     //  logln("Calendar After:  " + showDate(max));\r
131     //    }\r
132 \r
133     void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary)\r
134     {\r
135         findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary,\r
136                                           TimeZone.getDefault());\r
137     }\r
138 \r
139     void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST,\r
140                                            long expectedBoundary, TimeZone tz)\r
141     {\r
142         // Given a date with a year start, find the Daylight onset\r
143         // and end.  The given date should be 1/1/xx in some year.\r
144 \r
145         // Use a binary search, assuming that we have a Standard\r
146         // time at the midpoint.\r
147         long min = d.getTime();\r
148         long max = min + SIX_MONTHS;\r
149 \r
150         if (tz.inDaylightTime(d) != startsInDST)\r
151         {\r
152             errln("FAIL: " + tz.getID() + " inDaylightTime(" +\r
153                   d + ") != " + startsInDST);\r
154             startsInDST = !startsInDST; // Flip over; find the apparent value\r
155         }\r
156 \r
157         if (tz.inDaylightTime(new Date(max)) == startsInDST)\r
158         {\r
159             errln("FAIL: " + tz.getID() + " inDaylightTime(" +\r
160                   (new Date(max)) + ") != " + (!startsInDST));\r
161             return;\r
162         }\r
163 \r
164         while ((max - min) >  INTERVAL)\r
165         {\r
166             long mid = (min + max) >> 1;\r
167             boolean isIn = tz.inDaylightTime(new Date(mid));\r
168             if (isIn == startsInDST)\r
169             {\r
170                 min = mid;\r
171             }\r
172             else\r
173             {\r
174                 max = mid;\r
175             }\r
176         }\r
177 \r
178         logln(tz.getID() + " Before: " + showDate(min, tz));\r
179         logln(tz.getID() + " After:  " + showDate(max, tz));\r
180 \r
181         long mindelta = expectedBoundary - min;\r
182         // not used long maxdelta = max - expectedBoundary; \r
183         DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);\r
184         fmt.setTimeZone(tz);\r
185         if (mindelta >= 0 && mindelta <= INTERVAL &&\r
186             mindelta >= 0 && mindelta <= INTERVAL)\r
187             logln("PASS: Expected boundary at " + expectedBoundary + " = " + fmt.format(new Date(expectedBoundary)));\r
188         else\r
189             errln("FAIL: Expected boundary at " + expectedBoundary + " = " + fmt.format(new Date(expectedBoundary)));\r
190     }\r
191 \r
192     private static String showDate(long l)\r
193     {\r
194         return showDate(new Date(l));\r
195     }\r
196 \r
197     private static String showDate(Date d)\r
198     {\r
199         java.util.Calendar cal = java.util.Calendar.getInstance();\r
200         cal.setTime(d);\r
201         return "" + (cal.get(Calendar.YEAR) - 1900) + "/" + \r
202                showNN(cal.get(Calendar.MONTH) + 1) + "/" + \r
203                showNN(cal.get(Calendar.DAY_OF_MONTH)) + " " + \r
204                showNN(cal.get(Calendar.HOUR_OF_DAY)) + ":" \r
205                + showNN(cal.get(Calendar.MINUTE)) + " \"" + d + "\" = " +\r
206                d.getTime();\r
207     }\r
208 \r
209     private static String showDate(long l, TimeZone z)\r
210     {\r
211         return showDate(new Date(l), z);\r
212     }\r
213 \r
214     private static String showDate(Date d, TimeZone zone)\r
215     {\r
216         DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);\r
217         fmt.setTimeZone(zone);\r
218         java.util.Calendar cal = java.util.Calendar.getInstance();\r
219         cal.setTime(d);\r
220         return "" + (cal.get(Calendar.YEAR) - 1900) + "/" + \r
221                showNN(cal.get(Calendar.MONTH) + 1) + "/" + \r
222                showNN(cal.get(Calendar.DAY_OF_MONTH)) + " " + \r
223                showNN(cal.get(Calendar.HOUR_OF_DAY)) + ":" + \r
224                showNN(cal.get(Calendar.MINUTE)) + " \"" + d + "\" = " +\r
225                fmt.format(d) + " = " + d.getTime();\r
226     }\r
227 \r
228     private static String showNN(int n)\r
229     {\r
230         return ((n < 10) ? "0" : "") + n;\r
231     }\r
232 \r
233     /**\r
234      * Given a date, a TimeZone, and expected values for inDaylightTime,\r
235      * useDaylightTime, zone and DST offset, verify that this is the case.\r
236      */\r
237     void verifyDST(String tag, Calendar cal, TimeZone time_zone,\r
238                    boolean expUseDaylightTime, boolean expInDaylightTime,\r
239                    int expRawOffset, int expOffset)\r
240     {\r
241         Date d = cal.getTime();\r
242 \r
243         logln("-- " + tag + ": " + d +\r
244               " in zone " + time_zone.getID() + " (" +\r
245               d.getTime()/3600000.0 + ")");\r
246 \r
247         if (time_zone.inDaylightTime(d) == expInDaylightTime)\r
248             logln("PASS: inDaylightTime = " + time_zone.inDaylightTime(d));\r
249         else\r
250             errln("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d));\r
251 \r
252         if (time_zone.useDaylightTime() == expUseDaylightTime)\r
253             logln("PASS: useDaylightTime = " + time_zone.useDaylightTime());\r
254         else\r
255             errln("FAIL: useDaylightTime = " + time_zone.useDaylightTime());\r
256 \r
257         if (time_zone.getRawOffset() == expRawOffset)\r
258             logln("PASS: getRawOffset() = " + expRawOffset/(double)ONE_HOUR);\r
259         else\r
260             errln("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR +\r
261                   "; expected " + expRawOffset/(double)ONE_HOUR);\r
262 \r
263         //GregorianCalendar gc = new GregorianCalendar(time_zone);\r
264         //gc.setTime(d);\r
265         int offset = time_zone.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),\r
266                                          cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK),\r
267                                          ((cal.get(Calendar.HOUR_OF_DAY) * 60 +\r
268                                            cal.get(Calendar.MINUTE)) * 60 +\r
269                                           cal.get(Calendar.SECOND)) * 1000 +\r
270                                          cal.get(Calendar.MILLISECOND));\r
271         if (offset == expOffset)\r
272             logln("PASS: getOffset() = " + offset/(double)ONE_HOUR);\r
273         else {\r
274             logln("era=" + cal.get(Calendar.ERA) +\r
275                   ", year=" + cal.get(Calendar.YEAR) +\r
276                   ", month=" + cal.get(Calendar.MONTH) +\r
277                   ", dom=" + cal.get(Calendar.DAY_OF_MONTH) +\r
278                   ", dow=" + cal.get(Calendar.DAY_OF_WEEK) +\r
279                   ", time-of-day=" + (((cal.get(Calendar.HOUR_OF_DAY) * 60 +\r
280                                cal.get(Calendar.MINUTE)) * 60 +\r
281                               cal.get(Calendar.SECOND)) * 1000 +\r
282                              cal.get(Calendar.MILLISECOND)) / 3600000.0 +\r
283                             " hours");\r
284             errln("FAIL: getOffset() = " + offset/(double)ONE_HOUR +\r
285                   "; expected " + expOffset/(double)ONE_HOUR);\r
286         }\r
287     }\r
288 \r
289     /**\r
290      * Check that the given year/month/dom/hour maps to and from the\r
291      * given epochHours.  This verifies the functioning of the\r
292      * calendar and time zone in conjunction with one another,\r
293      * including the calendar time->fields and fields->time and\r
294      * the time zone getOffset method.\r
295      *\r
296      * @param epochHours hours after Jan 1 1970 0:00 GMT.\r
297      */\r
298     void verifyMapping(Calendar cal, int year, int month, int dom, int hour,\r
299                        double epochHours) {\r
300         double H = 3600000.0;\r
301         cal.clear();\r
302         cal.set(year, month, dom, hour, 0, 0);\r
303         Date d = cal.getTime();\r
304         double e = d.getTime() / H;\r
305         Date ed = new Date((long)(epochHours * H));\r
306         if (e == epochHours) {\r
307             logln("Ok: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +\r
308                   e + " (" + ed + ")");\r
309         } else {\r
310             errln("FAIL: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +\r
311                   e + " (" + new Date((long)(e * H)) + ")" +\r
312                   ", expected " + epochHours + " (" + ed + ")");\r
313         }\r
314         cal.setTime(ed);\r
315         if (cal.get(Calendar.YEAR) == year &&\r
316             cal.get(Calendar.MONTH) == month &&\r
317             cal.get(Calendar.DATE) == dom &&\r
318             cal.get(Calendar.MILLISECONDS_IN_DAY) == hour * 3600000) {\r
319             logln("Ok: " + epochHours + " (" + ed + ") => " +\r
320                   cal.get(Calendar.YEAR) + "/" +\r
321                   (cal.get(Calendar.MONTH)+1) + "/" +\r
322                   cal.get(Calendar.DATE) + " " +\r
323                   cal.get(Calendar.MILLISECONDS_IN_DAY)/H);\r
324         } else {\r
325             errln("FAIL: " + epochHours + " (" + ed + ") => " +\r
326                   cal.get(Calendar.YEAR) + "/" +\r
327                   (cal.get(Calendar.MONTH)+1) + "/" +\r
328                   cal.get(Calendar.DATE) + " " +\r
329                   cal.get(Calendar.MILLISECONDS_IN_DAY)/H +\r
330                   ", expected " + year + "/" + (month+1) + "/" + dom +\r
331                   " " + hour);\r
332         }\r
333     }\r
334 \r
335 // NOTE: Enable this code to check the behavior of the underlying JDK,\r
336 // using a JDK Calendar object.\r
337 //\r
338 //    int millisInDay(java.util.Calendar cal) {\r
339 //        return ((cal.get(Calendar.HOUR_OF_DAY) * 60 +\r
340 //                 cal.get(Calendar.MINUTE)) * 60 +\r
341 //                cal.get(Calendar.SECOND)) * 1000 +\r
342 //            cal.get(Calendar.MILLISECOND);\r
343 //    }\r
344 //\r
345 //    void verifyMapping(java.util.Calendar cal, int year, int month, int dom, int hour,\r
346 //                       double epochHours) {\r
347 //        cal.clear();\r
348 //        cal.set(year, month, dom, hour, 0, 0);\r
349 //        Date d = cal.getTime();\r
350 //        double e = d.getTime() / 3600000.0;\r
351 //        Date ed = new Date((long)(epochHours * 3600000));\r
352 //        if (e == epochHours) {\r
353 //            logln("Ok: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +\r
354 //                  e + " (" + ed + ")");\r
355 //        } else {\r
356 //            errln("FAIL: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +\r
357 //                  e + " (" + new Date((long)(e * 3600000)) + ")" +\r
358 //                  ", expected " + epochHours + " (" + ed + ")");\r
359 //        }\r
360 //        cal.setTime(ed);\r
361 //        if (cal.get(Calendar.YEAR) == year &&\r
362 //            cal.get(Calendar.MONTH) == month &&\r
363 //            cal.get(Calendar.DATE) == dom &&\r
364 //            millisInDay(cal) == hour * 3600000) {\r
365 //            logln("Ok: " + epochHours + " (" + ed + ") => " +\r
366 //                  cal.get(Calendar.YEAR) + "/" +\r
367 //                  (cal.get(Calendar.MONTH)+1) + "/" +\r
368 //                  cal.get(Calendar.DATE) + " " +\r
369 //                  millisInDay(cal)/3600000.0);\r
370 //        } else {\r
371 //            errln("FAIL: " + epochHours + " (" + ed + ") => " +\r
372 //                  cal.get(Calendar.YEAR) + "/" +\r
373 //                  (cal.get(Calendar.MONTH)+1) + "/" +\r
374 //                  cal.get(Calendar.DATE) + " " +\r
375 //                  millisInDay(cal)/3600000.0 +\r
376 //                  ", expected " + year + "/" + (month+1) + "/" + dom +\r
377 //                  " " + hour);\r
378 //        }\r
379 //    }\r
380 \r
381     public void TestBoundaries()\r
382     {\r
383         TimeZone save = TimeZone.getDefault();\r
384 \r
385         // Check basic mappings.  We had a problem with this for ICU\r
386         // 2.8 after migrating to using pass-through time zones.  The\r
387         // problem appeared only on JDK 1.3.\r
388         TimeZone pst = safeGetTimeZone("PST");\r
389         Calendar tempcal = Calendar.getInstance(pst);\r
390         verifyMapping(tempcal, 1997, Calendar.APRIL, 3,  0, 238904.0);\r
391         verifyMapping(tempcal, 1997, Calendar.APRIL, 4,  0, 238928.0);\r
392         verifyMapping(tempcal, 1997, Calendar.APRIL, 5,  0, 238952.0);\r
393         verifyMapping(tempcal, 1997, Calendar.APRIL, 5, 23, 238975.0);\r
394         verifyMapping(tempcal, 1997, Calendar.APRIL, 6,  0, 238976.0);\r
395         verifyMapping(tempcal, 1997, Calendar.APRIL, 6,  1, 238977.0);\r
396         verifyMapping(tempcal, 1997, Calendar.APRIL, 6,  3, 238978.0);\r
397         \r
398         TimeZone utc = safeGetTimeZone("UTC");\r
399         Calendar utccal = Calendar.getInstance(utc);\r
400         verifyMapping(utccal, 1997, Calendar.APRIL, 6, 0, 238968.0);\r
401 \r
402 // NOTE: Enable this code to check the behavior of the underlying JDK,\r
403 // using a JDK Calendar object.\r
404 //\r
405 //        java.util.TimeZone jdkpst = java.util.TimeZone.getTimeZone("PST");\r
406 //        java.util.Calendar jdkcal = java.util.Calendar.getInstance(jdkpst);\r
407 //        verifyMapping(jdkcal, 1997, Calendar.APRIL, 5,  0, 238952.0);\r
408 //        verifyMapping(jdkcal, 1997, Calendar.APRIL, 5, 23, 238975.0);\r
409 //        verifyMapping(jdkcal, 1997, Calendar.APRIL, 6,  0, 238976.0);\r
410 //        verifyMapping(jdkcal, 1997, Calendar.APRIL, 6,  1, 238977.0);\r
411 //        verifyMapping(jdkcal, 1997, Calendar.APRIL, 6,  3, 238978.0);\r
412 \r
413         tempcal.clear();\r
414         tempcal.set(1997, Calendar.APRIL, 6);\r
415         Date d = tempcal.getTime();\r
416 \r
417         try {\r
418             TimeZone.setDefault(pst);\r
419 \r
420             // DST changeover for PST is 4/6/1997 at 2 hours past midnight\r
421             // at 238978.0 epoch hours.\r
422 \r
423             // i is minutes past midnight standard time\r
424             for (int i=-120; i<=180; i+=60)\r
425             {\r
426                 boolean inDST = (i >= 120);\r
427                 tempcal.setTimeInMillis(d.getTime() + i*60*1000);\r
428                 verifyDST("hour=" + i/60,\r
429                           tempcal, pst, true, inDST, -8*ONE_HOUR,\r
430                           inDST ? -7*ONE_HOUR : -8*ONE_HOUR);\r
431             }\r
432         } finally {\r
433             TimeZone.setDefault(save);\r
434         }\r
435 \r
436         // We no longer use ICU TimeZone implementation for Java\r
437         // default TimeZone.  Java 1.3 or older version do not\r
438         // support historic transitions, therefore, the test below\r
439         // will fail on such environment (with the latest TimeZone\r
440         // patch for US 2007+ rule).\r
441         String javaver = System.getProperty("java.version", "1.3");\r
442         if (!javaver.startsWith("1.3"))\r
443         {\r
444             // This only works in PST/PDT\r
445             TimeZone.setDefault(safeGetTimeZone("PST"));\r
446             logln("========================================");\r
447             tempcal.set(1997, 0, 1);\r
448             findDaylightBoundaryUsingDate(tempcal.getTime(), "PST", PST_1997_BEG);\r
449             logln("========================================");\r
450             tempcal.set(1997, 6, 1);\r
451             findDaylightBoundaryUsingDate(tempcal.getTime(), "PDT", PST_1997_END);\r
452         }\r
453 \r
454         //  if (true)\r
455         //  {\r
456         //      logln("========================================");\r
457         //      findDaylightBoundaryUsingCalendar(new Date(97,0,1), false);\r
458         //      logln("========================================");\r
459         //      findDaylightBoundaryUsingCalendar(new Date(97,6,1), true);\r
460         //  }\r
461 \r
462         if (true)\r
463         {\r
464             // Southern hemisphere test\r
465             logln("========================================");\r
466             TimeZone z = safeGetTimeZone(AUSTRALIA);\r
467             tempcal.set(1997, 0, 1);\r
468             findDaylightBoundaryUsingTimeZone(tempcal.getTime(), true, AUSTRALIA_1997_END, z);\r
469             logln("========================================");\r
470             tempcal.set(1997, 6, 1);\r
471             findDaylightBoundaryUsingTimeZone(tempcal.getTime(), false, AUSTRALIA_1997_BEG, z);\r
472         }\r
473 \r
474         if (true)\r
475         {\r
476             logln("========================================");\r
477             tempcal.set(1997, 0, 1);\r
478             findDaylightBoundaryUsingTimeZone(tempcal.getTime(), false, PST_1997_BEG);\r
479             logln("========================================");\r
480             tempcal.set(1997, 6, 1);\r
481             findDaylightBoundaryUsingTimeZone(tempcal.getTime(), true, PST_1997_END);\r
482         }\r
483 \r
484         // This just shows the offset for April 4-7 in 1997.  This is redundant\r
485         // with a test above, so we disable it.\r
486         if (false)\r
487         {\r
488             TimeZone z = TimeZone.getDefault();\r
489             tempcal.set(1997, 3, 4);\r
490             logln(z.getOffset(1, 97, 3, 4, 6, 0) + " " + tempcal.getTime());\r
491             tempcal.set(1997, 3, 5);\r
492             logln(z.getOffset(1, 97, 3, 5, 7, 0) + " " + tempcal.getTime());\r
493             tempcal.set(1997, 3, 6);\r
494             logln(z.getOffset(1, 97, 3, 6, 1, 0) + " " + tempcal.getTime());\r
495             tempcal.set(1997, 3, 7);\r
496             logln(z.getOffset(1, 97, 3, 7, 2, 0) + " " + tempcal.getTime());\r
497         }\r
498     }\r
499 \r
500 \r
501     //----------------------------------------------------------------------\r
502     // Can't do any of these without a public inDaylightTime in GC\r
503     //----------------------------------------------------------------------\r
504 \r
505 \r
506     //    static GregorianCalendar cal = new GregorianCalendar();\r
507     //\r
508     //    static void _testUsingBinarySearch(Date d, boolean startsInDST)\r
509     //    {\r
510     //  // Given a date with a year start, find the Daylight onset\r
511     //  // and end.  The given date should be 1/1/xx in some year.\r
512     //\r
513     //  // Use a binary search, assuming that we have a Standard\r
514     //  // time at the midpoint.\r
515     //  long min = d.getTime();\r
516     //  long max = min + (long)(365.25 / 2 * ONE_DAY);\r
517     //\r
518     //  // First check the max\r
519     //  cal.setTime(new Date(max));\r
520     //  if (cal.inDaylightTime() == startsInDST)\r
521     //  {\r
522     //      logln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));\r
523     //  }\r
524     //\r
525     //  cal.setTime(d);\r
526     //  if (cal.inDaylightTime() != startsInDST)\r
527     //  {\r
528     //      logln("Error: inDaylightTime(" + d + ") != " + startsInDST);\r
529     //  }\r
530     //\r
531     //  while ((max - min) >  INTERVAL)\r
532     //  {\r
533     //      long mid = (min + max) >> 1;\r
534     //      cal.setTime(new Date(mid));\r
535     //      if (cal.inDaylightTime() == startsInDST)\r
536     //      {\r
537     //      min = mid;\r
538     //      }\r
539     //      else\r
540     //      {\r
541     //      max = mid;\r
542     //      }\r
543     //  }\r
544     //\r
545     //  logln("Binary Search Before: " + showDate(min));\r
546     //  logln("Binary Search After:  " + showDate(max));\r
547     //    }\r
548     //\r
549     //    static void _testUsingMillis(Date d, boolean startsInDST)\r
550     //    {\r
551     //  long millis = d.getTime();\r
552     //  long max = millis + (long)(370 * ONE_DAY); // A year plus extra\r
553     //\r
554     //  boolean lastDST = startsInDST;\r
555     //  while (millis < max)\r
556     //  {\r
557     //      cal.setTime(new Date(millis));\r
558     //      boolean inDaylight = cal.inDaylightTime();\r
559     //\r
560     //      if (inDaylight != lastDST)\r
561     //      {\r
562     //      logln("Switch " + (inDaylight ? "into" : "out of")\r
563     //                 + " DST at " + (new Date(millis)));\r
564     //      lastDST = inDaylight;\r
565     //      }\r
566     //\r
567     //      millis += 15*ONE_MINUTE;\r
568     //  }\r
569     //    }\r
570     //\r
571     //    static void _testUsingFields(int y, boolean startsInDST)\r
572     //    {\r
573     //  boolean lastDST = startsInDST;\r
574     //  for (int m = 0; m < 12; ++m)\r
575     //  {\r
576     //      for (int d = 1; d <= MONTH_LENGTH[m]; ++d)\r
577     //      {\r
578     //      for (int h = 0; h < 24; ++h)\r
579     //      {\r
580     //          for (int min = 0; min < 60; min += 15)\r
581     //          {\r
582     //          cal.clear();\r
583     //          cal.set(y, m, d, h, min);\r
584     //          boolean inDaylight = cal.inDaylightTime();\r
585     //          if (inDaylight != lastDST)\r
586     //          {\r
587     //              lastDST = inDaylight;\r
588     //              log("Switch " + (lastDST ? "into" : "out of")\r
589     //                       + " DST at " + y + "/" + (m+1) + "/" + d\r
590     //                       + " " + showNN(h) + ":" + showNN(min));\r
591     //              logln(" " + cal.getTime());\r
592     //\r
593     //              cal.set(y, m, d, h-1, 45);\r
594     //              log("Before = "\r
595     //+ y + "/" + (m+1) + "/" + d\r
596     //+ " " + showNN(h-1) + ":" + showNN(45));\r
597     //              logln(" " + cal.getTime());\r
598     //          }\r
599     //          }\r
600     //      }\r
601     //      }\r
602     //  }\r
603     //    }\r
604     //\r
605     //    public void Test1()\r
606     //    {\r
607     //  logln(Locale.getDefault().getDisplayName());\r
608     //  logln(TimeZone.getDefault().getID());\r
609     //  logln(new Date(0));\r
610     //\r
611     //  if (true)\r
612     //  {\r
613     //      logln("========================================");\r
614     //      _testUsingBinarySearch(new Date(97,0,1), false);\r
615     //      logln("========================================");\r
616     //      _testUsingBinarySearch(new Date(97,6,1), true);\r
617     //  }\r
618     //\r
619     //  if (true)\r
620     //  {\r
621     //      logln("========================================");\r
622     //      logln("Stepping using millis");\r
623     //      _testUsingMillis(new Date(97,0,1), false);\r
624     //  }\r
625     //\r
626     //  if (true)\r
627     //  {\r
628     //      logln("========================================");\r
629     //      logln("Stepping using fields");\r
630     //      _testUsingFields(1997, false);\r
631     //  }\r
632     //\r
633     //  if (false)\r
634     //  {\r
635     //      cal.clear();\r
636     //      cal.set(1997, 3, 5, 10, 0);\r
637     //      //  cal.inDaylightTime();\r
638     //      logln("Date = " + cal.getTime());\r
639     //      logln("Millis = " + cal.getTime().getTime()/3600000);\r
640     //  }\r
641     //    }\r
642 \r
643     //----------------------------------------------------------------------\r
644     //----------------------------------------------------------------------\r
645     //----------------------------------------------------------------------\r
646 \r
647     void _testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary)\r
648     {\r
649         // Given a date with a year start, find the Daylight onset\r
650         // and end.  The given date should be 1/1/xx in some year.\r
651 \r
652         // Use a binary search, assuming that we have a Standard\r
653         // time at the midpoint.\r
654         long min = d.getTime();\r
655         long max = min + (long)(365.25 / 2 * ONE_DAY);\r
656 \r
657         // First check the boundaries\r
658         boolean startsInDST = tz.inDaylightTime(d);\r
659 \r
660         if (tz.inDaylightTime(new Date(max)) == startsInDST)\r
661         {\r
662             errln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));\r
663         }\r
664 \r
665         while ((max - min) >  INTERVAL)\r
666         {\r
667             long mid = (min + max) >> 1;\r
668             if (tz.inDaylightTime(new Date(mid)) == startsInDST)\r
669             {\r
670                 min = mid;\r
671             }\r
672             else\r
673             {\r
674                 max = mid;\r
675             }\r
676         }\r
677 \r
678         logln("Binary Search Before: " + showDate(min));\r
679         logln("Binary Search After:  " + showDate(max));\r
680 \r
681         long mindelta = expectedBoundary - min;\r
682         // not used long maxdelta = max - expectedBoundary;\r
683         if (mindelta >= 0 && mindelta <= INTERVAL &&\r
684             mindelta >= 0 && mindelta <= INTERVAL)\r
685             logln("PASS: Expected boundary at " + expectedBoundary);\r
686         else\r
687             errln("FAIL: Expected boundary at " + expectedBoundary);\r
688     }\r
689 \r
690     /*\r
691       static void _testUsingMillis(Date d, boolean startsInDST)\r
692       {\r
693       long millis = d.getTime();\r
694       long max = millis + (long)(370 * ONE_DAY); // A year plus extra\r
695 \r
696       boolean lastDST = startsInDST;\r
697       while (millis < max)\r
698       {\r
699       cal.setTime(new Date(millis));\r
700       boolean inDaylight = cal.inDaylightTime();\r
701 \r
702       if (inDaylight != lastDST)\r
703       {\r
704       logln("Switch " + (inDaylight ? "into" : "out of")\r
705       + " DST at " + (new Date(millis)));\r
706       lastDST = inDaylight;\r
707       }\r
708 \r
709       millis += 15*ONE_MINUTE;\r
710       }\r
711       }\r
712       */\r
713 \r
714     /**\r
715      * Test new rule formats.\r
716      */\r
717     public void TestNewRules()\r
718     {\r
719         //logln(Locale.getDefault().getDisplayName());\r
720         //logln(TimeZone.getDefault().getID());\r
721         //logln(new Date(0));\r
722 \r
723         if (true)\r
724         {\r
725             // Doesn't matter what the default TimeZone is here, since we\r
726             // are creating our own TimeZone objects.\r
727 \r
728             SimpleTimeZone tz;\r
729             java.util.Calendar tempcal = java.util.Calendar.getInstance();\r
730             tempcal.clear();\r
731 \r
732             logln("-----------------------------------------------------------------");\r
733             logln("Aug 2ndTues .. Mar 15");\r
734             tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1",\r
735                                     Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR,\r
736                                     Calendar.MARCH, 15, 0, 2*ONE_HOUR);\r
737             //logln(tz.toString());\r
738             logln("========================================");\r
739             tempcal.set(1997, 0, 1);\r
740             _testUsingBinarySearch(tz, tempcal.getTime(), 858416400000L);\r
741             logln("========================================");\r
742             tempcal.set(1997, 6, 1);\r
743             _testUsingBinarySearch(tz, tempcal.getTime(), 871380000000L);\r
744 \r
745             logln("-----------------------------------------------------------------");\r
746             logln("Apr Wed>=14 .. Sep Sun<=20");\r
747             tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2",\r
748                                     Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR,\r
749                                     Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR);\r
750             //logln(tz.toString());\r
751             logln("========================================");\r
752             tempcal.set(1997, 0, 1);\r
753             _testUsingBinarySearch(tz, tempcal.getTime(), 861184800000L);\r
754             logln("========================================");\r
755             tempcal.set(1997, 6, 1);\r
756             _testUsingBinarySearch(tz, tempcal.getTime(), 874227600000L);\r
757         }\r
758 \r
759         /*\r
760           if (true)\r
761           {\r
762           logln("========================================");\r
763           logln("Stepping using millis");\r
764           _testUsingMillis(new Date(97,0,1), false);\r
765           }\r
766 \r
767           if (true)\r
768           {\r
769           logln("========================================");\r
770           logln("Stepping using fields");\r
771           _testUsingFields(1997, false);\r
772           }\r
773 \r
774           if (false)\r
775           {\r
776           cal.clear();\r
777           cal.set(1997, 3, 5, 10, 0);\r
778           //    cal.inDaylightTime();\r
779           logln("Date = " + cal.getTime());\r
780           logln("Millis = " + cal.getTime().getTime()/3600000);\r
781           }\r
782           */\r
783     }\r
784 \r
785     //----------------------------------------------------------------------\r
786     //----------------------------------------------------------------------\r
787     //----------------------------------------------------------------------\r
788     // Long Bug\r
789     //----------------------------------------------------------------------\r
790     //----------------------------------------------------------------------\r
791     //----------------------------------------------------------------------\r
792 \r
793     //public void Test3()\r
794     //{\r
795     //    findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true);\r
796     //}\r
797 \r
798     /**\r
799      * Find boundaries by stepping.\r
800      */\r
801     void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges)\r
802     {\r
803         java.util.Calendar tempcal = java.util.Calendar.getInstance();\r
804         tempcal.clear();\r
805         tempcal.set(year, Calendar.JANUARY, 1);\r
806         Date d = tempcal.getTime();\r
807         long time = d.getTime(); // ms\r
808         long limit = time + ONE_YEAR + ONE_DAY;\r
809         boolean lastState = z.inDaylightTime(d);\r
810         int changes = 0;\r
811         logln("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState);\r
812         logln("useDaylightTime = " + z.useDaylightTime());\r
813         while (time < limit)\r
814         {\r
815             d.setTime(time);\r
816             boolean state = z.inDaylightTime(d);\r
817             if (state != lastState)\r
818             {\r
819                 logln((state ? "Entry " : "Exit ") +\r
820                       "at " + d);\r
821                 lastState = state;\r
822                 ++changes;\r
823             }\r
824             time += interval;\r
825         }\r
826         if (changes == 0)\r
827         {\r
828             if (!lastState && !z.useDaylightTime()) logln("No DST");\r
829             else errln("FAIL: DST all year, or no DST with true useDaylightTime");\r
830         }\r
831         else if (changes != 2)\r
832         {\r
833             errln("FAIL: " + changes + " changes seen; should see 0 or 2");\r
834         }\r
835         else if (!z.useDaylightTime())\r
836         {\r
837             errln("FAIL: useDaylightTime false but 2 changes seen");\r
838         }\r
839         if (changes != expectedChanges)\r
840         {\r
841             errln("FAIL: " + changes + " changes seen; expected " + expectedChanges);\r
842         }\r
843     }\r
844 \r
845     public void TestStepwise()\r
846     {\r
847         findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("America/New_York"), 2);\r
848         // disabled Oct 2003 aliu; ACT could mean anything, depending on the underlying JDK, as of 2.8\r
849         // findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("ACT"), 2);\r
850         findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("America/Phoenix"), 0); // Added 3Jan01\r
851         findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone(AUSTRALIA), 2);\r
852     }\r
853 }\r