2 *******************************************************************************
3 * Copyright (C) 2000-2013, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
10 * @bug 4052967 4073209 4073215 4084933 4096952 4109314 4126678 4151406 4151429
11 * @bug 4154525 4154537 4154542 4154650 4159922 4162593 4173604 4176686 4184229 4208960
14 package com.ibm.icu.dev.test.timezone;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.IOException;
18 import java.io.ObjectInputStream;
19 import java.io.ObjectOutputStream;
20 import java.security.AccessControlException;
21 import java.util.Date;
22 import java.util.Locale;
24 import com.ibm.icu.dev.test.TestFmwk;
25 import com.ibm.icu.text.DateFormat;
26 import com.ibm.icu.text.SimpleDateFormat;
27 import com.ibm.icu.util.Calendar;
28 import com.ibm.icu.util.GregorianCalendar;
29 import com.ibm.icu.util.SimpleTimeZone;
30 import com.ibm.icu.util.TimeZone;
31 import com.ibm.icu.util.ULocale;
33 public class TimeZoneRegression extends TestFmwk {
35 public static void main(String[] args) throws Exception {
36 new TimeZoneRegression().run(args);
39 public void Test4052967() {
40 logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***");
41 String id = TimeZone.getDefault().getID();
44 logln("user.timezone: " + System.getProperty("user.timezone", "<not set>"));
45 } catch (AccessControlException e) {
46 // user.timezone is a protected system property - ignore
48 logln("TimeZone.getDefault().getID(): " + id);
49 logln(new Date().toString());
50 logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");
52 catch (SecurityException e) {
53 warnln("security exception: " + e.toString());
57 public void Test4073209() {
58 TimeZone z1 = TimeZone.getTimeZone("PST");
59 TimeZone z2 = TimeZone.getTimeZone("PST");
60 if (z1 == z2) errln("Fail: TimeZone should return clones");
63 public void Test4073215() {
64 SimpleTimeZone z = new SimpleTimeZone(0, "GMT");
65 if (z.useDaylightTime())
66 errln("Fail: Fix test to start with non-DST zone");
67 z.setStartRule(Calendar.FEBRUARY, 1, Calendar.SUNDAY, 0);
68 z.setEndRule(Calendar.MARCH, -1, Calendar.SUNDAY, 0);
69 if (!z.useDaylightTime())
70 errln("Fail: DST not active");
71 Calendar tempcal = Calendar.getInstance();
73 tempcal.setTimeZone(z);
74 tempcal.set(1997, Calendar.JANUARY, 31);
75 Date d1 = tempcal.getTime();
76 if (z.inDaylightTime(d1)) {
77 errln("Fail: DST not working as expected");
80 tempcal.set(1997, Calendar.MARCH, 1);
81 Date d2 = tempcal.getTime();
82 if (!z.inDaylightTime(d2)) {
83 errln("Fail: DST not working as expected");
86 tempcal.set(1997, Calendar.MARCH, 31);
87 Date d3 = tempcal.getTime();
88 if (z.inDaylightTime(d3)) {
89 errln("Fail: DST not working as expected");
94 * The expected behavior of TimeZone around the boundaries is:
95 * (Assume transition time of 2:00 AM)
96 * day of onset 1:59 AM STD = display name 1:59 AM ST
97 * 2:00 AM STD = display name 3:00 AM DT
98 * day of end 0:59 AM STD = display name 1:59 AM DT
99 * 1:00 AM STD = display name 1:00 AM ST
101 public void Test4084933() {
102 TimeZone tz = TimeZone.getTimeZone("PST");
104 long offset1 = tz.getOffset(1,
105 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (2*60*60*1000));
106 long offset2 = tz.getOffset(1,
107 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (2*60*60*1000)-1);
109 long offset3 = tz.getOffset(1,
110 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (1*60*60*1000));
111 long offset4 = tz.getOffset(1,
112 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (1*60*60*1000)-1);
115 * The following was added just for consistency. It shows that going *to* Daylight
116 * Savings Time (PDT) does work at 2am.
119 long offset5 = tz.getOffset(1,
120 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (2*60*60*1000));
121 long offset6 = tz.getOffset(1,
122 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (2*60*60*1000)-1);
124 long offset7 = tz.getOffset(1,
125 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (1*60*60*1000));
126 long offset8 = tz.getOffset(1,
127 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (1*60*60*1000)-1);
129 long SToffset = -8 * 60*60*1000L;
130 long DToffset = -7 * 60*60*1000L;
131 if (offset1 != SToffset || offset2 != SToffset ||
132 offset3 != SToffset || offset4 != DToffset ||
133 offset5 != DToffset || offset6 != SToffset ||
134 offset7 != SToffset || offset8 != SToffset)
135 warnln("Fail: TimeZone misbehaving");
138 public void Test4096952() {
139 String[] ZONES = { "GMT", "MET", "IST" };
142 for (int i=0; i<ZONES.length; ++i) {
143 TimeZone zone = TimeZone.getTimeZone(ZONES[i]);
144 if (!zone.getID().equals(ZONES[i]))
145 warnln("Fail: Test broken; zones not instantiating");
147 ByteArrayOutputStream baos;
148 ObjectOutputStream ostream =
149 new ObjectOutputStream(baos = new
150 ByteArrayOutputStream());
151 ostream.writeObject(zone);
154 ObjectInputStream istream =
155 new ObjectInputStream(new
156 ByteArrayInputStream(baos.toByteArray()));
157 TimeZone frankenZone = (TimeZone) istream.readObject();
158 //logln("Zone: " + zone);
159 //logln("FrankenZone: " + frankenZone);
160 if (!zone.equals(frankenZone)) {
161 logln("TimeZone " + zone.getID() +
162 " not equal to serialized/deserialized one");
166 if (!pass) errln("Fail: TimeZone serialization/equality bug");
168 catch (IOException e) {
172 catch (ClassNotFoundException e) {
178 public void Test4109314() {
179 GregorianCalendar testCal = (GregorianCalendar)Calendar.getInstance();
180 TimeZone PST = TimeZone.getTimeZone("PST");
181 java.util.Calendar tempcal = java.util.Calendar.getInstance();
183 tempcal.set(1998,Calendar.APRIL,4,22,0);
184 Date d1 = tempcal.getTime();
185 tempcal.set(1998,Calendar.APRIL,5,6,0);
186 Date d2 = tempcal.getTime();
187 tempcal.set(1998,Calendar.OCTOBER,24,22,0);
188 Date d3 = tempcal.getTime();
189 tempcal.set(1998,Calendar.OCTOBER,25,6,0);
190 Date d4 = tempcal.getTime();
191 Object[] testData = {
196 for (int i=0; i<testData.length; i+=3) {
197 testCal.setTimeZone((TimeZone) testData[i]);
198 long t = ((Date)testData[i+1]).getTime();
199 Date end = (Date) testData[i+2];
200 while (t < end.getTime()) {
201 testCal.setTime(new Date(t));
202 if (!checkCalendar314(testCal, (TimeZone) testData[i]))
207 if (!pass) errln("Fail: TZ API inconsistent");
210 boolean checkCalendar314(GregorianCalendar testCal, TimeZone testTZ) {
211 // GregorianCalendar testCal = (GregorianCalendar)aCal.clone();
213 final int ONE_DAY = 24*60*60*1000;
215 int tzOffset, tzRawOffset;
216 Float tzOffsetFloat,tzRawOffsetFloat;
217 // Here is where the user made an error. They were passing in the value of
218 // the MILLSECOND field; you need to pass in the millis in the day in STANDARD
220 int millis = testCal.get(Calendar.MILLISECOND) +
221 1000 * (testCal.get(Calendar.SECOND) +
222 60 * (testCal.get(Calendar.MINUTE) +
223 60 * (testCal.get(Calendar.HOUR_OF_DAY)))) -
224 testCal.get(Calendar.DST_OFFSET);
226 /* Fix up millis to be in range. ASSUME THAT WE ARE NOT AT THE
227 * BEGINNING OR END OF A MONTH. We must add this code because
228 * getOffset() has been changed to be more strict about the parameters
229 * it receives -- it turns out that this test was passing in illegal
231 int date = testCal.get(Calendar.DATE);
232 int dow = testCal.get(Calendar.DAY_OF_WEEK);
236 dow = Calendar.SUNDAY + ((dow - Calendar.SUNDAY + 6) % 7);
238 while (millis >= ONE_DAY) {
241 dow = Calendar.SUNDAY + ((dow - Calendar.SUNDAY + 1) % 7);
244 tzOffset = testTZ.getOffset(testCal.get(Calendar.ERA),
245 testCal.get(Calendar.YEAR),
246 testCal.get(Calendar.MONTH),
250 tzRawOffset = testTZ.getRawOffset();
251 tzOffsetFloat = new Float((float)tzOffset/(float)3600000);
252 tzRawOffsetFloat = new Float((float)tzRawOffset/(float)3600000);
254 Date testDate = testCal.getTime();
256 boolean inDaylightTime = testTZ.inDaylightTime(testDate);
257 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm");
258 sdf.setCalendar(testCal);
259 String inDaylightTimeString;
265 inDaylightTimeString = " DST ";
266 passed = (tzOffset == (tzRawOffset + 3600000));
270 inDaylightTimeString = " ";
271 passed = (tzOffset == tzRawOffset);
274 String output = testTZ.getID() + " " + sdf.format(testDate) +
275 " Offset(" + tzOffsetFloat + ")" +
276 " RawOffset(" + tzRawOffsetFloat + ")" +
277 " " + millis/(float)3600000 + " " +
278 inDaylightTimeString;
285 if (passed) logln(output); else errln(output);
292 * Yet another _alleged_ bug in TimeZone.getOffset(), a method that never
293 * should have been made public. It's simply too hard to use correctly.
295 * The original test code failed to do the following:
296 * (1) Call Calendar.setTime() before getting the fields!
297 * (2) Use the right millis (as usual) for getOffset(); they were passing
298 * in the MILLIS field, instead of the STANDARD MILLIS IN DAY.
299 * When you fix these two problems, the test passes, as expected.
301 public void Test4126678() {
302 // Note: this test depends on the PST time zone.
303 TimeZone initialZone = TimeZone.getDefault();
304 Calendar cal = Calendar.getInstance();
305 TimeZone tz = TimeZone.getTimeZone("PST");
306 TimeZone.setDefault(tz);
309 java.util.Calendar tempcal = java.util.Calendar.getInstance();
311 tempcal.set(1998, Calendar.APRIL, 5, 10, 0);
312 Date dt = tempcal.getTime();
313 // the dt value is local time in PST.
314 if (!tz.inDaylightTime(dt))
315 errln("We're not in Daylight Savings Time and we should be.\n");
318 int era = cal.get(Calendar.ERA);
319 int year = cal.get(Calendar.YEAR);
320 int month = cal.get(Calendar.MONTH);
321 int day = cal.get(Calendar.DATE);
322 int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
323 int millis = cal.get(Calendar.MILLISECOND) +
324 (cal.get(Calendar.SECOND) +
325 (cal.get(Calendar.MINUTE) +
326 (cal.get(Calendar.HOUR) * 60) * 60) * 1000) -
327 cal.get(Calendar.DST_OFFSET);
329 long offset = tz.getOffset(era, year, month, day, dayOfWeek, millis);
330 long raw_offset = tz.getRawOffset();
331 if (offset == raw_offset)
332 errln("Offsets should not match when in DST");
334 // restore the initial time zone so that this test case
335 // doesn't affect the others.
336 TimeZone.setDefault(initialZone);
340 * TimeZone.getAvailableIDs(int) throws exception for certain values,
341 * due to a faulty constant in TimeZone.java.
343 public void Test4151406() {
345 for (int h=-28; h<=30; ++h) {
346 // h is in half-hours from GMT; rawoffset is in millis
347 int rawoffset = h * 1800000;
348 int hh = (h<0) ? -h : h;
349 String hname = ((h<0) ? "GMT-" : "GMT+") +
350 ((hh/2 < 10) ? "0" : "") +
352 ((hh%2==0) ? "00" : "30");
354 String[] ids = TimeZone.getAvailableIDs(rawoffset);
355 if (ids.length > max) max = ids.length;
356 logln(hname + ' ' + ids.length +
357 ((ids.length > 0) ? (" e.g. " + ids[0]) : ""));
358 } catch (Exception e) {
359 errln(hname + ' ' + "Fail: " + e);
362 logln("Maximum zones per offset = " + max);
365 public void Test4151429() {
367 TimeZone tz = TimeZone.getTimeZone("GMT");
368 /*String name =*/ tz.getDisplayName(true, Integer.MAX_VALUE,
369 Locale.getDefault());
370 errln("IllegalArgumentException not thrown by TimeZone.getDisplayName()");
371 } catch(IllegalArgumentException e) {
372 System.out.print("");
377 * SimpleTimeZone accepts illegal DST savings values. These values
378 * must be non-zero. There is no upper limit at this time.
380 public void Test4154525() {
381 final int GOOD = 1, BAD = 0;
387 Integer.MIN_VALUE, BAD,
388 // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time
390 for (int i=0; i<DATA.length; i+=2) {
391 int savings = DATA[i];
392 boolean valid = DATA[i+1] == GOOD;
393 String method = null;
394 for (int j=0; j<2; ++j) {
398 method = "constructor";
399 SimpleTimeZone z = new SimpleTimeZone(0, "id",
400 Calendar.JANUARY, 1, 0, 0,
401 Calendar.MARCH, 1, 0, 0,
402 savings); // <- what we're interested in
405 method = "setDSTSavings()";
406 z = new SimpleTimeZone(0, "GMT");
407 z.setDSTSavings(savings);
411 logln("Pass: DST savings of " + savings + " accepted by " + method);
413 errln("Fail: DST savings of " + savings + " accepted by " + method);
415 } catch (IllegalArgumentException e) {
417 errln("Fail: DST savings of " + savings + " to " + method + " gave " + e);
419 logln("Pass: DST savings of " + savings + " to " + method + " gave " + e);
427 * SimpleTimeZone.hasSameRules() doesn't work for zones with no DST
428 * and different DST parameters.
430 public void Test4154537() {
431 // tz1 and tz2 have no DST and different rule parameters
432 SimpleTimeZone tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0);
433 SimpleTimeZone tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0);
434 // tza and tzA have the same rule params
435 SimpleTimeZone tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0);
436 SimpleTimeZone tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0);
437 // tzb differs from tza
438 SimpleTimeZone tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0);
439 if (tz1.useDaylightTime() || tz2.useDaylightTime() ||
440 !tza.useDaylightTime() || !tzA.useDaylightTime() ||
441 !tzb.useDaylightTime()) {
442 errln("Test is broken -- rewrite it");
444 if (!tza.hasSameRules(tzA) || tza.hasSameRules(tzb)) {
445 errln("Fail: hasSameRules() broken for zones with rules");
447 if (!tz1.hasSameRules(tz2)) {
448 errln("Fail: hasSameRules() returns false for zones without rules");
449 errln("zone 1 = " + tz1);
450 errln("zone 2 = " + tz2);
455 * SimpleTimeZone constructors, setStartRule(), and setEndRule() don't
456 * check for out-of-range arguments.
458 public void Test4154542() {
462 final int GOOD_MONTH = Calendar.JANUARY;
463 final int GOOD_DAY = 1;
464 final int GOOD_DAY_OF_WEEK = Calendar.SUNDAY;
465 final int GOOD_TIME = 0;
468 GOOD, Integer.MIN_VALUE, 0, Integer.MAX_VALUE, Integer.MIN_VALUE,
469 GOOD, Calendar.JANUARY, -5, Calendar.SUNDAY, 0,
470 GOOD, Calendar.DECEMBER, 5, Calendar.SATURDAY, 24*60*60*1000-1,
471 BAD, Calendar.DECEMBER, 5, Calendar.SATURDAY, 24*60*60*1000+1,
472 BAD, Calendar.DECEMBER, 5, Calendar.SATURDAY, -1,
473 BAD, Calendar.JANUARY, -6, Calendar.SUNDAY, 0,
474 BAD, Calendar.DECEMBER, 6, Calendar.SATURDAY, 24*60*60*1000,
475 GOOD, Calendar.DECEMBER, 1, 0, 0,
476 GOOD, Calendar.DECEMBER, 31, 0, 0,
477 BAD, Calendar.APRIL, 31, 0, 0,
478 BAD, Calendar.DECEMBER, 32, 0, 0,
479 BAD, Calendar.JANUARY-1, 1, Calendar.SUNDAY, 0,
480 BAD, Calendar.DECEMBER+1, 1, Calendar.SUNDAY, 0,
481 GOOD, Calendar.DECEMBER, 31, -Calendar.SUNDAY, 0,
482 GOOD, Calendar.DECEMBER, 31, -Calendar.SATURDAY, 0,
483 BAD, Calendar.DECEMBER, 32, -Calendar.SATURDAY, 0,
484 BAD, Calendar.DECEMBER, -32, -Calendar.SATURDAY, 0,
485 BAD, Calendar.DECEMBER, 31, -Calendar.SATURDAY-1, 0,
487 SimpleTimeZone zone = new SimpleTimeZone(0, "Z");
488 for (int i=0; i<DATA.length; i+=5) {
489 boolean shouldBeGood = (DATA[i] == GOOD);
490 int month = DATA[i+1];
492 int dayOfWeek = DATA[i+3];
493 int time = DATA[i+4];
497 zone.setStartRule(month, day, dayOfWeek, time);
498 } catch (IllegalArgumentException e) {
501 if ((ex == null) != shouldBeGood) {
502 errln("setStartRule(month=" + month + ", day=" + day +
503 ", dayOfWeek=" + dayOfWeek + ", time=" + time +
504 (shouldBeGood ? (") should work but throws " + ex)
505 : ") should fail but doesn't"));
510 zone.setEndRule(month, day, dayOfWeek, time);
511 } catch (IllegalArgumentException e) {
514 if ((ex == null) != shouldBeGood) {
515 errln("setEndRule(month=" + month + ", day=" + day +
516 ", dayOfWeek=" + dayOfWeek + ", time=" + time +
517 (shouldBeGood ? (") should work but throws " + ex)
518 : ") should fail but doesn't"));
523 /*SimpleTimeZone temp =*/ new SimpleTimeZone(0, "Z",
524 month, day, dayOfWeek, time,
525 GOOD_MONTH, GOOD_DAY, GOOD_DAY_OF_WEEK, GOOD_TIME);
526 } catch (IllegalArgumentException e) {
529 if ((ex == null) != shouldBeGood) {
530 errln("SimpleTimeZone(month=" + month + ", day=" + day +
531 ", dayOfWeek=" + dayOfWeek + ", time=" + time +
532 (shouldBeGood ? (", <end>) should work but throws " + ex)
533 : ", <end>) should fail but doesn't"));
538 /*SimpleTimeZone temp = */new SimpleTimeZone(0, "Z",
539 GOOD_MONTH, GOOD_DAY, GOOD_DAY_OF_WEEK, GOOD_TIME,
540 month, day, dayOfWeek, time);
542 } catch (IllegalArgumentException e) {
545 if ((ex == null) != shouldBeGood) {
546 errln("SimpleTimeZone(<start>, month=" + month + ", day=" + day +
547 ", dayOfWeek=" + dayOfWeek + ", time=" + time +
548 (shouldBeGood ? (") should work but throws " + ex)
549 : ") should fail but doesn't"));
555 * SimpleTimeZone.getOffset accepts illegal arguments.
557 public void Test4154650() {
558 final int GOOD=1, BAD=0;
559 final int GOOD_ERA=GregorianCalendar.AD, GOOD_YEAR=1998, GOOD_MONTH=Calendar.AUGUST;
560 final int GOOD_DAY=2, GOOD_DOW=Calendar.SUNDAY, GOOD_TIME=16*3600000;
562 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
564 GOOD, GregorianCalendar.BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
565 GOOD, GregorianCalendar.AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
566 BAD, GregorianCalendar.BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
567 BAD, GregorianCalendar.AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME,
569 GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME,
570 GOOD, GOOD_ERA, GOOD_YEAR, Calendar.DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME,
571 BAD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
572 BAD, GOOD_ERA, GOOD_YEAR, Calendar.DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME,
574 GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 1, GOOD_DOW, GOOD_TIME,
575 GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 31, GOOD_DOW, GOOD_TIME,
576 BAD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 0, GOOD_DOW, GOOD_TIME,
577 BAD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 32, GOOD_DOW, GOOD_TIME,
579 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SUNDAY, GOOD_TIME,
580 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SATURDAY, GOOD_TIME,
581 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SUNDAY-1, GOOD_TIME,
582 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SATURDAY+1, GOOD_TIME,
584 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0,
585 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1,
586 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1,
587 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000,
590 TimeZone tz = TimeZone.getDefault();
591 for (int i=0; i<DATA.length; i+=7) {
592 boolean good = DATA[i] == GOOD;
593 IllegalArgumentException e = null;
595 /*int offset =*/ tz.getOffset(DATA[i+1], DATA[i+2], DATA[i+3],
596 DATA[i+4], DATA[i+5], DATA[i+6]);
598 } catch (IllegalArgumentException ex) {
601 if (good != (e == null)) {
602 errln("Fail: getOffset(" +
603 DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " +
604 DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] +
605 (good ? (") threw " + e) : ") accepts invalid args"));
611 * TimeZone constructors allow null IDs.
613 public void Test4159922() {
616 // TimeZone API. Only hasSameRules() and setDefault() should
619 z = TimeZone.getTimeZone(null);
620 errln("FAIL: Null allowed in getTimeZone");
621 } catch (NullPointerException e) {
622 System.out.print("");
624 z = TimeZone.getTimeZone("GMT");
626 // {dlf} requiring cast for disambiguation is ok for compatibility since null
627 // is not a valid argument to this API
628 z.getDisplayName(false, TimeZone.SHORT, (ULocale)null);
629 errln("FAIL: Null allowed in getDisplayName(3)");
630 } catch (NullPointerException e) {
631 System.out.print("");
635 z.getDisplayName((ULocale)null);
636 errln("FAIL: Null allowed in getDisplayName(1)");
637 } catch (NullPointerException e) {
638 System.out.print("");
641 if (z.hasSameRules(null)) {
642 errln("FAIL: hasSameRules returned true");
644 } catch (NullPointerException e) {
645 errln("FAIL: Null NOT allowed in hasSameRules");
648 z.inDaylightTime(null);
649 errln("FAIL: Null allowed in inDaylightTime");
650 } catch (NullPointerException e) {
651 System.out.print("");
655 errln("FAIL: Null allowed in setID");
656 } catch (NullPointerException e) {
657 System.out.print("");
660 TimeZone save = TimeZone.getDefault();
662 TimeZone.setDefault(null);
663 } catch (NullPointerException e) {
664 errln("FAIL: Null NOT allowed in setDefault");
666 TimeZone.setDefault(save);
669 // SimpleTimeZone API
670 SimpleTimeZone s = null;
672 s = new SimpleTimeZone(0, null);
673 errln("FAIL: Null allowed in SimpleTimeZone(2)");
674 } catch (NullPointerException e) {
675 System.out.print("");
678 s = new SimpleTimeZone(0, null, 0, 1, 0, 0, 0, 1, 0, 0);
679 errln("FAIL: Null allowed in SimpleTimeZone(10)");
680 } catch (NullPointerException e) {
681 System.out.print("");
684 s = new SimpleTimeZone(0, null, 0, 1, 0, 0, 0, 1, 0, 0, 1000);
685 errln("FAIL: Null allowed in SimpleTimeZone(11)");
686 } catch (NullPointerException e) {
687 System.out.print("");
690 errln("FAIL: Did not get the expected Exception");
695 * TimeZone broken at midnight. The TimeZone code fails to handle
696 * transitions at midnight correctly.
698 public void Test4162593() {
699 SimpleDateFormat fmt = new SimpleDateFormat("z", Locale.US);
700 final int ONE_HOUR = 60*60*1000;
701 final float H = (float) ONE_HOUR;
702 TimeZone initialZone = TimeZone.getDefault();
703 SimpleDateFormat sdf = new SimpleDateFormat("MMM dd yyyy HH:mm z");
705 SimpleTimeZone asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/,
706 Calendar.OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR,
707 Calendar.MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR);
711 * Transition expected between start+1H and start+2H
714 new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/,
715 Calendar.APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR,
716 Calendar.OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR),
717 new int[] {1998, Calendar.SEPTEMBER, 30, 22, 0},
721 new int[] {2000, Calendar.FEBRUARY, 28, 22, 0},
725 new int[] {2000, Calendar.FEBRUARY, 29, 22, 0},
729 String[] zone = new String[4];
731 for (int j=0; j<DATA.length; j+=3) {
732 TimeZone tz = (TimeZone)DATA[j];
733 TimeZone.setDefault(tz);
737 // Must construct the Date object AFTER setting the default zone
738 int[] p = (int[])DATA[j+1];
739 Calendar cal = Calendar.getInstance();
741 cal.set(p[0], p[1], p[2], p[3], p[4]);
742 long start = cal.getTime().getTime();
743 boolean transitionExpected = ((Boolean)DATA[j+2]).booleanValue();
745 logln(tz.getID() + ":");
746 for (int i=0; i<4; ++i) {
747 Date d = new Date(start + i*ONE_HOUR);
748 zone[i] = fmt.format(d);
749 logln("" + i + ": " + sdf.format(d) + " => " + zone[i] +
750 " (" + d.getTime()/H + ")");
752 cal.set(p[0], p[1], p[2], 0, 0);
753 for (int i=0; i<4; ++i) {
755 int dom = p[2]+(h>=24?1:0);
759 cal.set(p[0], p[1], dom, 0, 0);
760 int off = tz.getOffset(GregorianCalendar.AD,
761 cal.get(Calendar.YEAR),
762 cal.get(Calendar.MONTH),
763 cal.get(Calendar.DATE),
764 cal.get(Calendar.DAY_OF_WEEK),
766 cal.add(Calendar.HOUR, h);
767 int dstOffset = cal.get(Calendar.DST_OFFSET);
768 logln("h=" + h + "; dom=" + dom +
769 "; ZONE_OFFSET=" + cal.get(Calendar.ZONE_OFFSET)/H +
770 "; DST_OFFSET=" + dstOffset/H +
771 "; getOffset()=" + off/H +
772 " (" + cal.getTime().getTime()/H + ")");
774 if (zone[0].equals(zone[1]) &&
775 (zone[1].equals(zone[2]) != transitionExpected) &&
776 zone[2].equals(zone[3])) {
777 logln("Ok: transition " + transitionExpected);
779 errln("FAIL: expected " +
780 (transitionExpected?"transition":"no transition"));
784 // restore the initial time zone so that this test case
785 // doesn't affect the others.
786 TimeZone.setDefault(initialZone);
790 * TimeZone broken in last hour of year
792 public void Test4173604() {
793 TimeZone pst = TimeZone.getTimeZone("PST");
794 int o22 = pst.getOffset(1, 1998, 11, 31, Calendar.THURSDAY, 22*60*60*1000);
795 int o23 = pst.getOffset(1, 1998, 11, 31, Calendar.THURSDAY, 23*60*60*1000);
796 int o00 = pst.getOffset(1, 1999, 0, 1, Calendar.FRIDAY, 0);
797 if (o22 != o23 || o22 != o00) {
798 errln("Offsets should be the same (for PST), but got: " +
799 "12/31 22:00 " + o22 +
800 ", 12/31 23:00 " + o23 +
801 ", 01/01 00:00 " + o00);
804 GregorianCalendar cal = new GregorianCalendar();
805 cal.setTimeZone(pst);
807 cal.set(1998, Calendar.JANUARY, 1);
808 int lastDST = cal.get(Calendar.DST_OFFSET);
811 while (cal.get(Calendar.YEAR) < 2000) {
812 cal.add(Calendar.MINUTE, delta);
813 if (cal.get(Calendar.DST_OFFSET) != lastDST) {
815 Calendar t = (Calendar)cal.clone();
816 t.add(Calendar.MINUTE, -delta);
817 logln(t.getTime() + " " + t.get(Calendar.DST_OFFSET));
818 logln(cal.getTime() + " " + (lastDST=cal.get(Calendar.DST_OFFSET)));
821 if (transitions != 4) {
822 errln("Saw " + transitions + " transitions; should have seen 4");
827 * getDisplayName doesn't work with unusual savings/offsets.
829 public void Test4176686() {
830 // Construct a zone that does not observe DST but
831 // that does have a DST savings (which should be ignored).
832 int offset = 90 * 60000; // 1:30
833 SimpleTimeZone z1 = new SimpleTimeZone(offset, "_std_zone_");
834 z1.setDSTSavings(45 * 60000); // 0:45
836 // Construct a zone that observes DST for the first 6 months.
837 SimpleTimeZone z2 = new SimpleTimeZone(offset, "_dst_zone_");
838 z2.setDSTSavings(45 * 60000); // 0:45
839 z2.setStartRule(Calendar.JANUARY, 1, 0);
840 z2.setEndRule(Calendar.JULY, 1, 0);
842 // Also check DateFormat
843 DateFormat fmt1 = new SimpleDateFormat("z");
844 fmt1.setTimeZone(z1); // Format uses standard zone
845 DateFormat fmt2 = new SimpleDateFormat("z");
846 fmt2.setTimeZone(z2); // Format uses DST zone
847 java.util.Calendar tempcal = java.util.Calendar.getInstance();
849 tempcal.set(1970, Calendar.FEBRUARY, 1);
850 Date dst = tempcal.getTime(); // Time in DST
851 tempcal.set(1970, Calendar.AUGUST, 1);
852 Date std = tempcal.getTime(); // Time in standard
854 // Description, Result, Expected Result
856 "getDisplayName(false, SHORT)/std zone",
857 z1.getDisplayName(false, TimeZone.SHORT), "GMT+1:30",
858 "getDisplayName(false, LONG)/std zone",
859 z1.getDisplayName(false, TimeZone.LONG ), "GMT+01:30",
860 "getDisplayName(true, SHORT)/std zone",
861 z1.getDisplayName(true, TimeZone.SHORT), "GMT+1:30",
862 "getDisplayName(true, LONG)/std zone",
863 z1.getDisplayName(true, TimeZone.LONG ), "GMT+01:30",
864 "getDisplayName(false, SHORT)/dst zone",
865 z2.getDisplayName(false, TimeZone.SHORT), "GMT+1:30",
866 "getDisplayName(false, LONG)/dst zone",
867 z2.getDisplayName(false, TimeZone.LONG ), "GMT+01:30",
868 "getDisplayName(true, SHORT)/dst zone",
869 z2.getDisplayName(true, TimeZone.SHORT), "GMT+2:15",
870 "getDisplayName(true, LONG)/dst zone",
871 z2.getDisplayName(true, TimeZone.LONG ), "GMT+02:15",
872 "DateFormat.format(std)/std zone", fmt1.format(std), "GMT+1:30",
873 "DateFormat.format(dst)/std zone", fmt1.format(dst), "GMT+1:30",
874 "DateFormat.format(std)/dst zone", fmt2.format(std), "GMT+1:30",
875 "DateFormat.format(dst)/dst zone", fmt2.format(dst), "GMT+2:15",
878 for (int i=0; i<DATA.length; i+=3) {
879 if (!DATA[i+1].equals(DATA[i+2])) {
880 errln("FAIL: " + DATA[i] + " -> " + DATA[i+1] + ", exp " + DATA[i+2]);
886 * SimpleTimeZone allows invalid DOM values.
888 // Current orgnaization of data in zoneinfor.res allows negative
889 // values from DOM so comment these tests out
891 public void Test4184229() {
892 SimpleTimeZone zone = null;
894 zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0);
895 errln("Failed. No exception has been thrown for DOM -1 startDay");
896 } catch(IllegalArgumentException e) {
897 logln("(a) " + e.getMessage());
900 zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0);
901 errln("Failed. No exception has been thrown for DOM -1 endDay");
902 } catch(IllegalArgumentException e) {
903 logln("(b) " + e.getMessage());
906 zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, 1000);
907 errln("Failed. No exception has been thrown for DOM -1 startDay +savings");
908 } catch(IllegalArgumentException e) {
909 logln("(c) " + e.getMessage());
912 zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000);
913 errln("Failed. No exception has been thrown for DOM -1 endDay +savings");
914 } catch(IllegalArgumentException e) {
915 logln("(d) " + e.getMessage());
917 // Make a valid constructor call for subsequent tests.
919 zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0);
922 zone.setStartRule(0, -1, 0, 0);
923 errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings");
924 } catch(IllegalArgumentException e) {
925 logln("(e) " + e.getMessage());
928 zone.setStartRule(0, -1, 0);
929 errln("Failed. No exception has been thrown for DOM -1 setStartRule");
930 } catch(IllegalArgumentException e) {
931 logln("(f) " + e.getMessage());
934 zone.setEndRule(0, -1, 0, 0);
935 errln("Failed. No exception has been thrown for DOM -1 setEndRule +savings");
936 } catch(IllegalArgumentException e) {
937 logln("(g) " + e.getMessage());
940 zone.setEndRule(0, -1, 0);
941 errln("Failed. No exception has been thrown for DOM -1 setEndRule");
942 } catch(IllegalArgumentException e) {
943 logln("(h) " + e.getMessage());
949 * SimpleTimeZone.getOffset() throws IllegalArgumentException when to get
950 * of 2/29/1996 (leap day).
952 public void Test4208960 () {
953 TimeZone tz = TimeZone.getTimeZone("PST");
955 /*int offset =*/ tz.getOffset(GregorianCalendar.AD, 1996, Calendar.FEBRUARY, 29,
956 Calendar.THURSDAY, 0);
958 } catch (IllegalArgumentException e) {
959 errln("FAILED: to get TimeZone.getOffset(2/29/96)");
962 /*int offset =*/ tz.getOffset(GregorianCalendar.AD, 1997, Calendar.FEBRUARY, 29,
963 Calendar.THURSDAY, 0);
965 warnln("FAILED: TimeZone.getOffset(2/29/97) expected to throw Exception.");
966 } catch (IllegalArgumentException e) {
967 logln("got IllegalArgumentException");
972 * Test to see if DateFormat understands zone equivalency groups. It
973 * might seem that this should be a DateFormat test, but it's really a
974 * TimeZone test -- the changes to DateFormat are minor.
976 * We use two known, zones that are equivalent, where one zone has
977 * localized name data, and the other doesn't, in some locale.
979 public void TestJ449() {
980 // not used String str;
982 // Modify the following three as necessary. The two IDs must
983 // specify two zones in the same equivalency group. One must have
984 // locale data in 'loc'; the other must not.
985 String idWithLocaleData = "America/Los_Angeles";
986 String idWithoutLocaleData = "PST"; // "US/Pacific";
987 Locale loc = new Locale("en", "", "");
989 TimeZone zoneWith = TimeZone.getTimeZone(idWithLocaleData);
990 TimeZone zoneWithout = TimeZone.getTimeZone(idWithoutLocaleData);
991 // Make sure we got valid zones
992 if (!(zoneWith.getID().equals(idWithLocaleData) &&
993 zoneWithout.getID().equals(idWithoutLocaleData))) {
994 warnln("Fail: Unable to create zones");
996 GregorianCalendar calWith = new GregorianCalendar(zoneWith);
997 GregorianCalendar calWithout = new GregorianCalendar(zoneWithout);
998 SimpleDateFormat fmt =
999 new SimpleDateFormat("MMM d yyyy hh:mm a zzz", loc);
1000 Date date = new Date(0L);
1001 fmt.setCalendar(calWith);
1002 String strWith = fmt.format(date);
1003 fmt.setCalendar(calWithout);
1004 String strWithout = fmt.format(date);
1005 if (strWith.equals(strWithout)) {
1006 logln("Ok: " + idWithLocaleData + " -> " +
1007 strWith + "; " + idWithoutLocaleData + " -> " +
1010 errln("FAIL: " + idWithLocaleData + " -> " +
1011 strWith + "; " + idWithoutLocaleData + " -> " +
1018 * getOffset returns wrong offset for days in early 20th century
1020 public void TestJ5134() {
1021 GregorianCalendar testCal = (GregorianCalendar)Calendar.getInstance();
1022 TimeZone icuEastern = TimeZone.getTimeZone("America/New_York");
1023 testCal.setTimeZone(icuEastern);
1024 testCal.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
1025 long time = testCal.getTimeInMillis();
1027 int offset = icuEastern.getOffset(time);
1028 if (offset != -18000000) {
1029 errln("FAIL: UTC offset in time zone America/New_York on Jan 1, 1900 -> " + offset);
1031 boolean isDst = icuEastern.inDaylightTime(new Date(time));
1033 errln("FAIL: DST is observed in time zone America/New_York on Jan 1, 1900");
1036 if (System.getProperty("java.vendor", "").startsWith("IBM") &&
1037 System.getProperty("java.version", "").equals("1.4.1")) {
1038 // IBM JDK 1.4.1 has a bug and fails to run this test case.
1041 java.util.TimeZone jdkEastern = java.util.TimeZone.getTimeZone("America/New_York");
1042 // Compare offset and DST observation with JDK and ICU for 50 years since 1900
1043 testCal.add(Calendar.YEAR, 50);
1044 long endTime = testCal.getTimeInMillis();
1047 while (time < endTime) {
1048 offset = icuEastern.getOffset(time);
1049 jdkOffset = jdkEastern.getOffset(time);
1050 if (offset != jdkOffset) {
1051 errln("FAIL: Incompatible UTC offset -> JDK:" + jdkOffset + "/ICU:" + offset + " [" + time + "]");
1053 Date d = new Date(time);
1054 isDst = icuEastern.inDaylightTime(d);
1055 isDstJdk = jdkEastern.inDaylightTime(d);
1056 if (isDst != isDstJdk) {
1057 errln("FAIL: Incompatible DST -> JDK:" + isDstJdk + "/ICU:" + isDst + " [" + time + "]");
1059 time += 24*60*60*1000L; // increment 1 day
1064 * Test setRawOffset works OK with system timezone
1066 public void TestT5280() {
1067 String[] tzids = TimeZone.getAvailableIDs();
1068 for (int i = 0; i < tzids.length; i++) {
1069 TimeZone tz = TimeZone.getTimeZone(tzids[i]);
1070 boolean useDst = tz.useDaylightTime();
1072 // Increase offset for 30 minutes
1073 int newRawOffset = tz.getRawOffset() + 30*60*1000;
1075 tz.setRawOffset(newRawOffset);
1076 } catch (Exception e) {
1077 errln("FAIL: setRawOffset throws an exception");
1079 int offset = tz.getRawOffset();
1080 if (offset != newRawOffset) {
1081 errln("FAIL: Modified zone(" + tz.getID() + ") - getRawOffset returns " + offset + "/ Expected: " + newRawOffset);
1084 // Check if DST observation status is not unexpectedly changed.
1085 boolean newDst = tz.useDaylightTime();
1086 if (useDst != newDst) {
1087 errln("FAIL: Modified zone(" + tz.getID() + ") - useDaylightTime has changed from " + useDst + " to " + newDst);
1089 // Make sure the offset is preserved in a clone
1090 TimeZone tzClone = (TimeZone)tz.clone();
1091 offset = tzClone.getRawOffset();
1092 if (offset != newRawOffset) {
1093 errln("FAIL: Cloned modified zone(" + tz.getID() + ") - getRawOffset returns " + offset + "/ Expected: " + newRawOffset);
1099 * Zone ID is not set by a SimpleTimeZone constructor
1101 public void TestT5432() {
1102 String tzid = "MyZone";
1105 // 2-arg constructor
1106 stz = new SimpleTimeZone(0, tzid);
1107 if (!tzid.equals(stz.getID())) {
1108 errln("FAIL: Bad zone id (" + stz.getID() + ") is returned - expected ("
1109 + tzid + ") [2-arg constructor]");
1112 // 10-arg constructor
1113 stz = new SimpleTimeZone(0, tzid, 3, -1, 1, 3600000, 9, -1, 1, 3600000);
1114 if (!tzid.equals(stz.getID())) {
1115 errln("FAIL: Bad zone id (" + stz.getID() + ") is returned - expected ("
1116 + tzid + ") [10-arg constructor]");
1119 // 11-arg constructor
1120 stz = new SimpleTimeZone(0, tzid, 3, -1, 1, 3600000, 9, -1, 1, 3600000, 3600000);
1121 if (!tzid.equals(stz.getID())) {
1122 errln("FAIL: Bad zone id (" + stz.getID() + ") is returned - expected ("
1123 + tzid + ") [11-arg constructor]");
1126 // 13-arg constructor - this version had a problem reported by trac#5432
1127 stz = new SimpleTimeZone(0, tzid, 3, -1, 1, 3600000, SimpleTimeZone.WALL_TIME,
1128 9, -1, 1, 3600000, SimpleTimeZone.WALL_TIME, 3600000);
1129 if (!tzid.equals(stz.getID())) {
1130 errln("FAIL: Bad zone id (" + stz.getID() + ") is returned - expected ("
1131 + tzid + ") [13-arg constructor]");
1136 public void TestJohannesburg() {
1137 String j_id="Africa/Johannesburg";
1138 TimeZone johannesburg = TimeZone.getTimeZone(j_id);
1139 final int ONE_HOUR = 60*60*1000;
1140 int expectedOffset = ONE_HOUR*2; // GMT+2 - NO DST
1141 int offset = johannesburg.getOffset(GregorianCalendar.AD,2007,Calendar.JULY,5,Calendar.THURSDAY,0);
1143 if(offset != expectedOffset) {
1144 errln("FAIL: zone " + j_id +" returned offset in July " + offset +", expected "+expectedOffset);
1146 logln("OK: zone " + j_id +" returned offset in July: " + offset);
1149 int offset2 = johannesburg.getOffset(GregorianCalendar.AD,2007,Calendar.DECEMBER,12,Calendar.WEDNESDAY,0);
1151 if(offset2 != expectedOffset) {
1152 errln("FAIL: zone " + j_id +" returned offset in December " + offset2 +", expected "+expectedOffset);
1154 logln("OK: zone " + j_id +" returned offset in December: " + offset2);
1158 public void TestT7107() {
1159 Thread[] workers = new Thread[20];
1160 for (int i = 0 ; i < workers.length; i++) {
1161 workers[i] = new Thread(new Runnable() {
1163 for (int j = 0; j < 10000; j++) {
1165 com.ibm.icu.util.TimeZone.getTimeZone("GMT").getDisplayName();
1166 } catch (Exception e) {
1167 errln("FAIL: Caught an exception " + e);
1173 for (Thread wk : workers) {
1176 for (Thread wk : workers) {
1179 } catch (InterruptedException ie) {