/** ******************************************************************************* * Copyright (C) 2000-2010, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ package com.ibm.icu.dev.test.timezone; import java.util.Date; import com.ibm.icu.dev.test.TestFmwk; import com.ibm.icu.text.DateFormat; import com.ibm.icu.util.Calendar; import com.ibm.icu.util.SimpleTimeZone; import com.ibm.icu.util.TimeZone; /** * A test which discovers the boundaries of DST programmatically and verifies * that they are correct. */ public class TimeZoneBoundaryTest extends TestFmwk { static final int ONE_SECOND = 1000; static final int ONE_MINUTE = 60*ONE_SECOND; static final int ONE_HOUR = 60*ONE_MINUTE; static final long ONE_DAY = 24*ONE_HOUR; static final long ONE_YEAR = (long)(365.25 * ONE_DAY); static final long SIX_MONTHS = ONE_YEAR / 2; static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31}; // These values are empirically determined to be correct static final long PST_1997_BEG = 860320800000L; static final long PST_1997_END = 877856400000L; // Minimum interval for binary searches in ms; should be no larger // than 1000. static final long INTERVAL = 10; // Milliseconds // [3Jan01 Liu] Updated for 2000f data static final String AUSTRALIA = "Australia/Adelaide"; static final long AUSTRALIA_1997_BEG = 877797000000L; static final long AUSTRALIA_1997_END = 859653000000L; public static void main(String[] args) throws Exception { new TimeZoneBoundaryTest().run(args); } /** * Date.toString().substring() Boundary Test * Look for a DST changeover to occur within 6 months of the given Date. * The initial Date.toString() should yield a string containing the * startMode as a SUBSTRING. The boundary will be tested to be * at the expectedBoundary value. */ void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary) { // Given a date with a year start, find the Daylight onset // and end. The given date should be 1/1/xx in some year. if (d.toString().indexOf(startMode) == -1) { logln("Error: " + startMode + " not present in " + d); } // Use a binary search, assuming that we have a Standard // time at the midpoint. long min = d.getTime(); long max = min + SIX_MONTHS; while ((max - min) > INTERVAL) { long mid = (min + max) >> 1; String s = new Date(mid).toString(); // logln(s); if (s.indexOf(startMode) != -1) { min = mid; } else { max = mid; } } logln("Date Before: " + showDate(min)); logln("Date After: " + showDate(max)); long mindelta = expectedBoundary - min; // not used long maxdelta = max - expectedBoundary; if (mindelta >= 0 && mindelta <= INTERVAL && mindelta >= 0 && mindelta <= INTERVAL) logln("PASS: Expected boundary at " + expectedBoundary); else errln("FAIL: Expected boundary at " + expectedBoundary); } // This test cannot be compiled until the inDaylightTime() method of GregorianCalendar // becomes public. // static void findDaylightBoundaryUsingCalendar(Date d, boolean startsInDST) // { // // Given a date with a year start, find the Daylight onset // // and end. The given date should be 1/1/xx in some year. // // GregorianCalendar cal = new GregorianCalendar(); // cal.setTime(d); // if (cal.inDaylightTime() != startsInDST) // { // logln("Error: inDaylightTime(" + d + ") != " + startsInDST); // } // // // Use a binary search, assuming that we have a Standard // // time at the midpoint. // long min = d.getTime(); // long max = min + (long)(365.25 / 2 * 24*60*60*1000); // // while ((max - min) > INTERVAL) // { // long mid = (min + max) >> 1; // cal.setTime(new Date(mid)); // if (cal.inDaylightTime() == startsInDST) // { // min = mid; // } // else // { // max = mid; // } // } // // logln("Calendar Before: " + showDate(min)); // logln("Calendar After: " + showDate(max)); // } void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary) { findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary, TimeZone.getDefault()); } void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary, TimeZone tz) { // Given a date with a year start, find the Daylight onset // and end. The given date should be 1/1/xx in some year. // Use a binary search, assuming that we have a Standard // time at the midpoint. long min = d.getTime(); long max = min + SIX_MONTHS; if (tz.inDaylightTime(d) != startsInDST) { errln("FAIL: " + tz.getID() + " inDaylightTime(" + d + ") != " + startsInDST); startsInDST = !startsInDST; // Flip over; find the apparent value } if (tz.inDaylightTime(new Date(max)) == startsInDST) { errln("FAIL: " + tz.getID() + " inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST)); return; } while ((max - min) > INTERVAL) { long mid = (min + max) >> 1; boolean isIn = tz.inDaylightTime(new Date(mid)); if (isIn == startsInDST) { min = mid; } else { max = mid; } } logln(tz.getID() + " Before: " + showDate(min, tz)); logln(tz.getID() + " After: " + showDate(max, tz)); long mindelta = expectedBoundary - min; // not used long maxdelta = max - expectedBoundary; DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); fmt.setTimeZone(tz); if (mindelta >= 0 && mindelta <= INTERVAL && mindelta >= 0 && mindelta <= INTERVAL) logln("PASS: Expected boundary at " + expectedBoundary + " = " + fmt.format(new Date(expectedBoundary))); else errln("FAIL: Expected boundary at " + expectedBoundary + " = " + fmt.format(new Date(expectedBoundary))); } private static String showDate(long l) { return showDate(new Date(l)); } private static String showDate(Date d) { java.util.Calendar cal = java.util.Calendar.getInstance(); cal.setTime(d); return "" + (cal.get(Calendar.YEAR) - 1900) + "/" + showNN(cal.get(Calendar.MONTH) + 1) + "/" + showNN(cal.get(Calendar.DAY_OF_MONTH)) + " " + showNN(cal.get(Calendar.HOUR_OF_DAY)) + ":" + showNN(cal.get(Calendar.MINUTE)) + " \"" + d + "\" = " + d.getTime(); } private static String showDate(long l, TimeZone z) { return showDate(new Date(l), z); } private static String showDate(Date d, TimeZone zone) { DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); fmt.setTimeZone(zone); java.util.Calendar cal = java.util.Calendar.getInstance(); cal.setTime(d); return "" + (cal.get(Calendar.YEAR) - 1900) + "/" + showNN(cal.get(Calendar.MONTH) + 1) + "/" + showNN(cal.get(Calendar.DAY_OF_MONTH)) + " " + showNN(cal.get(Calendar.HOUR_OF_DAY)) + ":" + showNN(cal.get(Calendar.MINUTE)) + " \"" + d + "\" = " + fmt.format(d) + " = " + d.getTime(); } private static String showNN(int n) { return ((n < 10) ? "0" : "") + n; } /** * Given a date, a TimeZone, and expected values for inDaylightTime, * useDaylightTime, zone and DST offset, verify that this is the case. */ void verifyDST(String tag, Calendar cal, TimeZone time_zone, boolean expUseDaylightTime, boolean expInDaylightTime, int expRawOffset, int expOffset) { Date d = cal.getTime(); logln("-- " + tag + ": " + d + " in zone " + time_zone.getID() + " (" + d.getTime()/3600000.0 + ")"); if (time_zone.inDaylightTime(d) == expInDaylightTime) logln("PASS: inDaylightTime = " + time_zone.inDaylightTime(d)); else errln("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d)); if (time_zone.useDaylightTime() == expUseDaylightTime) logln("PASS: useDaylightTime = " + time_zone.useDaylightTime()); else errln("FAIL: useDaylightTime = " + time_zone.useDaylightTime()); if (time_zone.getRawOffset() == expRawOffset) logln("PASS: getRawOffset() = " + expRawOffset/(double)ONE_HOUR); else errln("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR + "; expected " + expRawOffset/(double)ONE_HOUR); //GregorianCalendar gc = new GregorianCalendar(time_zone); //gc.setTime(d); int offset = time_zone.getOffset(cal.get(Calendar.ERA), cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_WEEK), ((cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE)) * 60 + cal.get(Calendar.SECOND)) * 1000 + cal.get(Calendar.MILLISECOND)); if (offset == expOffset) logln("PASS: getOffset() = " + offset/(double)ONE_HOUR); else { logln("era=" + cal.get(Calendar.ERA) + ", year=" + cal.get(Calendar.YEAR) + ", month=" + cal.get(Calendar.MONTH) + ", dom=" + cal.get(Calendar.DAY_OF_MONTH) + ", dow=" + cal.get(Calendar.DAY_OF_WEEK) + ", time-of-day=" + (((cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE)) * 60 + cal.get(Calendar.SECOND)) * 1000 + cal.get(Calendar.MILLISECOND)) / 3600000.0 + " hours"); errln("FAIL: getOffset() = " + offset/(double)ONE_HOUR + "; expected " + expOffset/(double)ONE_HOUR); } } /** * Check that the given year/month/dom/hour maps to and from the * given epochHours. This verifies the functioning of the * calendar and time zone in conjunction with one another, * including the calendar time->fields and fields->time and * the time zone getOffset method. * * @param epochHours hours after Jan 1 1970 0:00 GMT. */ void verifyMapping(Calendar cal, int year, int month, int dom, int hour, double epochHours) { double H = 3600000.0; cal.clear(); cal.set(year, month, dom, hour, 0, 0); Date d = cal.getTime(); double e = d.getTime() / H; Date ed = new Date((long)(epochHours * H)); if (e == epochHours) { logln("Ok: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + e + " (" + ed + ")"); } else { errln("FAIL: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + e + " (" + new Date((long)(e * H)) + ")" + ", expected " + epochHours + " (" + ed + ")"); } cal.setTime(ed); if (cal.get(Calendar.YEAR) == year && cal.get(Calendar.MONTH) == month && cal.get(Calendar.DATE) == dom && cal.get(Calendar.MILLISECONDS_IN_DAY) == hour * 3600000) { logln("Ok: " + epochHours + " (" + ed + ") => " + cal.get(Calendar.YEAR) + "/" + (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE) + " " + cal.get(Calendar.MILLISECONDS_IN_DAY)/H); } else { errln("FAIL: " + epochHours + " (" + ed + ") => " + cal.get(Calendar.YEAR) + "/" + (cal.get(Calendar.MONTH)+1) + "/" + cal.get(Calendar.DATE) + " " + cal.get(Calendar.MILLISECONDS_IN_DAY)/H + ", expected " + year + "/" + (month+1) + "/" + dom + " " + hour); } } // NOTE: Enable this code to check the behavior of the underlying JDK, // using a JDK Calendar object. // // int millisInDay(java.util.Calendar cal) { // return ((cal.get(Calendar.HOUR_OF_DAY) * 60 + // cal.get(Calendar.MINUTE)) * 60 + // cal.get(Calendar.SECOND)) * 1000 + // cal.get(Calendar.MILLISECOND); // } // // void verifyMapping(java.util.Calendar cal, int year, int month, int dom, int hour, // double epochHours) { // cal.clear(); // cal.set(year, month, dom, hour, 0, 0); // Date d = cal.getTime(); // double e = d.getTime() / 3600000.0; // Date ed = new Date((long)(epochHours * 3600000)); // if (e == epochHours) { // logln("Ok: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + // e + " (" + ed + ")"); // } else { // errln("FAIL: " + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + // e + " (" + new Date((long)(e * 3600000)) + ")" + // ", expected " + epochHours + " (" + ed + ")"); // } // cal.setTime(ed); // if (cal.get(Calendar.YEAR) == year && // cal.get(Calendar.MONTH) == month && // cal.get(Calendar.DATE) == dom && // millisInDay(cal) == hour * 3600000) { // logln("Ok: " + epochHours + " (" + ed + ") => " + // cal.get(Calendar.YEAR) + "/" + // (cal.get(Calendar.MONTH)+1) + "/" + // cal.get(Calendar.DATE) + " " + // millisInDay(cal)/3600000.0); // } else { // errln("FAIL: " + epochHours + " (" + ed + ") => " + // cal.get(Calendar.YEAR) + "/" + // (cal.get(Calendar.MONTH)+1) + "/" + // cal.get(Calendar.DATE) + " " + // millisInDay(cal)/3600000.0 + // ", expected " + year + "/" + (month+1) + "/" + dom + // " " + hour); // } // } public void TestBoundaries() { TimeZone save = TimeZone.getDefault(); // Check basic mappings. We had a problem with this for ICU // 2.8 after migrating to using pass-through time zones. The // problem appeared only on JDK 1.3. TimeZone pst = safeGetTimeZone("PST"); Calendar tempcal = Calendar.getInstance(pst); verifyMapping(tempcal, 1997, Calendar.APRIL, 3, 0, 238904.0); verifyMapping(tempcal, 1997, Calendar.APRIL, 4, 0, 238928.0); verifyMapping(tempcal, 1997, Calendar.APRIL, 5, 0, 238952.0); verifyMapping(tempcal, 1997, Calendar.APRIL, 5, 23, 238975.0); verifyMapping(tempcal, 1997, Calendar.APRIL, 6, 0, 238976.0); verifyMapping(tempcal, 1997, Calendar.APRIL, 6, 1, 238977.0); verifyMapping(tempcal, 1997, Calendar.APRIL, 6, 3, 238978.0); TimeZone utc = safeGetTimeZone("UTC"); Calendar utccal = Calendar.getInstance(utc); verifyMapping(utccal, 1997, Calendar.APRIL, 6, 0, 238968.0); // NOTE: Enable this code to check the behavior of the underlying JDK, // using a JDK Calendar object. // // java.util.TimeZone jdkpst = java.util.TimeZone.getTimeZone("PST"); // java.util.Calendar jdkcal = java.util.Calendar.getInstance(jdkpst); // verifyMapping(jdkcal, 1997, Calendar.APRIL, 5, 0, 238952.0); // verifyMapping(jdkcal, 1997, Calendar.APRIL, 5, 23, 238975.0); // verifyMapping(jdkcal, 1997, Calendar.APRIL, 6, 0, 238976.0); // verifyMapping(jdkcal, 1997, Calendar.APRIL, 6, 1, 238977.0); // verifyMapping(jdkcal, 1997, Calendar.APRIL, 6, 3, 238978.0); tempcal.clear(); tempcal.set(1997, Calendar.APRIL, 6); Date d = tempcal.getTime(); try { TimeZone.setDefault(pst); // DST changeover for PST is 4/6/1997 at 2 hours past midnight // at 238978.0 epoch hours. // i is minutes past midnight standard time for (int i=-120; i<=180; i+=60) { boolean inDST = (i >= 120); tempcal.setTimeInMillis(d.getTime() + i*60*1000); verifyDST("hour=" + i/60, tempcal, pst, true, inDST, -8*ONE_HOUR, inDST ? -7*ONE_HOUR : -8*ONE_HOUR); } } finally { TimeZone.setDefault(save); } // We no longer use ICU TimeZone implementation for Java // default TimeZone. Java 1.3 or older version do not // support historic transitions, therefore, the test below // will fail on such environment (with the latest TimeZone // patch for US 2007+ rule). String javaver = System.getProperty("java.version", "1.3"); if (!javaver.startsWith("1.3")) { // This only works in PST/PDT TimeZone.setDefault(safeGetTimeZone("PST")); logln("========================================"); tempcal.set(1997, 0, 1); findDaylightBoundaryUsingDate(tempcal.getTime(), "PST", PST_1997_BEG); logln("========================================"); tempcal.set(1997, 6, 1); findDaylightBoundaryUsingDate(tempcal.getTime(), "PDT", PST_1997_END); } // if (true) // { // logln("========================================"); // findDaylightBoundaryUsingCalendar(new Date(97,0,1), false); // logln("========================================"); // findDaylightBoundaryUsingCalendar(new Date(97,6,1), true); // } if (true) { // Southern hemisphere test logln("========================================"); TimeZone z = safeGetTimeZone(AUSTRALIA); tempcal.set(1997, 0, 1); findDaylightBoundaryUsingTimeZone(tempcal.getTime(), true, AUSTRALIA_1997_END, z); logln("========================================"); tempcal.set(1997, 6, 1); findDaylightBoundaryUsingTimeZone(tempcal.getTime(), false, AUSTRALIA_1997_BEG, z); } if (true) { logln("========================================"); tempcal.set(1997, 0, 1); findDaylightBoundaryUsingTimeZone(tempcal.getTime(), false, PST_1997_BEG); logln("========================================"); tempcal.set(1997, 6, 1); findDaylightBoundaryUsingTimeZone(tempcal.getTime(), true, PST_1997_END); } // This just shows the offset for April 4-7 in 1997. This is redundant // with a test above, so we disable it. if (false) { TimeZone z = TimeZone.getDefault(); tempcal.set(1997, 3, 4); logln(z.getOffset(1, 97, 3, 4, 6, 0) + " " + tempcal.getTime()); tempcal.set(1997, 3, 5); logln(z.getOffset(1, 97, 3, 5, 7, 0) + " " + tempcal.getTime()); tempcal.set(1997, 3, 6); logln(z.getOffset(1, 97, 3, 6, 1, 0) + " " + tempcal.getTime()); tempcal.set(1997, 3, 7); logln(z.getOffset(1, 97, 3, 7, 2, 0) + " " + tempcal.getTime()); } } //---------------------------------------------------------------------- // Can't do any of these without a public inDaylightTime in GC //---------------------------------------------------------------------- // static GregorianCalendar cal = new GregorianCalendar(); // // static void _testUsingBinarySearch(Date d, boolean startsInDST) // { // // Given a date with a year start, find the Daylight onset // // and end. The given date should be 1/1/xx in some year. // // // Use a binary search, assuming that we have a Standard // // time at the midpoint. // long min = d.getTime(); // long max = min + (long)(365.25 / 2 * ONE_DAY); // // // First check the max // cal.setTime(new Date(max)); // if (cal.inDaylightTime() == startsInDST) // { // logln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST)); // } // // cal.setTime(d); // if (cal.inDaylightTime() != startsInDST) // { // logln("Error: inDaylightTime(" + d + ") != " + startsInDST); // } // // while ((max - min) > INTERVAL) // { // long mid = (min + max) >> 1; // cal.setTime(new Date(mid)); // if (cal.inDaylightTime() == startsInDST) // { // min = mid; // } // else // { // max = mid; // } // } // // logln("Binary Search Before: " + showDate(min)); // logln("Binary Search After: " + showDate(max)); // } // // static void _testUsingMillis(Date d, boolean startsInDST) // { // long millis = d.getTime(); // long max = millis + (long)(370 * ONE_DAY); // A year plus extra // // boolean lastDST = startsInDST; // while (millis < max) // { // cal.setTime(new Date(millis)); // boolean inDaylight = cal.inDaylightTime(); // // if (inDaylight != lastDST) // { // logln("Switch " + (inDaylight ? "into" : "out of") // + " DST at " + (new Date(millis))); // lastDST = inDaylight; // } // // millis += 15*ONE_MINUTE; // } // } // // static void _testUsingFields(int y, boolean startsInDST) // { // boolean lastDST = startsInDST; // for (int m = 0; m < 12; ++m) // { // for (int d = 1; d <= MONTH_LENGTH[m]; ++d) // { // for (int h = 0; h < 24; ++h) // { // for (int min = 0; min < 60; min += 15) // { // cal.clear(); // cal.set(y, m, d, h, min); // boolean inDaylight = cal.inDaylightTime(); // if (inDaylight != lastDST) // { // lastDST = inDaylight; // log("Switch " + (lastDST ? "into" : "out of") // + " DST at " + y + "/" + (m+1) + "/" + d // + " " + showNN(h) + ":" + showNN(min)); // logln(" " + cal.getTime()); // // cal.set(y, m, d, h-1, 45); // log("Before = " //+ y + "/" + (m+1) + "/" + d //+ " " + showNN(h-1) + ":" + showNN(45)); // logln(" " + cal.getTime()); // } // } // } // } // } // } // // public void Test1() // { // logln(Locale.getDefault().getDisplayName()); // logln(TimeZone.getDefault().getID()); // logln(new Date(0)); // // if (true) // { // logln("========================================"); // _testUsingBinarySearch(new Date(97,0,1), false); // logln("========================================"); // _testUsingBinarySearch(new Date(97,6,1), true); // } // // if (true) // { // logln("========================================"); // logln("Stepping using millis"); // _testUsingMillis(new Date(97,0,1), false); // } // // if (true) // { // logln("========================================"); // logln("Stepping using fields"); // _testUsingFields(1997, false); // } // // if (false) // { // cal.clear(); // cal.set(1997, 3, 5, 10, 0); // // cal.inDaylightTime(); // logln("Date = " + cal.getTime()); // logln("Millis = " + cal.getTime().getTime()/3600000); // } // } //---------------------------------------------------------------------- //---------------------------------------------------------------------- //---------------------------------------------------------------------- void _testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary) { // Given a date with a year start, find the Daylight onset // and end. The given date should be 1/1/xx in some year. // Use a binary search, assuming that we have a Standard // time at the midpoint. long min = d.getTime(); long max = min + (long)(365.25 / 2 * ONE_DAY); // First check the boundaries boolean startsInDST = tz.inDaylightTime(d); if (tz.inDaylightTime(new Date(max)) == startsInDST) { errln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST)); } while ((max - min) > INTERVAL) { long mid = (min + max) >> 1; if (tz.inDaylightTime(new Date(mid)) == startsInDST) { min = mid; } else { max = mid; } } logln("Binary Search Before: " + showDate(min)); logln("Binary Search After: " + showDate(max)); long mindelta = expectedBoundary - min; // not used long maxdelta = max - expectedBoundary; if (mindelta >= 0 && mindelta <= INTERVAL && mindelta >= 0 && mindelta <= INTERVAL) logln("PASS: Expected boundary at " + expectedBoundary); else errln("FAIL: Expected boundary at " + expectedBoundary); } /* static void _testUsingMillis(Date d, boolean startsInDST) { long millis = d.getTime(); long max = millis + (long)(370 * ONE_DAY); // A year plus extra boolean lastDST = startsInDST; while (millis < max) { cal.setTime(new Date(millis)); boolean inDaylight = cal.inDaylightTime(); if (inDaylight != lastDST) { logln("Switch " + (inDaylight ? "into" : "out of") + " DST at " + (new Date(millis))); lastDST = inDaylight; } millis += 15*ONE_MINUTE; } } */ /** * Test new rule formats. */ public void TestNewRules() { //logln(Locale.getDefault().getDisplayName()); //logln(TimeZone.getDefault().getID()); //logln(new Date(0)); if (true) { // Doesn't matter what the default TimeZone is here, since we // are creating our own TimeZone objects. SimpleTimeZone tz; java.util.Calendar tempcal = java.util.Calendar.getInstance(); tempcal.clear(); logln("-----------------------------------------------------------------"); logln("Aug 2ndTues .. Mar 15"); tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1", Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR, Calendar.MARCH, 15, 0, 2*ONE_HOUR); //logln(tz.toString()); logln("========================================"); tempcal.set(1997, 0, 1); _testUsingBinarySearch(tz, tempcal.getTime(), 858416400000L); logln("========================================"); tempcal.set(1997, 6, 1); _testUsingBinarySearch(tz, tempcal.getTime(), 871380000000L); logln("-----------------------------------------------------------------"); logln("Apr Wed>=14 .. Sep Sun<=20"); tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2", Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR, Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR); //logln(tz.toString()); logln("========================================"); tempcal.set(1997, 0, 1); _testUsingBinarySearch(tz, tempcal.getTime(), 861184800000L); logln("========================================"); tempcal.set(1997, 6, 1); _testUsingBinarySearch(tz, tempcal.getTime(), 874227600000L); } /* if (true) { logln("========================================"); logln("Stepping using millis"); _testUsingMillis(new Date(97,0,1), false); } if (true) { logln("========================================"); logln("Stepping using fields"); _testUsingFields(1997, false); } if (false) { cal.clear(); cal.set(1997, 3, 5, 10, 0); // cal.inDaylightTime(); logln("Date = " + cal.getTime()); logln("Millis = " + cal.getTime().getTime()/3600000); } */ } //---------------------------------------------------------------------- //---------------------------------------------------------------------- //---------------------------------------------------------------------- // Long Bug //---------------------------------------------------------------------- //---------------------------------------------------------------------- //---------------------------------------------------------------------- //public void Test3() //{ // findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true); //} /** * Find boundaries by stepping. */ void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges) { java.util.Calendar tempcal = java.util.Calendar.getInstance(); tempcal.clear(); tempcal.set(year, Calendar.JANUARY, 1); Date d = tempcal.getTime(); long time = d.getTime(); // ms long limit = time + ONE_YEAR + ONE_DAY; boolean lastState = z.inDaylightTime(d); int changes = 0; logln("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState); logln("useDaylightTime = " + z.useDaylightTime()); while (time < limit) { d.setTime(time); boolean state = z.inDaylightTime(d); if (state != lastState) { logln((state ? "Entry " : "Exit ") + "at " + d); lastState = state; ++changes; } time += interval; } if (changes == 0) { if (!lastState && !z.useDaylightTime()) logln("No DST"); else errln("FAIL: DST all year, or no DST with true useDaylightTime"); } else if (changes != 2) { errln("FAIL: " + changes + " changes seen; should see 0 or 2"); } else if (!z.useDaylightTime()) { errln("FAIL: useDaylightTime false but 2 changes seen"); } if (changes != expectedChanges) { errln("FAIL: " + changes + " changes seen; expected " + expectedChanges); } } public void TestStepwise() { findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("America/New_York"), 2); // disabled Oct 2003 aliu; ACT could mean anything, depending on the underlying JDK, as of 2.8 // findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("ACT"), 2); findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone("America/Phoenix"), 0); // Added 3Jan01 findBoundariesStepwise(1997, ONE_DAY, safeGetTimeZone(AUSTRALIA), 2); } }