2 *******************************************************************************
3 * Copyright (C) 2000-2010, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.dev.test.timezone;
10 import com.ibm.icu.dev.test.TestFmwk;
11 import com.ibm.icu.text.DateFormat;
12 import com.ibm.icu.util.Calendar;
13 import com.ibm.icu.util.SimpleTimeZone;
14 import com.ibm.icu.util.TimeZone;
17 * A test which discovers the boundaries of DST programmatically and verifies
18 * that they are correct.
20 public class TimeZoneBoundaryTest extends TestFmwk
22 static final int ONE_SECOND = 1000;
23 static final int ONE_MINUTE = 60*ONE_SECOND;
24 static final int ONE_HOUR = 60*ONE_MINUTE;
25 static final long ONE_DAY = 24*ONE_HOUR;
26 static final long ONE_YEAR = (long)(365.25 * ONE_DAY);
27 static final long SIX_MONTHS = ONE_YEAR / 2;
29 static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
31 // These values are empirically determined to be correct
32 static final long PST_1997_BEG = 860320800000L;
33 static final long PST_1997_END = 877856400000L;
35 // Minimum interval for binary searches in ms; should be no larger
37 static final long INTERVAL = 10; // Milliseconds
39 // [3Jan01 Liu] Updated for 2000f data
40 static final String AUSTRALIA = "Australia/Adelaide";
41 static final long AUSTRALIA_1997_BEG = 877797000000L;
42 static final long AUSTRALIA_1997_END = 859653000000L;
44 public static void main(String[] args) throws Exception {
45 new TimeZoneBoundaryTest().run(args);
49 * Date.toString().substring() Boundary Test
50 * Look for a DST changeover to occur within 6 months of the given Date.
51 * The initial Date.toString() should yield a string containing the
52 * startMode as a SUBSTRING. The boundary will be tested to be
53 * at the expectedBoundary value.
55 void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary)
57 // Given a date with a year start, find the Daylight onset
58 // and end. The given date should be 1/1/xx in some year.
60 if (d.toString().indexOf(startMode) == -1)
62 logln("Error: " + startMode + " not present in " + d);
65 // Use a binary search, assuming that we have a Standard
66 // time at the midpoint.
67 long min = d.getTime();
68 long max = min + SIX_MONTHS;
70 while ((max - min) > INTERVAL)
72 long mid = (min + max) >> 1;
73 String s = new Date(mid).toString();
75 if (s.indexOf(startMode) != -1)
85 logln("Date Before: " + showDate(min));
86 logln("Date After: " + showDate(max));
87 long mindelta = expectedBoundary - min;
88 // not used long maxdelta = max - expectedBoundary;
89 if (mindelta >= 0 && mindelta <= INTERVAL &&
90 mindelta >= 0 && mindelta <= INTERVAL)
91 logln("PASS: Expected boundary at " + expectedBoundary);
93 errln("FAIL: Expected boundary at " + expectedBoundary);
96 // This test cannot be compiled until the inDaylightTime() method of GregorianCalendar
98 // static void findDaylightBoundaryUsingCalendar(Date d, boolean startsInDST)
100 // // Given a date with a year start, find the Daylight onset
101 // // and end. The given date should be 1/1/xx in some year.
103 // GregorianCalendar cal = new GregorianCalendar();
105 // if (cal.inDaylightTime() != startsInDST)
107 // logln("Error: inDaylightTime(" + d + ") != " + startsInDST);
110 // // Use a binary search, assuming that we have a Standard
111 // // time at the midpoint.
112 // long min = d.getTime();
113 // long max = min + (long)(365.25 / 2 * 24*60*60*1000);
115 // while ((max - min) > INTERVAL)
117 // long mid = (min + max) >> 1;
118 // cal.setTime(new Date(mid));
119 // if (cal.inDaylightTime() == startsInDST)
129 // logln("Calendar Before: " + showDate(min));
130 // logln("Calendar After: " + showDate(max));
133 void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary)
135 findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary,
136 TimeZone.getDefault());
139 void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST,
140 long expectedBoundary, TimeZone tz)
142 // Given a date with a year start, find the Daylight onset
143 // and end. The given date should be 1/1/xx in some year.
145 // Use a binary search, assuming that we have a Standard
146 // time at the midpoint.
147 long min = d.getTime();
148 long max = min + SIX_MONTHS;
150 if (tz.inDaylightTime(d) != startsInDST)
152 errln("FAIL: " + tz.getID() + " inDaylightTime(" +
153 d + ") != " + startsInDST);
154 startsInDST = !startsInDST; // Flip over; find the apparent value
157 if (tz.inDaylightTime(new Date(max)) == startsInDST)
159 errln("FAIL: " + tz.getID() + " inDaylightTime(" +
160 (new Date(max)) + ") != " + (!startsInDST));
164 while ((max - min) > INTERVAL)
166 long mid = (min + max) >> 1;
167 boolean isIn = tz.inDaylightTime(new Date(mid));
168 if (isIn == startsInDST)
178 logln(tz.getID() + " Before: " + showDate(min, tz));
179 logln(tz.getID() + " After: " + showDate(max, tz));
181 long mindelta = expectedBoundary - min;
182 // not used long maxdelta = max - expectedBoundary;
183 DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
185 if (mindelta >= 0 && mindelta <= INTERVAL &&
186 mindelta >= 0 && mindelta <= INTERVAL)
187 logln("PASS: Expected boundary at " + expectedBoundary + " = " + fmt.format(new Date(expectedBoundary)));
189 errln("FAIL: Expected boundary at " + expectedBoundary + " = " + fmt.format(new Date(expectedBoundary)));
192 private static String showDate(long l)
194 return showDate(new Date(l));
197 private static String showDate(Date d)
199 java.util.Calendar cal = java.util.Calendar.getInstance();
201 return "" + (cal.get(Calendar.YEAR) - 1900) + "/" +
202 showNN(cal.get(Calendar.MONTH) + 1) + "/" +
203 showNN(cal.get(Calendar.DAY_OF_MONTH)) + " " +
204 showNN(cal.get(Calendar.HOUR_OF_DAY)) + ":"
205 + showNN(cal.get(Calendar.MINUTE)) + " \"" + d + "\" = " +
209 private static String showDate(long l, TimeZone z)
211 return showDate(new Date(l), z);
214 private static String showDate(Date d, TimeZone zone)
216 DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
217 fmt.setTimeZone(zone);
218 java.util.Calendar cal = java.util.Calendar.getInstance();
220 return "" + (cal.get(Calendar.YEAR) - 1900) + "/" +
221 showNN(cal.get(Calendar.MONTH) + 1) + "/" +
222 showNN(cal.get(Calendar.DAY_OF_MONTH)) + " " +
223 showNN(cal.get(Calendar.HOUR_OF_DAY)) + ":" +
224 showNN(cal.get(Calendar.MINUTE)) + " \"" + d + "\" = " +
225 fmt.format(d) + " = " + d.getTime();
228 private static String showNN(int n)
230 return ((n < 10) ? "0" : "") + n;
234 * Given a date, a TimeZone, and expected values for inDaylightTime,
235 * useDaylightTime, zone and DST offset, verify that this is the case.
237 void verifyDST(String tag, Calendar cal, TimeZone time_zone,
238 boolean expUseDaylightTime, boolean expInDaylightTime,
239 int expRawOffset, int expOffset)
241 Date d = cal.getTime();
243 logln("-- " + tag + ": " + d +
244 " in zone " + time_zone.getID() + " (" +
245 d.getTime()/3600000.0 + ")");
247 if (time_zone.inDaylightTime(d) == expInDaylightTime)
248 logln("PASS: inDaylightTime = " + time_zone.inDaylightTime(d));
250 errln("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d));
252 if (time_zone.useDaylightTime() == expUseDaylightTime)
253 logln("PASS: useDaylightTime = " + time_zone.useDaylightTime());
255 errln("FAIL: useDaylightTime = " + time_zone.useDaylightTime());
257 if (time_zone.getRawOffset() == expRawOffset)
258 logln("PASS: getRawOffset() = " + expRawOffset/(double)ONE_HOUR);
260 errln("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR +
261 "; expected " + expRawOffset/(double)ONE_HOUR);
263 //GregorianCalendar gc = new GregorianCalendar(time_zone);
265 int offset = time_zone.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH),
266 cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK),
267 ((cal.get(Calendar.HOUR_OF_DAY) * 60 +
268 cal.get(Calendar.MINUTE)) * 60 +
269 cal.get(Calendar.SECOND)) * 1000 +
270 cal.get(Calendar.MILLISECOND));
271 if (offset == expOffset)
272 logln("PASS: getOffset() = " + offset/(double)ONE_HOUR);
274 logln("era=" + cal.get(Calendar.ERA) +
275 ", year=" + cal.get(Calendar.YEAR) +
276 ", month=" + cal.get(Calendar.MONTH) +
277 ", dom=" + cal.get(Calendar.DAY_OF_MONTH) +
278 ", dow=" + cal.get(Calendar.DAY_OF_WEEK) +
279 ", time-of-day=" + (((cal.get(Calendar.HOUR_OF_DAY) * 60 +
280 cal.get(Calendar.MINUTE)) * 60 +
281 cal.get(Calendar.SECOND)) * 1000 +
282 cal.get(Calendar.MILLISECOND)) / 3600000.0 +
284 errln("FAIL: getOffset() = " + offset/(double)ONE_HOUR +
285 "; expected " + expOffset/(double)ONE_HOUR);
290 * Check that the given year/month/dom/hour maps to and from the
291 * given epochHours. This verifies the functioning of the
292 * calendar and time zone in conjunction with one another,
293 * including the calendar time->fields and fields->time and
294 * the time zone getOffset method.
296 * @param epochHours hours after Jan 1 1970 0:00 GMT.
298 void verifyMapping(Calendar cal, int year, int month, int dom, int hour,
300 double H = 3600000.0;
302 cal.set(year, month, dom, hour, 0, 0);
303 Date d = cal.getTime();
304 double e = d.getTime() / H;
305 Date ed = new Date((long)(epochHours * H));
306 if (e == epochHours) {
307 logln("Ok: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
308 e + " (" + ed + ")");
310 errln("FAIL: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
311 e + " (" + new Date((long)(e * H)) + ")" +
312 ", expected " + epochHours + " (" + ed + ")");
315 if (cal.get(Calendar.YEAR) == year &&
316 cal.get(Calendar.MONTH) == month &&
317 cal.get(Calendar.DATE) == dom &&
318 cal.get(Calendar.MILLISECONDS_IN_DAY) == hour * 3600000) {
319 logln("Ok: " + epochHours + " (" + ed + ") => " +
320 cal.get(Calendar.YEAR) + "/" +
321 (cal.get(Calendar.MONTH)+1) + "/" +
322 cal.get(Calendar.DATE) + " " +
323 cal.get(Calendar.MILLISECONDS_IN_DAY)/H);
325 errln("FAIL: " + epochHours + " (" + ed + ") => " +
326 cal.get(Calendar.YEAR) + "/" +
327 (cal.get(Calendar.MONTH)+1) + "/" +
328 cal.get(Calendar.DATE) + " " +
329 cal.get(Calendar.MILLISECONDS_IN_DAY)/H +
330 ", expected " + year + "/" + (month+1) + "/" + dom +
335 // NOTE: Enable this code to check the behavior of the underlying JDK,
336 // using a JDK Calendar object.
338 // int millisInDay(java.util.Calendar cal) {
339 // return ((cal.get(Calendar.HOUR_OF_DAY) * 60 +
340 // cal.get(Calendar.MINUTE)) * 60 +
341 // cal.get(Calendar.SECOND)) * 1000 +
342 // cal.get(Calendar.MILLISECOND);
345 // void verifyMapping(java.util.Calendar cal, int year, int month, int dom, int hour,
346 // double epochHours) {
348 // cal.set(year, month, dom, hour, 0, 0);
349 // Date d = cal.getTime();
350 // double e = d.getTime() / 3600000.0;
351 // Date ed = new Date((long)(epochHours * 3600000));
352 // if (e == epochHours) {
353 // logln("Ok: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
354 // e + " (" + ed + ")");
356 // errln("FAIL: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " +
357 // e + " (" + new Date((long)(e * 3600000)) + ")" +
358 // ", expected " + epochHours + " (" + ed + ")");
361 // if (cal.get(Calendar.YEAR) == year &&
362 // cal.get(Calendar.MONTH) == month &&
363 // cal.get(Calendar.DATE) == dom &&
364 // millisInDay(cal) == hour * 3600000) {
365 // logln("Ok: " + epochHours + " (" + ed + ") => " +
366 // cal.get(Calendar.YEAR) + "/" +
367 // (cal.get(Calendar.MONTH)+1) + "/" +
368 // cal.get(Calendar.DATE) + " " +
369 // millisInDay(cal)/3600000.0);
371 // errln("FAIL: " + epochHours + " (" + ed + ") => " +
372 // cal.get(Calendar.YEAR) + "/" +
373 // (cal.get(Calendar.MONTH)+1) + "/" +
374 // cal.get(Calendar.DATE) + " " +
375 // millisInDay(cal)/3600000.0 +
376 // ", expected " + year + "/" + (month+1) + "/" + dom +
381 public void TestBoundaries()
383 TimeZone save = TimeZone.getDefault();
385 // Check basic mappings. We had a problem with this for ICU
386 // 2.8 after migrating to using pass-through time zones. The
387 // problem appeared only on JDK 1.3.
388 TimeZone pst = safeGetTimeZone("PST");
389 Calendar tempcal = Calendar.getInstance(pst);
390 verifyMapping(tempcal, 1997, Calendar.APRIL, 3, 0, 238904.0);
391 verifyMapping(tempcal, 1997, Calendar.APRIL, 4, 0, 238928.0);
392 verifyMapping(tempcal, 1997, Calendar.APRIL, 5, 0, 238952.0);
393 verifyMapping(tempcal, 1997, Calendar.APRIL, 5, 23, 238975.0);
394 verifyMapping(tempcal, 1997, Calendar.APRIL, 6, 0, 238976.0);
395 verifyMapping(tempcal, 1997, Calendar.APRIL, 6, 1, 238977.0);
396 verifyMapping(tempcal, 1997, Calendar.APRIL, 6, 3, 238978.0);
398 TimeZone utc = safeGetTimeZone("UTC");
399 Calendar utccal = Calendar.getInstance(utc);
400 verifyMapping(utccal, 1997, Calendar.APRIL, 6, 0, 238968.0);
402 // NOTE: Enable this code to check the behavior of the underlying JDK,
403 // using a JDK Calendar object.
405 // java.util.TimeZone jdkpst = java.util.TimeZone.getTimeZone("PST");
406 // java.util.Calendar jdkcal = java.util.Calendar.getInstance(jdkpst);
407 // verifyMapping(jdkcal, 1997, Calendar.APRIL, 5, 0, 238952.0);
408 // verifyMapping(jdkcal, 1997, Calendar.APRIL, 5, 23, 238975.0);
409 // verifyMapping(jdkcal, 1997, Calendar.APRIL, 6, 0, 238976.0);
410 // verifyMapping(jdkcal, 1997, Calendar.APRIL, 6, 1, 238977.0);
411 // verifyMapping(jdkcal, 1997, Calendar.APRIL, 6, 3, 238978.0);
414 tempcal.set(1997, Calendar.APRIL, 6);
415 Date d = tempcal.getTime();
418 TimeZone.setDefault(pst);
420 // DST changeover for PST is 4/6/1997 at 2 hours past midnight
421 // at 238978.0 epoch hours.
423 // i is minutes past midnight standard time
424 for (int i=-120; i<=180; i+=60)
426 boolean inDST = (i >= 120);
427 tempcal.setTimeInMillis(d.getTime() + i*60*1000);
428 verifyDST("hour=" + i/60,
429 tempcal, pst, true, inDST, -8*ONE_HOUR,
430 inDST ? -7*ONE_HOUR : -8*ONE_HOUR);
433 TimeZone.setDefault(save);
436 // We no longer use ICU TimeZone implementation for Java
437 // default TimeZone. Java 1.3 or older version do not
438 // support historic transitions, therefore, the test below
439 // will fail on such environment (with the latest TimeZone
440 // patch for US 2007+ rule).
441 String javaver = System.getProperty("java.version", "1.3");
442 if (!javaver.startsWith("1.3"))
444 // This only works in PST/PDT
445 TimeZone.setDefault(safeGetTimeZone("PST"));
446 logln("========================================");
447 tempcal.set(1997, 0, 1);
448 findDaylightBoundaryUsingDate(tempcal.getTime(), "PST", PST_1997_BEG);
449 logln("========================================");
450 tempcal.set(1997, 6, 1);
451 findDaylightBoundaryUsingDate(tempcal.getTime(), "PDT", PST_1997_END);
456 // logln("========================================");
457 // findDaylightBoundaryUsingCalendar(new Date(97,0,1), false);
458 // logln("========================================");
459 // findDaylightBoundaryUsingCalendar(new Date(97,6,1), true);
464 // Southern hemisphere test
465 logln("========================================");
466 TimeZone z = safeGetTimeZone(AUSTRALIA);
467 tempcal.set(1997, 0, 1);
468 findDaylightBoundaryUsingTimeZone(tempcal.getTime(), true, AUSTRALIA_1997_END, z);
469 logln("========================================");
470 tempcal.set(1997, 6, 1);
471 findDaylightBoundaryUsingTimeZone(tempcal.getTime(), false, AUSTRALIA_1997_BEG, z);
476 logln("========================================");
477 tempcal.set(1997, 0, 1);
478 findDaylightBoundaryUsingTimeZone(tempcal.getTime(), false, PST_1997_BEG);
479 logln("========================================");
480 tempcal.set(1997, 6, 1);
481 findDaylightBoundaryUsingTimeZone(tempcal.getTime(), true, PST_1997_END);
484 // This just shows the offset for April 4-7 in 1997. This is redundant
485 // with a test above, so we disable it.
488 TimeZone z = TimeZone.getDefault();
489 tempcal.set(1997, 3, 4);
490 logln(z.getOffset(1, 97, 3, 4, 6, 0) + " " + tempcal.getTime());
491 tempcal.set(1997, 3, 5);
492 logln(z.getOffset(1, 97, 3, 5, 7, 0) + " " + tempcal.getTime());
493 tempcal.set(1997, 3, 6);
494 logln(z.getOffset(1, 97, 3, 6, 1, 0) + " " + tempcal.getTime());
495 tempcal.set(1997, 3, 7);
496 logln(z.getOffset(1, 97, 3, 7, 2, 0) + " " + tempcal.getTime());
501 //----------------------------------------------------------------------
502 // Can't do any of these without a public inDaylightTime in GC
503 //----------------------------------------------------------------------
506 // static GregorianCalendar cal = new GregorianCalendar();
508 // static void _testUsingBinarySearch(Date d, boolean startsInDST)
510 // // Given a date with a year start, find the Daylight onset
511 // // and end. The given date should be 1/1/xx in some year.
513 // // Use a binary search, assuming that we have a Standard
514 // // time at the midpoint.
515 // long min = d.getTime();
516 // long max = min + (long)(365.25 / 2 * ONE_DAY);
518 // // First check the max
519 // cal.setTime(new Date(max));
520 // if (cal.inDaylightTime() == startsInDST)
522 // logln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));
526 // if (cal.inDaylightTime() != startsInDST)
528 // logln("Error: inDaylightTime(" + d + ") != " + startsInDST);
531 // while ((max - min) > INTERVAL)
533 // long mid = (min + max) >> 1;
534 // cal.setTime(new Date(mid));
535 // if (cal.inDaylightTime() == startsInDST)
545 // logln("Binary Search Before: " + showDate(min));
546 // logln("Binary Search After: " + showDate(max));
549 // static void _testUsingMillis(Date d, boolean startsInDST)
551 // long millis = d.getTime();
552 // long max = millis + (long)(370 * ONE_DAY); // A year plus extra
554 // boolean lastDST = startsInDST;
555 // while (millis < max)
557 // cal.setTime(new Date(millis));
558 // boolean inDaylight = cal.inDaylightTime();
560 // if (inDaylight != lastDST)
562 // logln("Switch " + (inDaylight ? "into" : "out of")
563 // + " DST at " + (new Date(millis)));
564 // lastDST = inDaylight;
567 // millis += 15*ONE_MINUTE;
571 // static void _testUsingFields(int y, boolean startsInDST)
573 // boolean lastDST = startsInDST;
574 // for (int m = 0; m < 12; ++m)
576 // for (int d = 1; d <= MONTH_LENGTH[m]; ++d)
578 // for (int h = 0; h < 24; ++h)
580 // for (int min = 0; min < 60; min += 15)
583 // cal.set(y, m, d, h, min);
584 // boolean inDaylight = cal.inDaylightTime();
585 // if (inDaylight != lastDST)
587 // lastDST = inDaylight;
588 // log("Switch " + (lastDST ? "into" : "out of")
589 // + " DST at " + y + "/" + (m+1) + "/" + d
590 // + " " + showNN(h) + ":" + showNN(min));
591 // logln(" " + cal.getTime());
593 // cal.set(y, m, d, h-1, 45);
595 //+ y + "/" + (m+1) + "/" + d
596 //+ " " + showNN(h-1) + ":" + showNN(45));
597 // logln(" " + cal.getTime());
605 // public void Test1()
607 // logln(Locale.getDefault().getDisplayName());
608 // logln(TimeZone.getDefault().getID());
609 // logln(new Date(0));
613 // logln("========================================");
614 // _testUsingBinarySearch(new Date(97,0,1), false);
615 // logln("========================================");
616 // _testUsingBinarySearch(new Date(97,6,1), true);
621 // logln("========================================");
622 // logln("Stepping using millis");
623 // _testUsingMillis(new Date(97,0,1), false);
628 // logln("========================================");
629 // logln("Stepping using fields");
630 // _testUsingFields(1997, false);
636 // cal.set(1997, 3, 5, 10, 0);
637 // // cal.inDaylightTime();
638 // logln("Date = " + cal.getTime());
639 // logln("Millis = " + cal.getTime().getTime()/3600000);
643 //----------------------------------------------------------------------
644 //----------------------------------------------------------------------
645 //----------------------------------------------------------------------
647 void _testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary)
649 // Given a date with a year start, find the Daylight onset
650 // and end. The given date should be 1/1/xx in some year.
652 // Use a binary search, assuming that we have a Standard
653 // time at the midpoint.
654 long min = d.getTime();
655 long max = min + (long)(365.25 / 2 * ONE_DAY);
657 // First check the boundaries
658 boolean startsInDST = tz.inDaylightTime(d);
660 if (tz.inDaylightTime(new Date(max)) == startsInDST)
662 errln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));
665 while ((max - min) > INTERVAL)
667 long mid = (min + max) >> 1;
668 if (tz.inDaylightTime(new Date(mid)) == startsInDST)
678 logln("Binary Search Before: " + showDate(min));
679 logln("Binary Search After: " + showDate(max));
681 long mindelta = expectedBoundary - min;
682 // not used long maxdelta = max - expectedBoundary;
683 if (mindelta >= 0 && mindelta <= INTERVAL &&
684 mindelta >= 0 && mindelta <= INTERVAL)
685 logln("PASS: Expected boundary at " + expectedBoundary);
687 errln("FAIL: Expected boundary at " + expectedBoundary);
691 static void _testUsingMillis(Date d, boolean startsInDST)
693 long millis = d.getTime();
694 long max = millis + (long)(370 * ONE_DAY); // A year plus extra
696 boolean lastDST = startsInDST;
699 cal.setTime(new Date(millis));
700 boolean inDaylight = cal.inDaylightTime();
702 if (inDaylight != lastDST)
704 logln("Switch " + (inDaylight ? "into" : "out of")
705 + " DST at " + (new Date(millis)));
706 lastDST = inDaylight;
709 millis += 15*ONE_MINUTE;
715 * Test new rule formats.
717 public void TestNewRules()
719 //logln(Locale.getDefault().getDisplayName());
720 //logln(TimeZone.getDefault().getID());
721 //logln(new Date(0));
725 // Doesn't matter what the default TimeZone is here, since we
726 // are creating our own TimeZone objects.
729 java.util.Calendar tempcal = java.util.Calendar.getInstance();
732 logln("-----------------------------------------------------------------");
733 logln("Aug 2ndTues .. Mar 15");
734 tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1",
735 Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR,
736 Calendar.MARCH, 15, 0, 2*ONE_HOUR);
737 //logln(tz.toString());
738 logln("========================================");
739 tempcal.set(1997, 0, 1);
740 _testUsingBinarySearch(tz, tempcal.getTime(), 858416400000L);
741 logln("========================================");
742 tempcal.set(1997, 6, 1);
743 _testUsingBinarySearch(tz, tempcal.getTime(), 871380000000L);
745 logln("-----------------------------------------------------------------");
746 logln("Apr Wed>=14 .. Sep Sun<=20");
747 tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2",
748 Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR,
749 Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR);
750 //logln(tz.toString());
751 logln("========================================");
752 tempcal.set(1997, 0, 1);
753 _testUsingBinarySearch(tz, tempcal.getTime(), 861184800000L);
754 logln("========================================");
755 tempcal.set(1997, 6, 1);
756 _testUsingBinarySearch(tz, tempcal.getTime(), 874227600000L);
762 logln("========================================");
763 logln("Stepping using millis");
764 _testUsingMillis(new Date(97,0,1), false);
769 logln("========================================");
770 logln("Stepping using fields");
771 _testUsingFields(1997, false);
777 cal.set(1997, 3, 5, 10, 0);
778 // cal.inDaylightTime();
779 logln("Date = " + cal.getTime());
780 logln("Millis = " + cal.getTime().getTime()/3600000);
785 //----------------------------------------------------------------------
786 //----------------------------------------------------------------------
787 //----------------------------------------------------------------------
789 //----------------------------------------------------------------------
790 //----------------------------------------------------------------------
791 //----------------------------------------------------------------------
793 //public void Test3()
795 // findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true);
799 * Find boundaries by stepping.
801 void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges)
803 java.util.Calendar tempcal = java.util.Calendar.getInstance();
805 tempcal.set(year, Calendar.JANUARY, 1);
806 Date d = tempcal.getTime();
807 long time = d.getTime(); // ms
808 long limit = time + ONE_YEAR + ONE_DAY;
809 boolean lastState = z.inDaylightTime(d);
811 logln("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState);
812 logln("useDaylightTime = " + z.useDaylightTime());
816 boolean state = z.inDaylightTime(d);
817 if (state != lastState)
819 logln((state ? "Entry " : "Exit ") +
828 if (!lastState && !z.useDaylightTime()) logln("No DST");
829 else errln("FAIL: DST all year, or no DST with true useDaylightTime");
831 else if (changes != 2)
833 errln("FAIL: " + changes + " changes seen; should see 0 or 2");
835 else if (!z.useDaylightTime())
837 errln("FAIL: useDaylightTime false but 2 changes seen");
839 if (changes != expectedChanges)
841 errln("FAIL: " + changes + " changes seen; expected " + expectedChanges);
845 public void TestStepwise()
847 findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("America/New_York"), 2);
848 // disabled Oct 2003 aliu; ACT could mean anything, depending on the underlying JDK, as of 2.8
849 // findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("ACT"), 2);
850 findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("America/Phoenix"), 0); // Added 3Jan01
851 findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone(AUSTRALIA), 2);