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=COMPAT,SPI TimeZoneRegression 31 */ 32 33 import java.util.*; 34 import java.io.*; 35 import java.text.*; 36 37 public class TimeZoneRegression extends IntlTest { 38 39 public static void main(String[] args) throws Exception { 40 new TimeZoneRegression().run(args); 41 } 42 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 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") 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 */ 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 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 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 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") 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 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 */ 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") 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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") 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 */ 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 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") 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 */ 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 */ 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 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") 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 */ 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 */ 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