1 /*
2  * Copyright (c) 1998, 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  * @bug 4052967 4073209 4073215 4084933 4096952 4109314 4126678 4151406 4151429
27  * 4154525 4154537 4154542 4154650 4159922 4162593 4173604 4176686 4184229 4208960
28  * 4966229 6433179 6851214 8007520 8008577
29  * @library /java/text/testlib
30  * @run main/othervm -Djava.locale.providers=JRE,SPI TimeZoneRegression
31  */
32 
33 import java.util.*;
34 import java.io.*;
35 import java.text.*;
36 
37 public class TimeZoneRegression extends IntlTest {
38 
main(String[] args)39     public static void main(String[] args) throws Exception {
40         new TimeZoneRegression().run(args);
41     }
42 
Test4052967()43     public void Test4052967() {
44         logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***");
45         String id = TimeZone.getDefault().getID();
46         logln("user.timezone: " + System.getProperty("user.timezone", "<not set>"));
47         logln("TimeZone.getDefault().getID(): " + id);
48         logln(new Date().toString());
49         logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");
50     }
51 
Test4073209()52     public void Test4073209() {
53         TimeZone z1 = TimeZone.getTimeZone("PST");
54         TimeZone z2 = TimeZone.getTimeZone("PST");
55         if (z1 == z2) {
56             errln("Fail: TimeZone should return clones");
57         }
58     }
59 
60     @SuppressWarnings("deprecation")
Test4073215()61     public void Test4073215() {
62         SimpleTimeZone z = new SimpleTimeZone(0, "GMT");
63         if (z.useDaylightTime()) {
64             errln("Fail: Fix test to start with non-DST zone");
65         }
66         z.setStartRule(Calendar.FEBRUARY, 1, Calendar.SUNDAY, 0);
67         z.setEndRule(Calendar.MARCH, -1, Calendar.SUNDAY, 0);
68         if (!z.useDaylightTime()) {
69             errln("Fail: DST not active");
70         }
71         if (z.inDaylightTime(new Date(97, Calendar.JANUARY, 31)) ||
72             !z.inDaylightTime(new Date(97, Calendar.MARCH, 1)) ||
73             z.inDaylightTime(new Date(97, Calendar.MARCH, 31))) {
74             errln("Fail: DST not working as expected");
75         }
76     }
77 
78     /**
79      * The expected behavior of TimeZone around the boundaries is:
80      * (Assume transition time of 2:00 AM)
81      *    day of onset 1:59 AM STD  = display name 1:59 AM ST
82      *                 2:00 AM STD  = display name 3:00 AM DT
83      *    day of end   0:59 AM STD  = display name 1:59 AM DT
84      *                 1:00 AM STD  = display name 1:00 AM ST
85      */
Test4084933()86     public void Test4084933() {
87         // test both SimpleTimeZone and ZoneInfo objects.
88         // @since 1.4
89         sub4084933(getPST());
90         sub4084933(TimeZone.getTimeZone("PST"));
91     }
92 
sub4084933(TimeZone tz)93     private void sub4084933(TimeZone tz) {
94         long offset1 = tz.getOffset(1,
95             1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (2*60*60*1000));
96         long offset2 = tz.getOffset(1,
97             1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (2*60*60*1000)-1);
98 
99         long offset3 = tz.getOffset(1,
100             1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (1*60*60*1000));
101         long offset4 = tz.getOffset(1,
102             1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (1*60*60*1000)-1);
103 
104         /*
105          *  The following was added just for consistency.  It shows that going *to* Daylight
106          *  Savings Time (PDT) does work at 2am.
107          */
108 
109         long offset5 = tz.getOffset(1,
110             1997, Calendar.APRIL, 6, Calendar.SUNDAY, (2*60*60*1000));
111         long offset6 = tz.getOffset(1,
112             1997, Calendar.APRIL, 6, Calendar.SUNDAY, (2*60*60*1000)-1);
113 
114         long offset7 = tz.getOffset(1,
115             1997, Calendar.APRIL, 6, Calendar.SUNDAY, (1*60*60*1000));
116         long offset8 = tz.getOffset(1,
117             1997, Calendar.APRIL, 6, Calendar.SUNDAY, (1*60*60*1000)-1);
118 
119         long SToffset = -8 * 60*60*1000L;
120         long DToffset = -7 * 60*60*1000L;
121         if (offset1 != SToffset || offset2 != SToffset ||
122             offset3 != SToffset || offset4 != DToffset ||
123             offset5 != DToffset || offset6 != SToffset ||
124             offset7 != SToffset || offset8 != SToffset)
125             errln("Fail: TimeZone misbehaving"); {
126         }
127     }
128 
Test4096952()129     public void Test4096952() {
130         String[] ZONES = { "GMT", "MET", "IST" };
131         boolean pass = true;
132         try {
133             for (int i=0; i<ZONES.length; ++i) {
134                 TimeZone zone = TimeZone.getTimeZone(ZONES[i]);
135                 if (!zone.getID().equals(ZONES[i]))
136                     errln("Fail: Test broken; zones not instantiating");
137 
138                 ByteArrayOutputStream baos;
139                 ObjectOutputStream ostream =
140                     new ObjectOutputStream(baos = new
141                                            ByteArrayOutputStream());
142                 ostream.writeObject(zone);
143                 ostream.close();
144                 baos.close();
145                 ObjectInputStream istream =
146                     new ObjectInputStream(new
147                                           ByteArrayInputStream(baos.toByteArray()));
148                 TimeZone frankenZone = (TimeZone) istream.readObject();
149                 //logln("Zone:        " + zone);
150                 //logln("FrankenZone: " + frankenZone);
151                 if (!zone.equals(frankenZone)) {
152                     logln("TimeZone " + zone.getID() +
153                           " not equal to serialized/deserialized one");
154                     pass = false;
155                 }
156             }
157             if (!pass) errln("Fail: TimeZone serialization/equality bug");
158         }
159         catch (IOException e) {
160             errln("Fail: " + e);
161             e.printStackTrace();
162         }
163         catch (ClassNotFoundException e) {
164             errln("Fail: " + e);
165             e.printStackTrace();
166         }
167     }
168 
Test4109314()169     public void Test4109314() {
170         // test both SimpleTimeZone and ZoneInfo objects.
171         // @since 1.4
172         if (Locale.getDefault().equals(new Locale("th", "TH"))) {
173             return;
174         }
175         sub4109314(getPST());
176         sub4109314(TimeZone.getTimeZone("PST"));
177     }
178 
179 
180     @SuppressWarnings("deprecation")
sub4109314(TimeZone PST)181     private void sub4109314(TimeZone PST) {
182         GregorianCalendar testCal = (GregorianCalendar)Calendar.getInstance();
183         Object[] testData = {
184             PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0),
185             PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0),
186         };
187         boolean pass=true;
188         for (int i=0; i<testData.length; i+=3) {
189             testCal.setTimeZone((TimeZone) testData[i]);
190             long t = ((Date)testData[i+1]).getTime();
191             Date end = (Date) testData[i+2];
192             while (t < end.getTime()) {
193                 testCal.setTime(new Date(t));
194                 if (!checkCalendar314(testCal, (TimeZone) testData[i]))
195                     pass = false;
196                 t += 60*60*1000L;
197             }
198         }
199         if (!pass) errln("Fail: TZ API inconsistent");
200     }
201 
checkCalendar314(GregorianCalendar testCal, TimeZone testTZ)202     boolean checkCalendar314(GregorianCalendar testCal, TimeZone testTZ) {
203         // GregorianCalendar testCal = (GregorianCalendar)aCal.clone();
204 
205         final int ONE_DAY = 24*60*60*1000;
206 
207         int tzOffset, tzRawOffset;
208         Float tzOffsetFloat,tzRawOffsetFloat;
209         // Here is where the user made an error.  They were passing in the value of
210         // the MILLSECOND field; you need to pass in the millis in the day in STANDARD
211         // time.
212         int millis = testCal.get(Calendar.MILLISECOND) +
213             1000 * (testCal.get(Calendar.SECOND) +
214                     60 * (testCal.get(Calendar.MINUTE) +
215                           60 * (testCal.get(Calendar.HOUR_OF_DAY)))) -
216             testCal.get(Calendar.DST_OFFSET);
217 
218         /* Fix up millis to be in range.  ASSUME THAT WE ARE NOT AT THE
219          * BEGINNING OR END OF A MONTH.  We must add this code because
220          * getOffset() has been changed to be more strict about the parameters
221          * it receives -- it turns out that this test was passing in illegal
222          * values. */
223         int date = testCal.get(Calendar.DATE);
224         int dow  = testCal.get(Calendar.DAY_OF_WEEK);
225         while (millis < 0) {
226             millis += ONE_DAY;
227             --date;
228             dow = Calendar.SUNDAY + ((dow - Calendar.SUNDAY + 6) % 7);
229         }
230         while (millis >= ONE_DAY) {
231             millis -= ONE_DAY;
232             ++date;
233             dow = Calendar.SUNDAY + ((dow - Calendar.SUNDAY + 1) % 7);
234         }
235 
236         tzOffset = testTZ.getOffset(testCal.get(Calendar.ERA),
237                                     testCal.get(Calendar.YEAR),
238                                     testCal.get(Calendar.MONTH),
239                                     date,
240                                     dow,
241                                     millis);
242         tzRawOffset = testTZ.getRawOffset();
243         tzOffsetFloat = new Float((float)tzOffset/(float)3600000);
244         tzRawOffsetFloat = new Float((float)tzRawOffset/(float)3600000);
245 
246         Date testDate = testCal.getTime();
247 
248         boolean inDaylightTime = testTZ.inDaylightTime(testDate);
249         SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
250         sdf.setCalendar(testCal);
251         String inDaylightTimeString;
252 
253         boolean passed;
254 
255         if (inDaylightTime)
256         {
257             inDaylightTimeString = " DST ";
258             passed = (tzOffset == (tzRawOffset + 3600000));
259         }
260         else
261         {
262             inDaylightTimeString = "     ";
263             passed = (tzOffset == tzRawOffset);
264         }
265 
266         String output = testTZ.getID() + " " + sdf.format(testDate) +
267             " Offset(" + tzOffsetFloat + ")" +
268             " RawOffset(" + tzRawOffsetFloat + ")" +
269             " " + millis/(float)3600000 + " " +
270             inDaylightTimeString;
271 
272         if (passed)
273             output += "     ";
274         else
275             output += "ERROR";
276 
277         if (passed) logln(output); else errln(output);
278         return passed;
279     }
280 
281     /**
282      * CANNOT REPRODUDE
283      *
284      * Yet another _alleged_ bug in TimeZone.getOffset(), a method that never
285      * should have been made public.  It's simply too hard to use correctly.
286      *
287      * The original test code failed to do the following:
288      * (1) Call Calendar.setTime() before getting the fields!
289      * (2) Use the right millis (as usual) for getOffset(); they were passing
290      *     in the MILLIS field, instead of the STANDARD MILLIS IN DAY.
291      * When you fix these two problems, the test passes, as expected.
292      */
Test4126678()293     public void Test4126678() {
294         // Note: this test depends on the PST time zone.
295         TimeZone initialZone = TimeZone.getDefault();
296 
297         // test both SimpleTimeZone and ZoneInfo objects.
298         // @since 1.4
299         sub4126678(getPST());
300         sub4126678(TimeZone.getTimeZone("PST"));
301 
302         // restore the initial time zone so that this test case
303         // doesn't affect the others.
304         TimeZone.setDefault(initialZone);
305     }
306 
307     @SuppressWarnings("deprecation")
sub4126678(TimeZone tz)308     private void sub4126678(TimeZone tz) {
309         Calendar cal = Calendar.getInstance();
310         TimeZone.setDefault(tz);
311         cal.setTimeZone(tz);
312 
313         Date dt = new Date(1998-1900, Calendar.APRIL, 5, 10, 0);
314         // the dt value is local time in PST.
315         if (!tz.inDaylightTime(dt))
316             errln("We're not in Daylight Savings Time and we should be.\n");
317 
318         cal.setTime(dt);
319         int era = cal.get(Calendar.ERA);
320         int year = cal.get(Calendar.YEAR);
321         int month = cal.get(Calendar.MONTH);
322         int day = cal.get(Calendar.DATE);
323         int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
324         int millis = cal.get(Calendar.MILLISECOND) +
325             (cal.get(Calendar.SECOND) +
326              (cal.get(Calendar.MINUTE) +
327               (cal.get(Calendar.HOUR) * 60) * 60) * 1000) -
328             cal.get(Calendar.DST_OFFSET);
329 
330         long offset = tz.getOffset(era, year, month, day, dayOfWeek, millis);
331         long raw_offset = tz.getRawOffset();
332         if (offset == raw_offset) {
333             errln("Offsets should not match when in DST");
334         }
335     }
336 
337     /**
338      * TimeZone.getAvailableIDs(int) throws exception for certain values,
339      * due to a faulty constant in TimeZone.java.
340      */
Test4151406()341     public void Test4151406() {
342         int max = 0;
343         for (int h=-28; h<=30; ++h) {
344             // h is in half-hours from GMT; rawoffset is in millis
345             int rawoffset = h * 1800000;
346             int hh = (h<0) ? -h : h;
347             String hname = ((h<0) ? "GMT-" : "GMT+") +
348                 ((hh/2 < 10) ? "0" : "") +
349                 (hh/2) + ':' +
350                 ((hh%2==0) ? "00" : "30");
351             try {
352                 String[] ids = TimeZone.getAvailableIDs(rawoffset);
353                 if (ids.length > max) max = ids.length;
354                 logln(hname + ' ' + ids.length +
355                       ((ids.length > 0) ? (" e.g. " + ids[0]) : ""));
356             } catch (Exception e) {
357                 errln(hname + ' ' + "Fail: " + e);
358             }
359         }
360         logln("Maximum zones per offset = " + max);
361     }
362 
Test4151429()363     public void Test4151429() {
364         try {
365             TimeZone tz = TimeZone.getTimeZone("GMT");
366             String name = tz.getDisplayName(true, Integer.MAX_VALUE,
367                                             Locale.getDefault());
368             errln("IllegalArgumentException not thrown by TimeZone.getDisplayName()");
369         } catch(IllegalArgumentException e) {}
370     }
371 
372     /**
373      * SimpleTimeZone accepts illegal DST savings values.  These values
374      * must be non-zero.  There is no upper limit at this time.
375      */
Test4154525()376     public void Test4154525() {
377         final int GOOD = 1, BAD = 0;
378         int[] DATA = {
379             1, GOOD,
380             0, BAD,
381             -1, BAD,
382             60*60*1000, GOOD,
383             Integer.MIN_VALUE, BAD,
384             // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time
385         };
386         for (int i=0; i<DATA.length; i+=2) {
387             int savings = DATA[i];
388             boolean valid = DATA[i+1] == GOOD;
389             String method = null;
390             for (int j=0; j<2; ++j) {
391                 try {
392                     switch (j) {
393                     case 0:
394                         method = "constructor";
395                         SimpleTimeZone z = new SimpleTimeZone(0, "id",
396                             Calendar.JANUARY, 1, 0, 0,
397                             Calendar.MARCH, 1, 0, 0,
398                             savings); // <- what we're interested in
399                         break;
400                     case 1:
401                         method = "setDSTSavings()";
402                         z = new SimpleTimeZone(0, "GMT");
403                         z.setDSTSavings(savings);
404                         break;
405                     }
406                     if (valid) {
407                         logln("Pass: DST savings of " + savings + " accepted by " + method);
408                     } else {
409                         errln("Fail: DST savings of " + savings + " accepted by " + method);
410                     }
411                 } catch (IllegalArgumentException e) {
412                     if (valid) {
413                         errln("Fail: DST savings of " + savings + " to " + method + " gave " + e);
414                     } else {
415                         logln("Pass: DST savings of " + savings + " to " + method + " gave " + e);
416                     }
417                 }
418             }
419         }
420     }
421 
422     /**
423      * SimpleTimeZone.hasSameRules() doesn't work for zones with no DST
424      * and different DST parameters.
425      */
Test4154537()426     public void Test4154537() {
427         // tz1 and tz2 have no DST and different rule parameters
428         SimpleTimeZone tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0);
429         SimpleTimeZone tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0);
430         // tza and tzA have the same rule params
431         SimpleTimeZone tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0);
432         SimpleTimeZone tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0);
433         // tzb differs from tza
434         SimpleTimeZone tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0);
435         if (tz1.useDaylightTime() || tz2.useDaylightTime() ||
436             !tza.useDaylightTime() || !tzA.useDaylightTime() ||
437             !tzb.useDaylightTime()) {
438             errln("Test is broken -- rewrite it");
439         }
440         if (!tza.hasSameRules(tzA) || tza.hasSameRules(tzb)) {
441             errln("Fail: hasSameRules() broken for zones with rules");
442         }
443         if (!tz1.hasSameRules(tz2)) {
444             errln("Fail: hasSameRules() returns false for zones without rules");
445             errln("zone 1 = " + tz1);
446             errln("zone 2 = " + tz2);
447         }
448     }
449 
450     /**
451      * SimpleTimeZone constructors, setStartRule(), and setEndRule() don't
452      * check for out-of-range arguments.
453      */
Test4154542()454     public void Test4154542() {
455         final int GOOD = 1;
456         final int BAD  = 0;
457 
458         final int GOOD_MONTH       = Calendar.JANUARY;
459         final int GOOD_DAY         = 1;
460         final int GOOD_DAY_OF_WEEK = Calendar.SUNDAY;
461         final int GOOD_TIME        = 0;
462 
463         int[] DATA = {
464             GOOD, Integer.MIN_VALUE,    0,  Integer.MAX_VALUE,   Integer.MIN_VALUE,
465             GOOD, Calendar.JANUARY,    -5,  Calendar.SUNDAY,     0,
466             GOOD, Calendar.DECEMBER,    5,  Calendar.SATURDAY,   24*60*60*1000-1,
467             GOOD, Calendar.DECEMBER,    5,  Calendar.SATURDAY,   24*60*60*1000,
468             BAD,  Calendar.DECEMBER,    5,  Calendar.SATURDAY,   24*60*60*1000+1,
469             BAD,  Calendar.DECEMBER,    5,  Calendar.SATURDAY,  -1,
470             BAD,  Calendar.JANUARY,    -6,  Calendar.SUNDAY,     0,
471             BAD,  Calendar.DECEMBER,    6,  Calendar.SATURDAY,   24*60*60*1000,
472             GOOD, Calendar.DECEMBER,    1,  0,                   0,
473             GOOD, Calendar.DECEMBER,   31,  0,                   0,
474             BAD,  Calendar.APRIL,      31,  0,                   0,
475             BAD,  Calendar.DECEMBER,   32,  0,                   0,
476             BAD,  Calendar.JANUARY-1,   1,  Calendar.SUNDAY,     0,
477             BAD,  Calendar.DECEMBER+1,  1,  Calendar.SUNDAY,     0,
478             GOOD, Calendar.DECEMBER,   31, -Calendar.SUNDAY,     0,
479             GOOD, Calendar.DECEMBER,   31, -Calendar.SATURDAY,   0,
480             BAD,  Calendar.DECEMBER,   32, -Calendar.SATURDAY,   0,
481             BAD,  Calendar.DECEMBER,  -32, -Calendar.SATURDAY,   0,
482             BAD,  Calendar.DECEMBER,   31, -Calendar.SATURDAY-1, 0,
483         };
484         SimpleTimeZone zone = new SimpleTimeZone(0, "Z");
485         for (int i=0; i<DATA.length; i+=5) {
486             boolean shouldBeGood = (DATA[i] == GOOD);
487             int month     = DATA[i+1];
488             int day       = DATA[i+2];
489             int dayOfWeek = DATA[i+3];
490             int time      = DATA[i+4];
491 
492             Exception ex = null;
493             try {
494                 zone.setStartRule(month, day, dayOfWeek, time);
495             } catch (IllegalArgumentException e) {
496                 ex = e;
497             }
498             if ((ex == null) != shouldBeGood) {
499                 errln("setStartRule(month=" + month + ", day=" + day +
500                       ", dayOfWeek=" + dayOfWeek + ", time=" + time +
501                       (shouldBeGood ? (") should work but throws " + ex)
502                        : ") should fail but doesn't"));
503             }
504 
505             ex = null;
506             try {
507                 zone.setEndRule(month, day, dayOfWeek, time);
508             } catch (IllegalArgumentException e) {
509                 ex = e;
510             }
511             if ((ex == null) != shouldBeGood) {
512                 errln("setEndRule(month=" + month + ", day=" + day +
513                       ", dayOfWeek=" + dayOfWeek + ", time=" + time +
514                       (shouldBeGood ? (") should work but throws " + ex)
515                        : ") should fail but doesn't"));
516             }
517 
518             ex = null;
519             try {
520                 SimpleTimeZone temp = new SimpleTimeZone(0, "Z",
521                         month, day, dayOfWeek, time,
522                         GOOD_MONTH, GOOD_DAY, GOOD_DAY_OF_WEEK, GOOD_TIME);
523             } catch (IllegalArgumentException e) {
524                 ex = e;
525             }
526             if ((ex == null) != shouldBeGood) {
527                 errln("SimpleTimeZone(month=" + month + ", day=" + day +
528                       ", dayOfWeek=" + dayOfWeek + ", time=" + time +
529                       (shouldBeGood ? (", <end>) should work but throws " + ex)
530                        : ", <end>) should fail but doesn't"));
531             }
532 
533             ex = null;
534             try {
535                 SimpleTimeZone temp = new SimpleTimeZone(0, "Z",
536                         GOOD_MONTH, GOOD_DAY, GOOD_DAY_OF_WEEK, GOOD_TIME,
537                         month, day, dayOfWeek, time);
538             } catch (IllegalArgumentException e) {
539                 ex = e;
540             }
541             if ((ex == null) != shouldBeGood) {
542                 errln("SimpleTimeZone(<start>, month=" + month + ", day=" + day +
543                       ", dayOfWeek=" + dayOfWeek + ", time=" + time +
544                       (shouldBeGood ? (") should work but throws " + ex)
545                        : ") should fail but doesn't"));
546             }
547         }
548     }
549 
550     /**
551      * SimpleTimeZone.getOffset accepts illegal arguments.
552      */
Test4154650()553     public void Test4154650() {
554         final int GOOD=1, BAD=0;
555         final int GOOD_ERA=GregorianCalendar.AD, GOOD_YEAR=1998, GOOD_MONTH=Calendar.AUGUST;
556         final int GOOD_DAY=2, GOOD_DOW=Calendar.SUNDAY, GOOD_TIME=16*3600000;
557         int[] DATA = {
558             GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
559 
560             GOOD, GregorianCalendar.BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
561             GOOD, GregorianCalendar.AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
562             BAD,  GregorianCalendar.BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
563             BAD,  GregorianCalendar.AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
564 
565             GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME,
566             GOOD, GOOD_ERA, GOOD_YEAR, Calendar.DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME,
567             BAD,  GOOD_ERA, GOOD_YEAR, Calendar.JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
568             BAD,  GOOD_ERA, GOOD_YEAR, Calendar.DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
569 
570             GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 1, GOOD_DOW, GOOD_TIME,
571             GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 31, GOOD_DOW, GOOD_TIME,
572             BAD,  GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 0, GOOD_DOW, GOOD_TIME,
573             BAD,  GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 32, GOOD_DOW, GOOD_TIME,
574 
575             GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SUNDAY, GOOD_TIME,
576             GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SATURDAY, GOOD_TIME,
577             BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SUNDAY-1, GOOD_TIME,
578             BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SATURDAY+1, GOOD_TIME,
579 
580             GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0,
581             GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1,
582             BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1,
583             BAD,  GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000,
584         };
585 
586         TimeZone tz = TimeZone.getDefault();
587         for (int i=0; i<DATA.length; i+=7) {
588             boolean good = DATA[i] == GOOD;
589             IllegalArgumentException e = null;
590             try {
591                 int offset = tz.getOffset(DATA[i+1], DATA[i+2], DATA[i+3],
592                                           DATA[i+4], DATA[i+5], DATA[i+6]);
593            } catch (IllegalArgumentException ex) {
594                 e = ex;
595             }
596             if (good != (e == null)) {
597                 errln("Fail: getOffset(" +
598                       DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " +
599                       DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] +
600                       (good ? (") threw " + e) : ") accepts invalid args"));
601             }
602         }
603     }
604 
605     /**
606      * TimeZone constructors allow null IDs.
607      */
Test4159922()608     public void Test4159922() {
609         TimeZone z = null;
610 
611         // TimeZone API.  Only hasSameRules() and setDefault() should
612         // allow null.
613         try {
614             z = TimeZone.getTimeZone((String)null);
615             errln("FAIL: Null allowed in getTimeZone");
616         } catch (NullPointerException e) {}
617         z = TimeZone.getTimeZone("GMT");
618         try {
619             z.getDisplayName(false, TimeZone.SHORT, null);
620             errln("FAIL: Null allowed in getDisplayName(3)");
621         } catch (NullPointerException e) {}
622         try {
623             z.getDisplayName(null);
624             errln("FAIL: Null allowed in getDisplayName(1)");
625         } catch (NullPointerException e) {}
626         try {
627             if (z.hasSameRules(null)) {
628                 errln("FAIL: hasSameRules returned true");
629             }
630         } catch (NullPointerException e) {
631             errln("FAIL: Null NOT allowed in hasSameRules");
632         }
633         try {
634             z.inDaylightTime(null);
635             errln("FAIL: Null allowed in inDaylightTime");
636         } catch (NullPointerException e) {}
637         try {
638             z.setID(null);
639             errln("FAIL: Null allowed in setID");
640         } catch (NullPointerException e) {}
641 
642         TimeZone save = TimeZone.getDefault();
643         try {
644             TimeZone.setDefault(null);
645         } catch (NullPointerException e) {
646             errln("FAIL: Null NOT allowed in setDefault");
647         } finally {
648             TimeZone.setDefault(save);
649         }
650 
651         // SimpleTimeZone API
652         SimpleTimeZone s = null;
653         try {
654             s = new SimpleTimeZone(0, null);
655             errln("FAIL: Null allowed in SimpleTimeZone(2)");
656         } catch (NullPointerException e) {}
657         try {
658             s = new SimpleTimeZone(0, null, 0, 1, 0, 0, 0, 1, 0, 0);
659             errln("FAIL: Null allowed in SimpleTimeZone(10)");
660         } catch (NullPointerException e) {}
661         try {
662             s = new SimpleTimeZone(0, null, 0, 1, 0, 0, 0, 1, 0, 0, 1000);
663             errln("FAIL: Null allowed in SimpleTimeZone(11)");
664         } catch (NullPointerException e) {}
665     }
666 
667     /**
668      * TimeZone broken at midnight.  The TimeZone code fails to handle
669      * transitions at midnight correctly.
670      */
671     @SuppressWarnings("deprecation")
Test4162593()672     public void Test4162593() {
673         SimpleDateFormat fmt = new SimpleDateFormat("z", Locale.US);
674         final int ONE_HOUR = 60*60*1000;
675         TimeZone initialZone = TimeZone.getDefault();
676 
677         SimpleTimeZone asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/,
678             Calendar.OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR,
679             Calendar.MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR);
680 
681         /* Zone
682          * Starting time
683          * Transition expected between start+1H and start+2H
684          */
685         Object[] DATA = {
686             new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/,
687                 Calendar.APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR,
688                 Calendar.OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR),
689             new int[] {98, Calendar.SEPTEMBER, 30, 22, 0},
690             Boolean.TRUE,
691 
692             asuncion,
693             new int[] {100, Calendar.FEBRUARY, 28, 22, 0},
694             Boolean.FALSE,
695 
696             asuncion,
697             new int[] {100, Calendar.FEBRUARY, 29, 22, 0},
698             Boolean.TRUE,
699         };
700 
701         String[] zone = new String[4];
702 
703         try {
704             for (int j=0; j<DATA.length; j+=3) {
705                 TimeZone tz = (TimeZone)DATA[j];
706                 TimeZone.setDefault(tz);
707                 fmt.setTimeZone(tz);
708 
709                 // Must construct the Date object AFTER setting the default zone
710                 int[] p = (int[])DATA[j+1];
711                 Date d = new Date(p[0], p[1], p[2], p[3], p[4]);
712                 boolean transitionExpected = ((Boolean)DATA[j+2]).booleanValue();
713 
714                 logln(tz.getID() + ":");
715                 for (int i=0; i<4; ++i) {
716                     zone[i] = fmt.format(d);
717                     logln("" + i + ": " + d);
718                     d = new Date(d.getTime() + ONE_HOUR);
719                 }
720                 if (zone[0].equals(zone[1]) &&
721                     (zone[1].equals(zone[2]) != transitionExpected) &&
722                     zone[2].equals(zone[3])) {
723                     logln("Ok: transition " + transitionExpected);
724                 } else {
725                     errln("Fail: boundary transition incorrect");
726                 }
727             }
728         }
729         finally {
730             // restore the initial time zone so that this test case
731             // doesn't affect the others.
732             TimeZone.setDefault(initialZone);
733         }
734     }
735 
736     /**
737      * TimeZone broken in last hour of year
738      */
Test4173604()739     public void Test4173604() {
740         // test both SimpleTimeZone and ZoneInfo objects.
741         // @since 1.4
742         sub4173604(getPST());
743         sub4173604(TimeZone.getTimeZone("PST"));
744     }
745 
sub4173604(TimeZone pst)746     private void sub4173604(TimeZone pst) {
747         int o22 = pst.getOffset(1, 1998, 11, 31, Calendar.THURSDAY, 22*60*60*1000);
748         int o23 = pst.getOffset(1, 1998, 11, 31, Calendar.THURSDAY, 23*60*60*1000);
749         int o00 = pst.getOffset(1, 1999, 0, 1, Calendar.FRIDAY, 0);
750         if (o22 != o23 || o22 != o00) {
751             errln("Offsets should be the same (for PST), but got: " +
752                   "12/31 22:00 " + o22 +
753                   ", 12/31 23:00 " + o23 +
754                   ", 01/01 00:00 " + o00);
755         }
756 
757         GregorianCalendar cal = new GregorianCalendar();
758         cal.setTimeZone(pst);
759         cal.clear();
760         cal.set(1998, Calendar.JANUARY, 1);
761         int lastDST = cal.get(Calendar.DST_OFFSET);
762         int transitions = 0;
763         int delta = 5;
764         while (cal.get(Calendar.YEAR) < 2000) {
765             cal.add(Calendar.MINUTE, delta);
766             if (cal.get(Calendar.DST_OFFSET) != lastDST) {
767                 ++transitions;
768                 Calendar t = (Calendar)cal.clone();
769                 t.add(Calendar.MINUTE, -delta);
770                 logln(t.getTime() + "  " + t.get(Calendar.DST_OFFSET));
771                 logln(cal.getTime() + "  " + (lastDST=cal.get(Calendar.DST_OFFSET)));
772             }
773         }
774         if (transitions != 4) {
775             errln("Saw " + transitions + " transitions; should have seen 4");
776         }
777     }
778 
779     /**
780      * getDisplayName doesn't work with unusual savings/offsets.
781      */
782     @SuppressWarnings("deprecation")
Test4176686()783     public void Test4176686() {
784         // Construct a zone that does not observe DST but
785         // that does have a DST savings (which should be ignored).
786         int offset = 90 * 60000; // 1:30
787         SimpleTimeZone z1 = new SimpleTimeZone(offset, "_std_zone_");
788         z1.setDSTSavings(45 * 60000); // 0:45
789 
790         // Construct a zone that observes DST for the first 6 months.
791         SimpleTimeZone z2 = new SimpleTimeZone(offset, "_dst_zone_");
792         z2.setDSTSavings(45 * 60000); // 0:45
793         z2.setStartRule(Calendar.JANUARY, 1, 0);
794         z2.setEndRule(Calendar.JULY, 1, 0);
795 
796         // Also check DateFormat
797         DateFormat fmt1 = new SimpleDateFormat("z");
798         fmt1.setTimeZone(z1); // Format uses standard zone
799         DateFormat fmt2 = new SimpleDateFormat("z");
800         fmt2.setTimeZone(z2); // Format uses DST zone
801         Date dst = new Date(1970-1900, Calendar.FEBRUARY, 1); // Time in DST
802         Date std = new Date(1970-1900, Calendar.AUGUST, 1); // Time in standard
803 
804         // Description, Result, Expected Result
805         String[] DATA = {
806             "getDisplayName(false, SHORT)/std zone",
807             z1.getDisplayName(false, TimeZone.SHORT), "GMT+01:30",
808             "getDisplayName(false, LONG)/std zone",
809             z1.getDisplayName(false, TimeZone.LONG ), "GMT+01:30",
810             "getDisplayName(true, SHORT)/std zone",
811             z1.getDisplayName(true, TimeZone.SHORT), "GMT+01:30",
812             "getDisplayName(true, LONG)/std zone",
813             z1.getDisplayName(true, TimeZone.LONG ), "GMT+01:30",
814             "getDisplayName(false, SHORT)/dst zone",
815             z2.getDisplayName(false, TimeZone.SHORT), "GMT+01:30",
816             "getDisplayName(false, LONG)/dst zone",
817             z2.getDisplayName(false, TimeZone.LONG ), "GMT+01:30",
818             "getDisplayName(true, SHORT)/dst zone",
819             z2.getDisplayName(true, TimeZone.SHORT), "GMT+02:15",
820             "getDisplayName(true, LONG)/dst zone",
821             z2.getDisplayName(true, TimeZone.LONG ), "GMT+02:15",
822             "DateFormat.format(std)/std zone", fmt1.format(std), "GMT+01:30",
823             "DateFormat.format(dst)/std zone", fmt1.format(dst), "GMT+01:30",
824             "DateFormat.format(std)/dst zone", fmt2.format(std), "GMT+01:30",
825             "DateFormat.format(dst)/dst zone", fmt2.format(dst), "GMT+02:15",
826         };
827 
828         for (int i=0; i<DATA.length; i+=3) {
829             if (!DATA[i+1].equals(DATA[i+2])) {
830                 errln("FAIL: " + DATA[i] + " -> " + DATA[i+1] + ", exp " + DATA[i+2]);
831             }
832         }
833     }
834 
835     /**
836      * SimpleTimeZone allows invalid DOM values.
837      */
Test4184229()838     public void Test4184229() {
839         SimpleTimeZone zone = null;
840         try {
841             zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0);
842             errln("Failed. No exception has been thrown for DOM -1 startDay");
843         } catch(IllegalArgumentException e) {
844             logln("(a) " + e.getMessage());
845         }
846         try {
847             zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0);
848             errln("Failed. No exception has been thrown for DOM -1 endDay");
849         } catch(IllegalArgumentException e) {
850             logln("(b) " + e.getMessage());
851         }
852         try {
853             zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, 1000);
854             errln("Failed. No exception has been thrown for DOM -1 startDay +savings");
855         } catch(IllegalArgumentException e) {
856             logln("(c) " + e.getMessage());
857         }
858         try {
859             zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000);
860             errln("Failed. No exception has been thrown for DOM -1 endDay +savings");
861         } catch(IllegalArgumentException e) {
862             logln("(d) " + e.getMessage());
863         }
864         // Make a valid constructor call for subsequent tests.
865         zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0);
866         try {
867             zone.setStartRule(0, -1, 0, 0);
868             errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings");
869         } catch(IllegalArgumentException e) {
870             logln("(e) " + e.getMessage());
871         }
872         try {
873             zone.setStartRule(0, -1, 0);
874             errln("Failed. No exception has been thrown for DOM -1 setStartRule");
875         } catch(IllegalArgumentException e) {
876             logln("(f) " + e.getMessage());
877         }
878         try {
879             zone.setEndRule(0, -1, 0, 0);
880             errln("Failed. No exception has been thrown for DOM -1 setEndRule +savings");
881         } catch(IllegalArgumentException e) {
882             logln("(g) " + e.getMessage());
883         }
884         try {
885             zone.setEndRule(0, -1, 0);
886             errln("Failed. No exception has been thrown for DOM -1 setEndRule");
887         } catch(IllegalArgumentException e) {
888             logln("(h) " + e.getMessage());
889         }
890     }
891 
892     /**
893      * SimpleTimeZone.getOffset() throws IllegalArgumentException when to get
894      * of 2/29/1996 (leap day).
895      */
Test4208960()896     public void Test4208960 () {
897         // test both SimpleTimeZone and ZoneInfo objects.
898         // @since 1.4
899         sub4208960(getPST());
900         sub4208960(TimeZone.getTimeZone("PST"));
901     }
902 
sub4208960(TimeZone tz)903     private void sub4208960(TimeZone tz) {
904         try {
905             int offset = tz.getOffset(GregorianCalendar.AD, 1996, Calendar.FEBRUARY, 29,
906                                       Calendar.THURSDAY, 0);
907         } catch (IllegalArgumentException e) {
908             errln("FAILED: to get TimeZone.getOffset(2/29/96)");
909         }
910         try {
911             int offset = tz.getOffset(GregorianCalendar.AD, 1997, Calendar.FEBRUARY, 29,
912                                       Calendar.THURSDAY, 0);
913             errln("FAILED: TimeZone.getOffset(2/29/97) expected to throw Exception.");
914         } catch (IllegalArgumentException e) {
915             logln("got IllegalArgumentException");
916         }
917     }
918 
919     /**
920      * 4966229: java.util.Date methods may works incorrect.
921      * sun.util.calendar.ZoneInfo doesn't clone properly.
922      */
923     @SuppressWarnings("deprecation")
Test4966229()924     public void Test4966229() {
925         TimeZone savedTZ = TimeZone.getDefault();
926         try {
927             TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
928             Date d = new Date(2100-1900, 5, 1); // specify year >2037
929             TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
930 
931             Calendar cal = new GregorianCalendar(tz);
932             cal.setTime(d);
933 
934             // Change the raw offset in tz
935             int offset = tz.getRawOffset();
936             tz.setRawOffset(0);
937 
938             TimeZone tz2 = (TimeZone) tz.clone();
939             Calendar cal2 = new GregorianCalendar(tz2);
940             cal2.setTime(d);
941             int expectedHourOfDay = cal2.get(cal.HOUR_OF_DAY);
942 
943             // Restore the GMT offset in tz which shouldn't affect tz2
944             tz.setRawOffset(offset);
945             cal2.setTime(d);
946             int hourOfDay = cal2.get(cal.HOUR_OF_DAY);
947             if (hourOfDay != expectedHourOfDay) {
948                 errln("wrong hour of day: got: " + hourOfDay
949                       + ", expected: " + expectedHourOfDay);
950             }
951         } finally {
952             TimeZone.setDefault(savedTZ);
953         }
954     }
955 
956     /**
957      * 6433179: (tz) Incorrect DST end for America/Winnipeg and Canada/Central in 2038+
958      */
Test6433179()959     public void Test6433179() {
960         // Use the old America/Winnipeg rule for testing. Note that
961         // startMode is WALL_TIME for testing. It's actually
962         // STANDARD_TIME, though.
963         //Rule  Winn    1966    2005    -       Oct     lastSun 2:00s   0       S
964         //Rule  Winn    1987    2005    -       Apr     Sun>=1  2:00s   1:00    D
965         TimeZone tz = new SimpleTimeZone(-6*ONE_HOUR, "America/Winnipeg",
966           Calendar.APRIL, 1, -Calendar.SUNDAY, 2*ONE_HOUR, SimpleTimeZone.WALL_TIME,
967           Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*ONE_HOUR, SimpleTimeZone.STANDARD_TIME,
968           1*ONE_HOUR);
969         Calendar cal = Calendar.getInstance(tz, Locale.US);
970         cal.clear();
971         cal.set(2039, Calendar.OCTOBER, 1);
972         cal.getTime();
973         cal.set(cal.DAY_OF_WEEK, cal.SUNDAY);
974         cal.set(cal.DAY_OF_WEEK_IN_MONTH, -1);
975         cal.add(Calendar.HOUR_OF_DAY, 2);
976         if (cal.get(cal.DST_OFFSET) == 0) {
977             errln("Should still be in DST.");
978         }
979     }
980 
981     private static final int ONE_HOUR = 60 * 60 * 1000;
982     /**
983      * Returns an instance of SimpleTimeZone for
984      * "PST". (TimeZone.getTimeZone() no longer returns a
985      * SimpleTimeZone object.)
986      * @since 1.4
987      */
getPST()988     private SimpleTimeZone getPST() {
989         return new SimpleTimeZone(-8*ONE_HOUR, "PST",
990                                   Calendar.APRIL, 1, -Calendar.SUNDAY, 2*ONE_HOUR,
991                                   Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*ONE_HOUR,
992                                   1*ONE_HOUR);
993     }
994 }
995 //eof
996