< prev index next >

test/jdk/java/util/TimeZone/TimeZoneBoundaryTest.java

Print this page

  1 /*
  2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @library /java/text/testlib
 27  * @summary test Time Zone Boundary

 28  */
 29 
 30 import java.text.*;
 31 import java.util.*;








 32 
 33 /**
 34  * A test which discovers the boundaries of DST programmatically and verifies
 35  * that they are correct.
 36  */
 37 public class TimeZoneBoundaryTest extends IntlTest
 38 {
 39     static final int ONE_SECOND = 1000;
 40     static final int ONE_MINUTE = 60*ONE_SECOND;
 41     static final int ONE_HOUR = 60*ONE_MINUTE;
 42     static final long ONE_DAY = 24*ONE_HOUR;
 43     static final long ONE_YEAR = (long)(365.25 * ONE_DAY);
 44     static final long SIX_MONTHS = ONE_YEAR / 2;
 45 
 46     static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
 47 
 48     // These values are empirically determined to be correct
 49     static final long PST_1997_BEG  = 860320800000L;
 50     static final long PST_1997_END  = 877856400000L;
 51 
 52     // Minimum interval for binary searches in ms; should be no larger
 53     // than 1000.
 54     static final long INTERVAL = 10; // Milliseconds
 55 
 56     static final String AUSTRALIA = "Australia/Adelaide";
 57     static final long AUSTRALIA_1997_BEG = 877797000000L;
 58     static final long AUSTRALIA_1997_END = 859653000000L;
 59 
 60     public static void main(String[] args) throws Exception {
 61         new TimeZoneBoundaryTest().run(args);
 62     }
 63 
 64     /**
 65      * Date.toString().substring() Boundary Test
 66      * Look for a DST changeover to occur within 6 months of the given Date.
 67      * The initial Date.toString() should yield a string containing the
 68      * startMode as a SUBSTRING.  The boundary will be tested to be
 69      * at the expectedBoundary value.
 70      */
 71     void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary)
 72     {
 73         // Given a date with a year start, find the Daylight onset
 74         // and end.  The given date should be 1/1/xx in some year.
 75 
 76         if (d.toString().indexOf(startMode) == -1)
 77         {
 78             logln("Error: " + startMode + " not present in " + d);
 79         }
 80 
 81         // Use a binary search, assuming that we have a Standard
 82         // time at the midpoint.
 83         long min = d.getTime();
 84         long max = min + SIX_MONTHS;
 85 
 86         while ((max - min) >  INTERVAL)
 87         {
 88             long mid = (min + max) >> 1;
 89             String s = new Date(mid).toString();
 90             // logln(s);
 91             if (s.indexOf(startMode) != -1)
 92             {
 93                 min = mid;
 94             }
 95             else
 96             {
 97                 max = mid;
 98             }
 99         }
100 
101         logln("Date Before: " + showDate(min));
102         logln("Date After:  " + showDate(max));
103         long mindelta = expectedBoundary - min;
104         long maxdelta = max - expectedBoundary;
105         if (mindelta >= 0 && mindelta <= INTERVAL &&
106             mindelta >= 0 && mindelta <= INTERVAL)
107             logln("PASS: Expected boundary at " + expectedBoundary);
108         else
109             errln("FAIL: Expected boundary at " + expectedBoundary);
110     }
111 
112     void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary)
113     {
114         findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary,
115                                           TimeZone.getDefault());
116     }
117 
118     void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST,
119                                            long expectedBoundary, TimeZone tz)
120     {
121         // Given a date with a year start, find the Daylight onset
122         // and end.  The given date should be 1/1/xx in some year.
123 
124         // Use a binary search, assuming that we have a Standard
125         // time at the midpoint.
126         long min = d.getTime();
127         long max = min + SIX_MONTHS;
128 
129         if (tz.inDaylightTime(d) != startsInDST)
130         {
131             errln("FAIL: " + tz.getID() + " inDaylightTime(" +
132                   d + ") != " + startsInDST);
133             startsInDST = !startsInDST; // Flip over; find the apparent value
134         }
135 
136         if (tz.inDaylightTime(new Date(max)) == startsInDST)
137         {
138             errln("FAIL: " + tz.getID() + " inDaylightTime(" +
139                   (new Date(max)) + ") != " + (!startsInDST));
140             return;
141         }
142 
143         while ((max - min) >  INTERVAL)
144         {
145             long mid = (min + max) >> 1;
146             boolean isIn = tz.inDaylightTime(new Date(mid));
147             if (isIn == startsInDST)
148             {
149                 min = mid;
150             }
151             else
152             {
153                 max = mid;
154             }
155         }
156 
157         logln(tz.getID() + " Before: " + showDate(min, tz));
158         logln(tz.getID() + " After:  " + showDate(max, tz));
159 
160         long mindelta = expectedBoundary - min;
161         long maxdelta = max - expectedBoundary;
162         if (mindelta >= 0 && mindelta <= INTERVAL &&
163             mindelta >= 0 && mindelta <= INTERVAL)
164             logln("PASS: Expected boundary at " + expectedBoundary);
165         else
166             errln("FAIL: Expected boundary at " + expectedBoundary);
167     }
168 
169     private static String showDate(long l)
170     {
171         return showDate(new Date(l));
172     }
173 
174     @SuppressWarnings("deprecation")
175     private static String showDate(Date d)
176     {
177         return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +
178             " " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +
179             " \"" + d + "\" = " +
180             d.getTime();
181     }
182 
183     private static String showDate(long l, TimeZone z)
184     {
185         return showDate(new Date(l), z);
186     }

192         fmt.setTimeZone(zone);
193         return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +
194             " " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +
195             " \"" + d + "\" = " +
196             fmt.format(d);
197     }
198 
199     private static String showNN(int n)
200     {
201         return ((n < 10) ? "0" : "") + n;
202     }
203 
204     /**
205      * Given a date, a TimeZone, and expected values for inDaylightTime,
206      * useDaylightTime, zone and DST offset, verify that this is the case.
207      */
208     void verifyDST(Date d, TimeZone time_zone,
209                    boolean expUseDaylightTime, boolean expInDaylightTime,
210                    int expZoneOffset, int expDSTOffset)
211     {
212         logln("-- Verifying time " + d +
213               " in zone " + time_zone.getID());
214 
215         if (time_zone.inDaylightTime(d) == expInDaylightTime)
216             logln("PASS: inDaylightTime = " + time_zone.inDaylightTime(d));
217         else
218             errln("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d));
219 
220         if (time_zone.useDaylightTime() == expUseDaylightTime)
221             logln("PASS: useDaylightTime = " + time_zone.useDaylightTime());
222         else
223             errln("FAIL: useDaylightTime = " + time_zone.useDaylightTime());
224 
225         if (time_zone.getRawOffset() == expZoneOffset)
226             logln("PASS: getRawOffset() = " + expZoneOffset/(double)ONE_HOUR);
227         else
228             errln("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR +
229                   "; expected " + expZoneOffset/(double)ONE_HOUR);
230 
231         GregorianCalendar gc = new GregorianCalendar(time_zone);
232         gc.setTime(d);
233         int offset = time_zone.getOffset(gc.get(gc.ERA), gc.get(gc.YEAR), gc.get(gc.MONTH),
234                                          gc.get(gc.DAY_OF_MONTH), gc.get(gc.DAY_OF_WEEK),
235                                          ((gc.get(gc.HOUR_OF_DAY) * 60 +
236                                            gc.get(gc.MINUTE)) * 60 +
237                                           gc.get(gc.SECOND)) * 1000 +
238                                          gc.get(gc.MILLISECOND));
239         if (offset == expDSTOffset)
240             logln("PASS: getOffset() = " + offset/(double)ONE_HOUR);
241         else
242             errln("FAIL: getOffset() = " + offset/(double)ONE_HOUR +
243                   "; expected " + expDSTOffset/(double)ONE_HOUR);
244     }
245 
246     @SuppressWarnings("deprecation")

247     public void TestBoundaries()
248     {
249         TimeZone pst = TimeZone.getTimeZone("PST");
250         TimeZone save = TimeZone.getDefault();
251         try {
252             TimeZone.setDefault(pst);
253 
254             // DST changeover for PST is 4/6/1997 at 2 hours past midnight
255             Date d = new Date(97,Calendar.APRIL,6);
256 
257             // i is minutes past midnight standard time
258             for (int i=60; i<=180; i+=15)
259             {
260                 boolean inDST = (i >= 120);
261                 Date e = new Date(d.getTime() + i*60*1000);
262                 verifyDST(e, pst, true, inDST, -8*ONE_HOUR,
263                           inDST ? -7*ONE_HOUR : -8*ONE_HOUR);
264             }
265 
266             logln("========================================");
267             findDaylightBoundaryUsingDate(new Date(97,0,1), "PST", PST_1997_BEG);
268             logln("========================================");
269             findDaylightBoundaryUsingDate(new Date(97,6,1), "PDT", PST_1997_END);
270 
271             // Southern hemisphere test
272             logln("========================================");
273             TimeZone z = TimeZone.getTimeZone(AUSTRALIA);
274             findDaylightBoundaryUsingTimeZone(new Date(97,0,1), true, AUSTRALIA_1997_END, z);
275 
276             logln("========================================");
277             findDaylightBoundaryUsingTimeZone(new Date(97,0,1), false, PST_1997_BEG);
278             logln("========================================");
279             findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true, PST_1997_END);
280         } finally {
281             TimeZone.setDefault(save);
282         }
283     }
284 
285     void testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary)
286     {
287         // Given a date with a year start, find the Daylight onset
288         // and end.  The given date should be 1/1/xx in some year.
289 
290         // Use a binary search, assuming that we have a Standard
291         // time at the midpoint.
292         long min = d.getTime();
293         long max = min + (long)(365.25 / 2 * ONE_DAY);
294 
295         // First check the boundaries
296         boolean startsInDST = tz.inDaylightTime(d);
297 
298         if (tz.inDaylightTime(new Date(max)) == startsInDST)
299         {
300             logln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));
301         }
302 
303         while ((max - min) >  INTERVAL)
304         {
305             long mid = (min + max) >> 1;
306             if (tz.inDaylightTime(new Date(mid)) == startsInDST)
307             {
308                 min = mid;
309             }
310             else
311             {
312                 max = mid;
313             }
314         }
315 
316         logln("Binary Search Before: " + showDate(min));
317         logln("Binary Search After:  " + showDate(max));
318 
319         long mindelta = expectedBoundary - min;
320         long maxdelta = max - expectedBoundary;
321         if (mindelta >= 0 && mindelta <= INTERVAL &&
322             mindelta >= 0 && mindelta <= INTERVAL)
323             logln("PASS: Expected boundary at " + expectedBoundary);
324         else
325             errln("FAIL: Expected boundary at " + expectedBoundary);
326     }
327 
328     /*
329       static void testUsingMillis(Date d, boolean startsInDST)
330       {
331       long millis = d.getTime();
332       long max = millis + (long)(370 * ONE_DAY); // A year plus extra
333 
334       boolean lastDST = startsInDST;
335       while (millis < max)
336       {
337       cal.setTime(new Date(millis));
338       boolean inDaylight = cal.inDaylightTime();
339 
340       if (inDaylight != lastDST)
341       {
342       logln("Switch " + (inDaylight ? "into" : "out of")
343       + " DST at " + (new Date(millis)));
344       lastDST = inDaylight;
345       }
346 
347       millis += 15*ONE_MINUTE;
348       }
349       }
350       */
351 
352     /**
353      * Test new rule formats.
354      */
355     @SuppressWarnings("deprecation")
356     public void TestNewRules()
357     {
358         //logln(Locale.getDefault().getDisplayName());
359         //logln(TimeZone.getDefault().getID());
360         //logln(new Date(0));
361 
362         if (true)
363         {
364             // Doesn't matter what the default TimeZone is here, since we
365             // are creating our own TimeZone objects.
366 
367             SimpleTimeZone tz;
368 
369             logln("-----------------------------------------------------------------");
370             logln("Aug 2ndTues .. Mar 15");
371             tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1",
372                                     Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR,
373                                     Calendar.MARCH, 15, 0, 2*ONE_HOUR);
374             //logln(tz.toString());
375             logln("========================================");
376             testUsingBinarySearch(tz, new Date(97,0,1), 858416400000L);
377             logln("========================================");
378             testUsingBinarySearch(tz, new Date(97,6,1), 871380000000L);
379 
380             logln("-----------------------------------------------------------------");
381             logln("Apr Wed>=14 .. Sep Sun<=20");
382             tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2",
383                                     Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR,
384                                     Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR);
385             //logln(tz.toString());
386             logln("========================================");
387             testUsingBinarySearch(tz, new Date(97,0,1), 861184800000L);
388             logln("========================================");
389             testUsingBinarySearch(tz, new Date(97,6,1), 874227600000L);
390         }
391 
392         /*
393           if (true)
394           {
395           logln("========================================");
396           logln("Stepping using millis");
397           testUsingMillis(new Date(97,0,1), false);
398           }
399 
400           if (true)
401           {
402           logln("========================================");
403           logln("Stepping using fields");
404           testUsingFields(1997, false);
405           }
406 
407           if (false)
408           {
409           cal.clear();
410           cal.set(1997, 3, 5, 10, 0);
411           //    cal.inDaylightTime();
412           logln("Date = " + cal.getTime());
413           logln("Millis = " + cal.getTime().getTime()/3600000);
414           }
415           */
416     }
417 
418     //----------------------------------------------------------------------
419     //----------------------------------------------------------------------
420     //----------------------------------------------------------------------
421     // Long Bug
422     //----------------------------------------------------------------------
423     //----------------------------------------------------------------------
424     //----------------------------------------------------------------------
425 
426     //public void Test3()
427     //{
428     //    findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true);
429     //}
430 
431     /**
432      * Find boundaries by stepping.
433      */
434     @SuppressWarnings("deprecation")
435     void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges)
436     {
437         Date d = new Date(year - 1900, Calendar.JANUARY, 1);
438         long time = d.getTime(); // ms
439         long limit = time + ONE_YEAR + ONE_DAY;
440         boolean lastState = z.inDaylightTime(d);
441         int changes = 0;
442         logln("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState);
443         logln("useDaylightTime = " + z.useDaylightTime());
444         while (time < limit)
445         {
446             d.setTime(time);
447             boolean state = z.inDaylightTime(d);
448             if (state != lastState)
449             {
450                 logln((state ? "Entry " : "Exit ") +
451                       "at " + d);
452                 lastState = state;
453                 ++changes;
454             }
455             time += interval;
456         }
457         if (changes == 0)
458         {
459             if (!lastState && !z.useDaylightTime()) logln("No DST");
460             else errln("FAIL: Timezone<" + z.getID() + "> DST all year, or no DST with true useDaylightTime");
461         }
462         else if (changes != 2)
463         {
464             errln("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; should see 0 or 2");
465         }
466         else if (!z.useDaylightTime())
467         {
468             errln("FAIL: Timezone<" + z.getID() + "> useDaylightTime false but 2 changes seen");
469         }
470         if (changes != expectedChanges)
471         {
472             errln("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; expected " + expectedChanges);
473         }
474     }
475 

476     public void TestStepwise()
477     {
478         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("ACT"), 0);
479         // "EST" is disabled because its behavior depends on the mapping property. (6466476).
480         //findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("EST"), 2);
481         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("HST"), 0);
482         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST"), 2);
483         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST8PDT"), 2);
484         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST"), 0);
485         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST8PDT"), 2);
486         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Japan"), 0);
487         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Europe/Paris"), 2);
488         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("America/Los_Angeles"), 2);
489         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone(AUSTRALIA), 2);
490     }
491 }

  1 /*
  2  * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test

 26  * @summary test Time Zone Boundary
 27  * @run junit TimeZoneBoundaryTest
 28  */
 29 
 30 import java.text.DateFormat;
 31 import java.util.Calendar;
 32 import java.util.Date;
 33 import java.util.GregorianCalendar;
 34 import java.util.SimpleTimeZone;
 35 import java.util.TimeZone;
 36 
 37 import org.junit.jupiter.api.Test;
 38 
 39 import static org.junit.jupiter.api.Assertions.fail;
 40 
 41 /**
 42  * A test which discovers the boundaries of DST programmatically and verifies
 43  * that they are correct.
 44  */
 45 public class TimeZoneBoundaryTest
 46 {
 47     static final int ONE_SECOND = 1000;
 48     static final int ONE_MINUTE = 60*ONE_SECOND;
 49     static final int ONE_HOUR = 60*ONE_MINUTE;
 50     static final long ONE_DAY = 24*ONE_HOUR;
 51     static final long ONE_YEAR = (long)(365.25 * ONE_DAY);
 52     static final long SIX_MONTHS = ONE_YEAR / 2;
 53 
 54     static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
 55 
 56     // These values are empirically determined to be correct
 57     static final long PST_1997_BEG  = 860320800000L;
 58     static final long PST_1997_END  = 877856400000L;
 59 
 60     // Minimum interval for binary searches in ms; should be no larger
 61     // than 1000.
 62     static final long INTERVAL = 10; // Milliseconds
 63 
 64     static final String AUSTRALIA = "Australia/Adelaide";
 65     static final long AUSTRALIA_1997_BEG = 877797000000L;
 66     static final long AUSTRALIA_1997_END = 859653000000L;
 67 




 68     /**
 69      * Date.toString().substring() Boundary Test
 70      * Look for a DST changeover to occur within 6 months of the given Date.
 71      * The initial Date.toString() should yield a string containing the
 72      * startMode as a SUBSTRING.  The boundary will be tested to be
 73      * at the expectedBoundary value.
 74      */
 75     void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary)
 76     {
 77         // Given a date with a year start, find the Daylight onset
 78         // and end.  The given date should be 1/1/xx in some year.
 79 
 80         if (d.toString().indexOf(startMode) == -1)
 81         {
 82             System.out.println("Error: " + startMode + " not present in " + d);
 83         }
 84 
 85         // Use a binary search, assuming that we have a Standard
 86         // time at the midpoint.
 87         long min = d.getTime();
 88         long max = min + SIX_MONTHS;
 89 
 90         while ((max - min) >  INTERVAL)
 91         {
 92             long mid = (min + max) >> 1;
 93             String s = new Date(mid).toString();
 94             // logln(s);
 95             if (s.indexOf(startMode) != -1)
 96             {
 97                 min = mid;
 98             }
 99             else
100             {
101                 max = mid;
102             }
103         }
104 
105         System.out.println("Date Before: " + showDate(min));
106         System.out.println("Date After:  " + showDate(max));
107         long mindelta = expectedBoundary - min;
108         long maxdelta = max - expectedBoundary;
109         if (mindelta >= 0 && mindelta <= INTERVAL &&
110             mindelta >= 0 && mindelta <= INTERVAL)
111             System.out.println("PASS: Expected boundary at " + expectedBoundary);
112         else
113             fail("FAIL: Expected boundary at " + expectedBoundary);
114     }
115 
116     void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary)
117     {
118         findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary,
119                                           TimeZone.getDefault());
120     }
121 
122     void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST,
123                                            long expectedBoundary, TimeZone tz)
124     {
125         // Given a date with a year start, find the Daylight onset
126         // and end.  The given date should be 1/1/xx in some year.
127 
128         // Use a binary search, assuming that we have a Standard
129         // time at the midpoint.
130         long min = d.getTime();
131         long max = min + SIX_MONTHS;
132 
133         if (tz.inDaylightTime(d) != startsInDST)
134         {
135             fail("FAIL: " + tz.getID() + " inDaylightTime(" +
136                   d + ") != " + startsInDST);
137             startsInDST = !startsInDST; // Flip over; find the apparent value
138         }
139 
140         if (tz.inDaylightTime(new Date(max)) == startsInDST)
141         {
142             fail("FAIL: " + tz.getID() + " inDaylightTime(" +
143                   (new Date(max)) + ") != " + (!startsInDST));
144             return;
145         }
146 
147         while ((max - min) >  INTERVAL)
148         {
149             long mid = (min + max) >> 1;
150             boolean isIn = tz.inDaylightTime(new Date(mid));
151             if (isIn == startsInDST)
152             {
153                 min = mid;
154             }
155             else
156             {
157                 max = mid;
158             }
159         }
160 
161         System.out.println(tz.getID() + " Before: " + showDate(min, tz));
162         System.out.println(tz.getID() + " After:  " + showDate(max, tz));
163 
164         long mindelta = expectedBoundary - min;
165         long maxdelta = max - expectedBoundary;
166         if (mindelta >= 0 && mindelta <= INTERVAL &&
167             mindelta >= 0 && mindelta <= INTERVAL)
168             System.out.println("PASS: Expected boundary at " + expectedBoundary);
169         else
170             fail("FAIL: Expected boundary at " + expectedBoundary);
171     }
172 
173     private static String showDate(long l)
174     {
175         return showDate(new Date(l));
176     }
177 
178     @SuppressWarnings("deprecation")
179     private static String showDate(Date d)
180     {
181         return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +
182             " " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +
183             " \"" + d + "\" = " +
184             d.getTime();
185     }
186 
187     private static String showDate(long l, TimeZone z)
188     {
189         return showDate(new Date(l), z);
190     }

196         fmt.setTimeZone(zone);
197         return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +
198             " " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +
199             " \"" + d + "\" = " +
200             fmt.format(d);
201     }
202 
203     private static String showNN(int n)
204     {
205         return ((n < 10) ? "0" : "") + n;
206     }
207 
208     /**
209      * Given a date, a TimeZone, and expected values for inDaylightTime,
210      * useDaylightTime, zone and DST offset, verify that this is the case.
211      */
212     void verifyDST(Date d, TimeZone time_zone,
213                    boolean expUseDaylightTime, boolean expInDaylightTime,
214                    int expZoneOffset, int expDSTOffset)
215     {
216         System.out.println("-- Verifying time " + d +
217               " in zone " + time_zone.getID());
218 
219         if (time_zone.inDaylightTime(d) == expInDaylightTime)
220             System.out.println("PASS: inDaylightTime = " + time_zone.inDaylightTime(d));
221         else
222             fail("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d));
223 
224         if (time_zone.useDaylightTime() == expUseDaylightTime)
225             System.out.println("PASS: useDaylightTime = " + time_zone.useDaylightTime());
226         else
227             fail("FAIL: useDaylightTime = " + time_zone.useDaylightTime());
228 
229         if (time_zone.getRawOffset() == expZoneOffset)
230             System.out.println("PASS: getRawOffset() = " + expZoneOffset/(double)ONE_HOUR);
231         else
232             fail("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR +
233                   "; expected " + expZoneOffset/(double)ONE_HOUR);
234 
235         GregorianCalendar gc = new GregorianCalendar(time_zone);
236         gc.setTime(d);
237         int offset = time_zone.getOffset(gc.get(gc.ERA), gc.get(gc.YEAR), gc.get(gc.MONTH),
238                                          gc.get(gc.DAY_OF_MONTH), gc.get(gc.DAY_OF_WEEK),
239                                          ((gc.get(gc.HOUR_OF_DAY) * 60 +
240                                            gc.get(gc.MINUTE)) * 60 +
241                                           gc.get(gc.SECOND)) * 1000 +
242                                          gc.get(gc.MILLISECOND));
243         if (offset == expDSTOffset)
244             System.out.println("PASS: getOffset() = " + offset/(double)ONE_HOUR);
245         else
246             fail("FAIL: getOffset() = " + offset/(double)ONE_HOUR +
247                   "; expected " + expDSTOffset/(double)ONE_HOUR);
248     }
249 
250     @SuppressWarnings("deprecation")
251     @Test
252     public void TestBoundaries()
253     {
254         TimeZone pst = TimeZone.getTimeZone("PST");
255         TimeZone save = TimeZone.getDefault();
256         try {
257             TimeZone.setDefault(pst);
258 
259             // DST changeover for PST is 4/6/1997 at 2 hours past midnight
260             Date d = new Date(97,Calendar.APRIL,6);
261 
262             // i is minutes past midnight standard time
263             for (int i=60; i<=180; i+=15)
264             {
265                 boolean inDST = (i >= 120);
266                 Date e = new Date(d.getTime() + i*60*1000);
267                 verifyDST(e, pst, true, inDST, -8*ONE_HOUR,
268                           inDST ? -7*ONE_HOUR : -8*ONE_HOUR);
269             }
270 
271             System.out.println("========================================");
272             findDaylightBoundaryUsingDate(new Date(97,0,1), "PST", PST_1997_BEG);
273             System.out.println("========================================");
274             findDaylightBoundaryUsingDate(new Date(97,6,1), "PDT", PST_1997_END);
275 
276             // Southern hemisphere test
277             System.out.println("========================================");
278             TimeZone z = TimeZone.getTimeZone(AUSTRALIA);
279             findDaylightBoundaryUsingTimeZone(new Date(97,0,1), true, AUSTRALIA_1997_END, z);
280 
281             System.out.println("========================================");
282             findDaylightBoundaryUsingTimeZone(new Date(97,0,1), false, PST_1997_BEG);
283             System.out.println("========================================");
284             findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true, PST_1997_END);
285         } finally {
286             TimeZone.setDefault(save);
287         }
288     }
289 
290     void testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary)
291     {
292         // Given a date with a year start, find the Daylight onset
293         // and end.  The given date should be 1/1/xx in some year.
294 
295         // Use a binary search, assuming that we have a Standard
296         // time at the midpoint.
297         long min = d.getTime();
298         long max = min + (long)(365.25 / 2 * ONE_DAY);
299 
300         // First check the boundaries
301         boolean startsInDST = tz.inDaylightTime(d);
302 
303         if (tz.inDaylightTime(new Date(max)) == startsInDST)
304         {
305             System.out.println("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));
306         }
307 
308         while ((max - min) >  INTERVAL)
309         {
310             long mid = (min + max) >> 1;
311             if (tz.inDaylightTime(new Date(mid)) == startsInDST)
312             {
313                 min = mid;
314             }
315             else
316             {
317                 max = mid;
318             }
319         }
320 
321         System.out.println("Binary Search Before: " + showDate(min));
322         System.out.println("Binary Search After:  " + showDate(max));
323 
324         long mindelta = expectedBoundary - min;
325         long maxdelta = max - expectedBoundary;
326         if (mindelta >= 0 && mindelta <= INTERVAL &&
327             mindelta >= 0 && mindelta <= INTERVAL)
328             System.out.println("PASS: Expected boundary at " + expectedBoundary);
329         else
330             fail("FAIL: Expected boundary at " + expectedBoundary);
331     }
332 
























333     /**
334      * Test new rule formats.
335      */
336     @SuppressWarnings("deprecation")
337     @Test
338     public void TestNewRules() {
339         // Doesn't matter what the default TimeZone is here, since we
340         // are creating our own TimeZone objects.
341 
342         SimpleTimeZone tz;
343 
344         System.out.println("-----------------------------------------------------------------");
345         System.out.println("Aug 2ndTues .. Mar 15");
346         tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1",
347                                 Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR,
348                                 Calendar.MARCH, 15, 0, 2*ONE_HOUR);
349         System.out.println("========================================");
350         testUsingBinarySearch(tz, new Date(97,0,1), 858416400000L);
351         System.out.println("========================================");
352         testUsingBinarySearch(tz, new Date(97,6,1), 871380000000L);
353 
354         System.out.println("-----------------------------------------------------------------");
355         System.out.println("Apr Wed>=14 .. Sep Sun<=20");
356         tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2",
357                                 Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR,
358                                 Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR);
359         System.out.println("========================================");
360         testUsingBinarySearch(tz, new Date(97,0,1), 861184800000L);
361         System.out.println("========================================");
362         testUsingBinarySearch(tz, new Date(97,6,1), 874227600000L);


































363     }
364 













365     /**
366      * Find boundaries by stepping.
367      */
368     @SuppressWarnings("deprecation")
369     void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges)
370     {
371         Date d = new Date(year - 1900, Calendar.JANUARY, 1);
372         long time = d.getTime(); // ms
373         long limit = time + ONE_YEAR + ONE_DAY;
374         boolean lastState = z.inDaylightTime(d);
375         int changes = 0;
376         System.out.println("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState);
377         System.out.println("useDaylightTime = " + z.useDaylightTime());
378         while (time < limit)
379         {
380             d.setTime(time);
381             boolean state = z.inDaylightTime(d);
382             if (state != lastState)
383             {
384                 System.out.println((state ? "Entry " : "Exit ") +
385                       "at " + d);
386                 lastState = state;
387                 ++changes;
388             }
389             time += interval;
390         }
391         if (changes == 0)
392         {
393             if (!lastState && !z.useDaylightTime()) System.out.println("No DST");
394             else fail("FAIL: Timezone<" + z.getID() + "> DST all year, or no DST with true useDaylightTime");
395         }
396         else if (changes != 2)
397         {
398             fail("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; should see 0 or 2");
399         }
400         else if (!z.useDaylightTime())
401         {
402             fail("FAIL: Timezone<" + z.getID() + "> useDaylightTime false but 2 changes seen");
403         }
404         if (changes != expectedChanges)
405         {
406             fail("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; expected " + expectedChanges);
407         }
408     }
409 
410     @Test
411     public void TestStepwise()
412     {
413         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("ACT"), 0);
414         // "EST" is disabled because its behavior depends on the mapping property. (6466476).
415         //findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("EST"), 2);
416         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("HST"), 0);
417         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST"), 2);
418         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST8PDT"), 2);
419         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST"), 0);
420         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST8PDT"), 2);
421         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Japan"), 0);
422         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Europe/Paris"), 2);
423         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("America/Los_Angeles"), 2);
424         findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone(AUSTRALIA), 2);
425     }
426 }
< prev index next >