1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /******************************************************************** 4 * Copyright (c) 1997-2016, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 ********************************************************************/ 7 8 #include "unicode/utypes.h" 9 10 #if !UCONFIG_NO_FORMATTING 11 12 #include "unicode/simpletz.h" 13 #include "unicode/smpdtfmt.h" 14 #include "unicode/strenum.h" 15 #include "unicode/gregocal.h" 16 #include "tzregts.h" 17 #include "calregts.h" 18 #include "cmemory.h" 19 20 // ***************************************************************************** 21 // class TimeZoneRegressionTest 22 // ***************************************************************************** 23 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break 24 25 void 26 TimeZoneRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 27 { 28 // if (exec) logln((UnicodeString)"TestSuite NumberFormatRegressionTest"); 29 switch (index) { 30 31 CASE(0, Test4052967); 32 CASE(1, Test4073209); 33 CASE(2, Test4073215); 34 CASE(3, Test4084933); 35 CASE(4, Test4096952); 36 CASE(5, Test4109314); 37 CASE(6, Test4126678); 38 CASE(7, Test4151406); 39 CASE(8, Test4151429); 40 CASE(9, Test4154537); 41 CASE(10, Test4154542); 42 CASE(11, Test4154650); 43 CASE(12, Test4154525); 44 CASE(13, Test4162593); 45 CASE(14, TestJ186); 46 CASE(15, TestJ449); 47 CASE(16, TestJDK12API); 48 CASE(17, Test4176686); 49 CASE(18, Test4184229); 50 CASE(19, TestNegativeDaylightSaving); 51 default: name = ""; break; 52 } 53 } 54 55 UBool 56 TimeZoneRegressionTest::failure(UErrorCode status, const char* msg) 57 { 58 if(U_FAILURE(status)) { 59 errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status)); 60 return TRUE; 61 } 62 63 return FALSE; 64 } 65 66 /** 67 * @bug 4052967 68 */ 69 void TimeZoneRegressionTest:: Test4052967() { 70 // {sfb} not applicable in C++ ? 71 /*logln("*** CHECK TIMEZONE AGAINST HOST OS SETTING ***"); 72 logln("user.timezone:" + System.getProperty("user.timezone", "<not set>")); 73 logln(new Date().toString()); 74 logln("*** THE RESULTS OF THIS TEST MUST BE VERIFIED MANUALLY ***");*/ 75 } 76 77 /** 78 * @bug 4073209 79 */ 80 void TimeZoneRegressionTest:: Test4073209() { 81 TimeZone *z1 = TimeZone::createTimeZone("PST"); 82 TimeZone *z2 = TimeZone::createTimeZone("PST"); 83 if (z1 == z2) 84 errln("Fail: TimeZone should return clones"); 85 delete z1; 86 delete z2; 87 } 88 89 UDate TimeZoneRegressionTest::findTransitionBinary(const SimpleTimeZone& tz, UDate min, UDate max) { 90 UErrorCode status = U_ZERO_ERROR; 91 UBool startsInDST = tz.inDaylightTime(min, status); 92 if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; 93 if (tz.inDaylightTime(max, status) == startsInDST) { 94 logln((UnicodeString)"Error: inDaylightTime() != " + ((!startsInDST)?"TRUE":"FALSE")); 95 return 0; 96 } 97 if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; 98 while ((max - min) > 100) { // Min accuracy in ms 99 UDate mid = (min + max) / 2; 100 if (tz.inDaylightTime(mid, status) == startsInDST) { 101 min = mid; 102 } else { 103 max = mid; 104 } 105 if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; 106 } 107 return (min + max) / 2; 108 } 109 110 UDate TimeZoneRegressionTest::findTransitionStepwise(const SimpleTimeZone& tz, UDate min, UDate max) { 111 UErrorCode status = U_ZERO_ERROR; 112 UBool startsInDST = tz.inDaylightTime(min, status); 113 if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; 114 while (min < max) { 115 if (tz.inDaylightTime(min, status) != startsInDST) { 116 return min; 117 } 118 if (failure(status, "SimpleTimeZone::inDaylightTime")) return 0; 119 min += (UDate)24*60*60*1000; // one day 120 } 121 return 0; 122 } 123 124 /** 125 * @bug 4073215 126 */ 127 // {sfb} will this work using a Calendar? 128 void TimeZoneRegressionTest:: Test4073215() 129 { 130 UErrorCode status = U_ZERO_ERROR; 131 UnicodeString str, str2; 132 SimpleTimeZone *z = new SimpleTimeZone(0, "GMT"); 133 if (z->useDaylightTime()) 134 errln("Fail: Fix test to start with non-DST zone"); 135 z->setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); 136 failure(status, "z->setStartRule()"); 137 z->setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); 138 failure(status, "z->setStartRule()"); 139 if (!z->useDaylightTime()) 140 errln("Fail: DST not active"); 141 142 GregorianCalendar cal(1997, UCAL_JANUARY, 31, status); 143 if(U_FAILURE(status)) { 144 dataerrln("Error creating calendar %s", u_errorName(status)); 145 return; 146 } 147 failure(status, "new GregorianCalendar"); 148 cal.adoptTimeZone(z); 149 150 SimpleDateFormat sdf((UnicodeString)"E d MMM yyyy G HH:mm", status); 151 if(U_FAILURE(status)) { 152 dataerrln("Error creating date format %s", u_errorName(status)); 153 return; 154 } 155 sdf.setCalendar(cal); 156 failure(status, "new SimpleDateFormat"); 157 158 UDate jan31, mar1, mar31; 159 160 UBool indt = z->inDaylightTime(jan31=cal.getTime(status), status); 161 failure(status, "inDaylightTime or getTime call on Jan 31"); 162 if (indt) { 163 errln("Fail: Jan 31 inDaylightTime=TRUE, exp FALSE"); 164 } 165 cal.set(1997, UCAL_MARCH, 1); 166 indt = z->inDaylightTime(mar1=cal.getTime(status), status); 167 failure(status, "inDaylightTime or getTime call on Mar 1"); 168 if (!indt) { 169 UnicodeString str; 170 sdf.format(cal.getTime(status), str); 171 failure(status, "getTime"); 172 errln((UnicodeString)"Fail: " + str + " inDaylightTime=FALSE, exp TRUE"); 173 } 174 cal.set(1997, UCAL_MARCH, 31); 175 indt = z->inDaylightTime(mar31=cal.getTime(status), status); 176 failure(status, "inDaylightTime or getTime call on Mar 31"); 177 if (indt) { 178 errln("Fail: Mar 31 inDaylightTime=TRUE, exp FALSE"); 179 } 180 181 /* 182 cal.set(1997, Calendar::DECEMBER, 31); 183 UDate dec31 = cal.getTime(status); 184 failure(status, "getTime"); 185 UDate trans = findTransitionStepwise(*z, jan31, dec31); 186 logln((UnicodeString)"Stepwise from " + 187 sdf.format(jan31, str.remove()) + "; transition at " + 188 (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); 189 trans = findTransitionStepwise(*z, mar1, dec31); 190 logln((UnicodeString)"Stepwise from " + 191 sdf.format(mar1, str.remove()) + "; transition at " + 192 (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); 193 trans = findTransitionStepwise(*z, mar31, dec31); 194 logln((UnicodeString)"Stepwise from " + 195 sdf.format(mar31, str.remove()) + "; transition at " + 196 (trans?sdf.format(trans, str2.remove()):(UnicodeString)"NONE")); 197 */ 198 } 199 200 /** 201 * @bug 4084933 202 * The expected behavior of TimeZone around the boundaries is: 203 * (Assume transition time of 2:00 AM) 204 * day of onset 1:59 AM STD = display name 1:59 AM ST 205 * 2:00 AM STD = display name 3:00 AM DT 206 * day of end 0:59 AM STD = display name 1:59 AM DT 207 * 1:00 AM STD = display name 1:00 AM ST 208 */ 209 void TimeZoneRegressionTest:: Test4084933() { 210 UErrorCode status = U_ZERO_ERROR; 211 TimeZone *tz = TimeZone::createTimeZone("PST"); 212 213 int32_t offset1 = tz->getOffset(1, 214 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); 215 int32_t offset2 = tz->getOffset(1, 216 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000)-1, status); 217 218 int32_t offset3 = tz->getOffset(1, 219 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000), status); 220 int32_t offset4 = tz->getOffset(1, 221 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (1*60*60*1000)-1, status); 222 223 /* 224 * The following was added just for consistency. It shows that going *to* Daylight 225 * Savings Time (PDT) does work at 2am. 226 */ 227 int32_t offset5 = tz->getOffset(1, 228 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000), status); 229 int32_t offset6 = tz->getOffset(1, 230 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (2*60*60*1000)-1, status); 231 int32_t offset5a = tz->getOffset(1, 232 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000), status); 233 int32_t offset6a = tz->getOffset(1, 234 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (3*60*60*1000)-1, status); 235 int32_t offset7 = tz->getOffset(1, 236 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000), status); 237 int32_t offset8 = tz->getOffset(1, 238 1997, UCAL_APRIL, 6, UCAL_SUNDAY, (1*60*60*1000)-1, status); 239 int32_t SToffset = (int32_t)(-8 * 60*60*1000L); 240 int32_t DToffset = (int32_t)(-7 * 60*60*1000L); 241 242 #define ERR_IF_FAIL(x) if(x) { dataerrln("FAIL: TimeZone misbehaving - %s", #x); } 243 244 ERR_IF_FAIL(U_FAILURE(status)) 245 ERR_IF_FAIL(offset1 != SToffset) 246 ERR_IF_FAIL(offset2 != SToffset) 247 ERR_IF_FAIL(offset3 != SToffset) 248 ERR_IF_FAIL(offset4 != DToffset) 249 ERR_IF_FAIL(offset5 != DToffset) 250 ERR_IF_FAIL(offset6 != SToffset) 251 ERR_IF_FAIL(offset5a != DToffset) 252 ERR_IF_FAIL(offset6a != DToffset) 253 ERR_IF_FAIL(offset7 != SToffset) 254 ERR_IF_FAIL(offset8 != SToffset) 255 256 #undef ERR_IF_FAIL 257 258 delete tz; 259 } 260 261 /** 262 * @bug 4096952 263 */ 264 void TimeZoneRegressionTest:: Test4096952() { 265 // {sfb} serialization not applicable 266 /* 267 UnicodeString ZONES [] = { UnicodeString("GMT"), UnicodeString("MET"), UnicodeString("IST") }; 268 UBool pass = TRUE; 269 //try { 270 for (int32_t i=0; i < ZONES.length; ++i) { 271 TimeZone *zone = TimeZone::createTimeZone(ZONES[i]); 272 UnicodeString id; 273 if (zone->getID(id) != ZONES[i]) 274 errln("Fail: Test broken; zones not instantiating"); 275 276 ByteArrayOutputStream baos; 277 ObjectOutputStream ostream = 278 new ObjectOutputStream(baos = new 279 ByteArrayOutputStream()); 280 ostream.writeObject(zone); 281 ostream.close(); 282 baos.close(); 283 ObjectInputStream istream = 284 new ObjectInputStream(new 285 ByteArrayInputStream(baos.toByteArray())); 286 TimeZone frankenZone = (TimeZone) istream.readObject(); 287 //logln("Zone: " + zone); 288 //logln("FrankenZone: " + frankenZone); 289 if (!zone.equals(frankenZone)) { 290 logln("TimeZone " + zone.getID() + 291 " not equal to serialized/deserialized one"); 292 pass = false; 293 } 294 } 295 if (!pass) errln("Fail: TimeZone serialization/equality bug"); 296 } 297 catch (IOException e) { 298 errln("Fail: " + e); 299 e.print32_tStackTrace(); 300 } 301 catch (ClassNotFoundException e) { 302 errln("Fail: " + e); 303 e.print32_tStackTrace(); 304 } 305 */ 306 } 307 308 /** 309 * @bug 4109314 310 */ 311 void TimeZoneRegressionTest:: Test4109314() { 312 UErrorCode status = U_ZERO_ERROR; 313 GregorianCalendar *testCal = (GregorianCalendar*)Calendar::createInstance(status); 314 if(U_FAILURE(status)) { 315 dataerrln("Error creating calendar %s", u_errorName(status)); 316 delete testCal; 317 return; 318 } 319 failure(status, "Calendar::createInstance"); 320 TimeZone *PST = TimeZone::createTimeZone("PST"); 321 /*Object[] testData = { 322 PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0), 323 PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0), 324 };*/ 325 UDate testData [] = { 326 CalendarRegressionTest::makeDate(98,UCAL_APRIL,4,22,0), 327 CalendarRegressionTest::makeDate(98, UCAL_APRIL,5,6,0), 328 CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,24,22,0), 329 CalendarRegressionTest::makeDate(98,UCAL_OCTOBER,25,6,0) 330 }; 331 UBool pass = TRUE; 332 for (int32_t i = 0; i < 4; i+=2) { 333 //testCal->setTimeZone((TimeZone) testData[i]); 334 testCal->setTimeZone(*PST); 335 UDate t = testData[i]; 336 UDate end = testData[i+1]; 337 while(testCal->getTime(status) < end) { 338 testCal->setTime(t, status); 339 if ( ! checkCalendar314(testCal, PST)) 340 pass = FALSE; 341 t += 60*60*1000.0; 342 } 343 } 344 if ( ! pass) 345 errln("Fail: TZ API inconsistent"); 346 347 delete testCal; 348 delete PST; 349 } 350 351 UBool 352 TimeZoneRegressionTest::checkCalendar314(GregorianCalendar *testCal, TimeZone *testTZ) 353 { 354 UErrorCode status = U_ZERO_ERROR; 355 // GregorianCalendar testCal = (GregorianCalendar)aCal.clone(); 356 357 int32_t tzOffset, tzRawOffset; 358 float tzOffsetFloat,tzRawOffsetFloat; 359 // Here is where the user made an error. They were passing in the value of 360 // the MILLSECOND field; you need to pass in the millis in the day in STANDARD 361 // time. 362 UDate millis = testCal->get(UCAL_MILLISECOND, status) + 363 1000.0 * (testCal->get(UCAL_SECOND, status) + 364 60.0 * (testCal->get(UCAL_MINUTE, status) + 365 60.0 * (testCal->get(UCAL_HOUR_OF_DAY, status)))) - 366 testCal->get(UCAL_DST_OFFSET, status); 367 368 /* Fix up millis to be in range. ASSUME THAT WE ARE NOT AT THE 369 * BEGINNING OR END OF A MONTH. We must add this code because 370 * getOffset() has been changed to be more strict about the parameters 371 * it receives -- it turns out that this test was passing in illegal 372 * values. */ 373 int32_t date = testCal->get(UCAL_DATE, status); 374 int32_t dow = testCal->get(UCAL_DAY_OF_WEEK, status); 375 while(millis < 0) { 376 millis += U_MILLIS_PER_DAY; 377 --date; 378 dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 6) % 7); 379 } 380 while (millis >= U_MILLIS_PER_DAY) { 381 millis -= U_MILLIS_PER_DAY; 382 ++date; 383 dow = UCAL_SUNDAY + ((dow - UCAL_SUNDAY + 1) % 7); 384 } 385 386 tzOffset = testTZ->getOffset((uint8_t)testCal->get(UCAL_ERA, status), 387 testCal->get(UCAL_YEAR, status), 388 testCal->get(UCAL_MONTH, status), 389 date, 390 (uint8_t)dow, 391 (int32_t)millis, 392 status); 393 tzRawOffset = testTZ->getRawOffset(); 394 tzOffsetFloat = (float)tzOffset/(float)3600000; 395 tzRawOffsetFloat = (float)tzRawOffset/(float)3600000; 396 397 UDate testDate = testCal->getTime(status); 398 399 UBool inDaylightTime = testTZ->inDaylightTime(testDate, status); 400 SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)"MM/dd/yyyy HH:mm", status); 401 sdf->setCalendar(*testCal); 402 UnicodeString inDaylightTimeString; 403 404 UBool passed; 405 406 if(inDaylightTime) 407 { 408 inDaylightTimeString = " DST "; 409 passed = (tzOffset == (tzRawOffset + 3600000)); 410 } 411 else 412 { 413 inDaylightTimeString = " "; 414 passed = (tzOffset == tzRawOffset); 415 } 416 417 UnicodeString output; 418 FieldPosition pos(FieldPosition::DONT_CARE); 419 output = testTZ->getID(output) + " " + sdf->format(testDate, output, pos) + 420 " Offset(" + tzOffsetFloat + ")" + 421 " RawOffset(" + tzRawOffsetFloat + ")" + 422 " " + millis/(float)3600000 + " " + 423 inDaylightTimeString; 424 425 if (passed) 426 output += " "; 427 else 428 output += "ERROR"; 429 430 if (passed) 431 logln(output); 432 else 433 errln(output); 434 435 delete sdf; 436 return passed; 437 } 438 439 /** 440 * @bug 4126678 441 * CANNOT REPRODUDE 442 * 443 * Yet another _alleged_ bug in TimeZone::getOffset(), a method that never 444 * should have been made public. It's simply too hard to use correctly. 445 * 446 * The original test code failed to do the following: 447 * (1) Call Calendar::setTime() before getting the fields! 448 * (2) Use the right millis (as usual) for getOffset(); they were passing 449 * in the MILLIS field, instead of the STANDARD MILLIS IN DAY. 450 * When you fix these two problems, the test passes, as expected. 451 */ 452 void TimeZoneRegressionTest:: Test4126678() 453 { 454 UErrorCode status = U_ZERO_ERROR; 455 Calendar *cal = Calendar::createInstance(status); 456 if(U_FAILURE(status)) { 457 dataerrln("Error creating calendar %s", u_errorName(status)); 458 delete cal; 459 return; 460 } 461 failure(status, "Calendar::createInstance"); 462 TimeZone *tz = TimeZone::createTimeZone("PST"); 463 cal->adoptTimeZone(tz); 464 465 cal->set(1998, UCAL_APRIL, 5, 10, 0); 466 467 if (! tz->useDaylightTime() || U_FAILURE(status)) 468 dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status)); 469 470 //cal.setTime(dt); 471 int32_t era = cal->get(UCAL_ERA, status); 472 int32_t year = cal->get(UCAL_YEAR, status); 473 int32_t month = cal->get(UCAL_MONTH, status); 474 int32_t day = cal->get(UCAL_DATE, status); 475 int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); 476 int32_t millis = cal->get(UCAL_MILLISECOND, status) + 477 (cal->get(UCAL_SECOND, status) + 478 (cal->get(UCAL_MINUTE, status) + 479 (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) - 480 cal->get(UCAL_DST_OFFSET, status); 481 482 failure(status, "cal->get"); 483 int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status); 484 int32_t raw_offset = tz->getRawOffset(); 485 486 if (offset == raw_offset) 487 dataerrln("Offsets should match"); 488 489 delete cal; 490 } 491 492 /** 493 * @bug 4151406 494 * TimeZone::getAvailableIDs(int32_t) throws exception for certain values, 495 * due to a faulty constant in TimeZone::java. 496 */ 497 void TimeZoneRegressionTest:: Test4151406() { 498 int32_t max = 0; 499 for (int32_t h=-28; h<=30; ++h) { 500 // h is in half-hours from GMT; rawoffset is in millis 501 int32_t rawoffset = h * 1800000; 502 int32_t hh = (h<0) ? -h : h; 503 UnicodeString hname = UnicodeString((h<0) ? "GMT-" : "GMT+") + 504 ((hh/2 < 10) ? "0" : "") + 505 (hh/2) + ':' + 506 ((hh%2==0) ? "00" : "30"); 507 //try { 508 UErrorCode ec = U_ZERO_ERROR; 509 int32_t count; 510 StringEnumeration* ids = TimeZone::createEnumeration(rawoffset); 511 if (ids == NULL) { 512 dataerrln("Fail: TimeZone::createEnumeration(rawoffset)"); 513 continue; 514 } 515 count = ids->count(ec); 516 if (count> max) 517 max = count; 518 if (count > 0) { 519 logln(hname + ' ' + (UnicodeString)count + (UnicodeString)" e.g. " + *ids->snext(ec)); 520 } else { 521 logln(hname + ' ' + count); 522 } 523 // weiv 11/27/2002: why uprv_free? This should be a delete 524 delete ids; 525 //delete [] ids; 526 //uprv_free(ids); 527 /*} catch (Exception e) { 528 errln(hname + ' ' + "Fail: " + e); 529 }*/ 530 } 531 logln("Maximum zones per offset = %d", max); 532 } 533 534 /** 535 * @bug 4151429 536 */ 537 void TimeZoneRegressionTest:: Test4151429() { 538 // {sfb} silly test in C++, since we are using an enum and not an int 539 //try { 540 /*TimeZone *tz = TimeZone::createTimeZone("GMT"); 541 UnicodeString name; 542 tz->getDisplayName(TRUE, TimeZone::LONG, 543 Locale.getDefault(), name); 544 errln("IllegalArgumentException not thrown by TimeZone::getDisplayName()");*/ 545 //} catch(IllegalArgumentException e) {} 546 } 547 548 /** 549 * @bug 4154537 550 * SimpleTimeZone::hasSameRules() doesn't work for zones with no DST 551 * and different DST parameters. 552 */ 553 void TimeZoneRegressionTest:: Test4154537() { 554 UErrorCode status = U_ZERO_ERROR; 555 // tz1 and tz2 have no DST and different rule parameters 556 SimpleTimeZone *tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0, status); 557 SimpleTimeZone *tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0, status); 558 // tza and tzA have the same rule params 559 SimpleTimeZone *tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0, status); 560 SimpleTimeZone *tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0, status); 561 // tzb differs from tza 562 SimpleTimeZone *tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0, status); 563 564 if(U_FAILURE(status)) 565 errln("Couldn't create TimeZones"); 566 567 if (tz1->useDaylightTime() || tz2->useDaylightTime() || 568 !tza->useDaylightTime() || !tzA->useDaylightTime() || 569 !tzb->useDaylightTime()) { 570 errln("Test is broken -- rewrite it"); 571 } 572 if (!tza->hasSameRules(*tzA) || tza->hasSameRules(*tzb)) { 573 errln("Fail: hasSameRules() broken for zones with rules"); 574 } 575 if (!tz1->hasSameRules(*tz2)) { 576 errln("Fail: hasSameRules() returns false for zones without rules"); 577 //errln("zone 1 = " + tz1); 578 //errln("zone 2 = " + tz2); 579 } 580 581 delete tz1; 582 delete tz2; 583 delete tza; 584 delete tzA; 585 delete tzb; 586 } 587 588 /** 589 * @bug 4154542 590 * SimpleTimeZOne constructors, setStartRule(), and setEndRule() don't 591 * check for out-of-range arguments. 592 */ 593 void TimeZoneRegressionTest:: Test4154542() 594 { 595 const int32_t GOOD = 1; 596 const int32_t BAD = 0; 597 598 const int32_t GOOD_MONTH = UCAL_JANUARY; 599 const int32_t GOOD_DAY = 1; 600 const int32_t GOOD_DAY_OF_WEEK = UCAL_SUNDAY; 601 const int32_t GOOD_TIME = 0; 602 603 int32_t DATA [] = { 604 GOOD, INT32_MIN, 0, INT32_MAX, INT32_MIN, 605 GOOD, UCAL_JANUARY, -5, UCAL_SUNDAY, 0, 606 GOOD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000, 607 BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, 24*60*60*1000+1, 608 BAD, UCAL_DECEMBER, 5, UCAL_SATURDAY, -1, 609 BAD, UCAL_JANUARY, -6, UCAL_SUNDAY, 0, 610 BAD, UCAL_DECEMBER, 6, UCAL_SATURDAY, 24*60*60*1000, 611 GOOD, UCAL_DECEMBER, 1, 0, 0, 612 GOOD, UCAL_DECEMBER, 31, 0, 0, 613 BAD, UCAL_APRIL, 31, 0, 0, 614 BAD, UCAL_DECEMBER, 32, 0, 0, 615 BAD, UCAL_JANUARY-1, 1, UCAL_SUNDAY, 0, 616 BAD, UCAL_DECEMBER+1, 1, UCAL_SUNDAY, 0, 617 GOOD, UCAL_DECEMBER, 31, -UCAL_SUNDAY, 0, 618 GOOD, UCAL_DECEMBER, 31, -UCAL_SATURDAY, 0, 619 BAD, UCAL_DECEMBER, 32, -UCAL_SATURDAY, 0, 620 BAD, UCAL_DECEMBER, -32, -UCAL_SATURDAY, 0, 621 BAD, UCAL_DECEMBER, 31, -UCAL_SATURDAY-1, 0, 622 }; 623 SimpleTimeZone *zone = new SimpleTimeZone(0, "Z"); 624 for (int32_t i=0; i < 18*5; i+=5) { 625 UBool shouldBeGood = (DATA[i] == GOOD); 626 int32_t month = DATA[i+1]; 627 int32_t day = DATA[i+2]; 628 int32_t dayOfWeek = DATA[i+3]; 629 int32_t time = DATA[i+4]; 630 631 UErrorCode status = U_ZERO_ERROR; 632 633 //Exception ex = null; 634 //try { 635 zone->setStartRule(month, day, dayOfWeek, time, status); 636 //} catch (IllegalArgumentException e) { 637 // ex = e; 638 //} 639 if (U_SUCCESS(status) != shouldBeGood) { 640 errln(UnicodeString("setStartRule(month=") + month + ", day=" + day + 641 ", dayOfWeek=" + dayOfWeek + ", time=" + time + 642 (shouldBeGood ? (") should work") 643 : ") should fail but doesn't")); 644 } 645 646 //ex = null; 647 //try { 648 status = U_ZERO_ERROR; 649 zone->setEndRule(month, day, dayOfWeek, time, status); 650 //} catch (IllegalArgumentException e) { 651 // ex = e; 652 //} 653 if (U_SUCCESS(status) != shouldBeGood) { 654 errln(UnicodeString("setEndRule(month=") + month + ", day=" + day + 655 ", dayOfWeek=" + dayOfWeek + ", time=" + time + 656 (shouldBeGood ? (") should work") 657 : ") should fail but doesn't")); 658 } 659 660 //ex = null; 661 //try { 662 // {sfb} need to look into ctor problems! (UErrorCode vs. dst signature confusion) 663 status = U_ZERO_ERROR; 664 SimpleTimeZone *temp = new SimpleTimeZone(0, "Z", 665 (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time, 666 (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK, 667 GOOD_TIME,status); 668 //} catch (IllegalArgumentException e) { 669 // ex = e; 670 //} 671 if (U_SUCCESS(status) != shouldBeGood) { 672 errln(UnicodeString("SimpleTimeZone(month=") + month + ", day=" + day + 673 ", dayOfWeek=" + dayOfWeek + ", time=" + time + 674 (shouldBeGood ? (", <end>) should work")// + ex) 675 : ", <end>) should fail but doesn't")); 676 } 677 678 delete temp; 679 //ex = null; 680 //try { 681 status = U_ZERO_ERROR; 682 temp = new SimpleTimeZone(0, "Z", 683 (int8_t)GOOD_MONTH, (int8_t)GOOD_DAY, (int8_t)GOOD_DAY_OF_WEEK, 684 GOOD_TIME, 685 (int8_t)month, (int8_t)day, (int8_t)dayOfWeek, time,status); 686 //} catch (IllegalArgumentException e) { 687 // ex = e; 688 //} 689 if (U_SUCCESS(status) != shouldBeGood) { 690 errln(UnicodeString("SimpleTimeZone(<start>, month=") + month + ", day=" + day + 691 ", dayOfWeek=" + dayOfWeek + ", time=" + time + 692 (shouldBeGood ? (") should work")// + ex) 693 : ") should fail but doesn't")); 694 } 695 delete temp; 696 } 697 delete zone; 698 } 699 700 701 /** 702 * @bug 4154525 703 * SimpleTimeZone accepts illegal DST savings values. These values 704 * must be non-zero. There is no upper limit at this time. 705 */ 706 void 707 TimeZoneRegressionTest::Test4154525() 708 { 709 const int32_t GOOD = 1, BAD = 0; 710 711 int32_t DATA [] = { 712 1, GOOD, 713 0, BAD, 714 -1, GOOD, // #13566 updates SimpleTimeZone to support negative DST saving amount 715 60*60*1000, GOOD, 716 INT32_MAX, GOOD, // no upper limit on DST savings at this time 717 INT32_MIN, GOOD // no lower limit as well 718 }; 719 720 UErrorCode status = U_ZERO_ERROR; 721 for(int32_t i = 0; i < 10; i+=2) { 722 int32_t savings = DATA[i]; 723 UBool valid = DATA[i+1] == GOOD; 724 UnicodeString method; 725 for(int32_t j=0; j < 2; ++j) { 726 SimpleTimeZone *z=NULL; 727 switch (j) { 728 case 0: 729 method = "constructor"; 730 z = new SimpleTimeZone(0, "id", 731 UCAL_JANUARY, 1, 0, 0, 732 UCAL_MARCH, 1, 0, 0, 733 savings, status); // <- what we're interested in 734 break; 735 case 1: 736 method = "setDSTSavings()"; 737 z = new SimpleTimeZone(0, "GMT"); 738 z->setDSTSavings(savings, status); 739 break; 740 } 741 742 if(U_FAILURE(status)) { 743 if(valid) { 744 errln(UnicodeString("Fail: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); 745 } 746 else { 747 logln(UnicodeString("Pass: DST savings of ") + savings + " to " + method + " gave " + u_errorName(status)); 748 } 749 } 750 else { 751 if(valid) { 752 logln(UnicodeString("Pass: DST savings of ") + savings + " accepted by " + method); 753 } 754 else { 755 errln(UnicodeString("Fail: DST savings of ") + savings + " accepted by " + method); 756 } 757 } 758 status = U_ZERO_ERROR; 759 delete z; 760 } 761 } 762 } 763 764 /** 765 * @bug 4154650 766 * SimpleTimeZone.getOffset accepts illegal arguments. 767 */ 768 void 769 TimeZoneRegressionTest::Test4154650() 770 { 771 const int32_t GOOD = 1, BAD = 0; 772 const int32_t GOOD_ERA = GregorianCalendar::AD, GOOD_YEAR = 1998, GOOD_MONTH = UCAL_AUGUST; 773 const int32_t GOOD_DAY = 2, GOOD_DOW = UCAL_SUNDAY, GOOD_TIME = 16*3600000; 774 775 int32_t DATA []= { 776 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, 777 778 GOOD, GregorianCalendar::BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, 779 GOOD, GregorianCalendar::AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, 780 BAD, GregorianCalendar::BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, 781 BAD, GregorianCalendar::AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, 782 783 GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME, 784 GOOD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME, 785 BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME, 786 BAD, GOOD_ERA, GOOD_YEAR, UCAL_DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME, 787 788 GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 1, GOOD_DOW, GOOD_TIME, 789 GOOD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 31, GOOD_DOW, GOOD_TIME, 790 BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 0, GOOD_DOW, GOOD_TIME, 791 BAD, GOOD_ERA, GOOD_YEAR, UCAL_JANUARY, 32, GOOD_DOW, GOOD_TIME, 792 793 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY, GOOD_TIME, 794 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY, GOOD_TIME, 795 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SUNDAY-1, GOOD_TIME, 796 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, UCAL_SATURDAY+1, GOOD_TIME, 797 798 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0, 799 GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1, 800 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1, 801 BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000, 802 }; 803 804 int32_t dataLen = UPRV_LENGTHOF(DATA); 805 806 UErrorCode status = U_ZERO_ERROR; 807 TimeZone *tz = TimeZone::createDefault(); 808 for(int32_t i = 0; i < dataLen; i += 7) { 809 UBool good = DATA[i] == GOOD; 810 //IllegalArgumentException e = null; 811 //try { 812 /*int32_t offset = */ 813 tz->getOffset((uint8_t)DATA[i+1], DATA[i+2], DATA[i+3], 814 DATA[i+4], (uint8_t)DATA[i+5], DATA[i+6], status); 815 //} catch (IllegalArgumentException ex) { 816 // e = ex; 817 //} 818 if(good != U_SUCCESS(status)) { 819 UnicodeString errMsg; 820 if (good) { 821 errMsg = (UnicodeString(") threw ") + u_errorName(status)); 822 } 823 else { 824 errMsg = UnicodeString(") accepts invalid args", ""); 825 } 826 errln(UnicodeString("Fail: getOffset(") + 827 DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " + 828 DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] + 829 errMsg); 830 } 831 status = U_ZERO_ERROR; // reset 832 } 833 delete tz; 834 } 835 836 /** 837 * @bug 4162593 838 * TimeZone broken at midnight. The TimeZone code fails to handle 839 * transitions at midnight correctly. 840 */ 841 void 842 TimeZoneRegressionTest::Test4162593() 843 { 844 UErrorCode status = U_ZERO_ERROR; 845 SimpleDateFormat *fmt = new SimpleDateFormat("z", Locale::getUS(), status); 846 if(U_FAILURE(status)) { 847 dataerrln("Error creating calendar %s", u_errorName(status)); 848 delete fmt; 849 return; 850 } 851 const int32_t ONE_HOUR = 60*60*1000; 852 853 SimpleTimeZone *asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/, 854 UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 855 UCAL_MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); 856 857 /* Zone 858 * Starting time 859 * Transition expected between start+1H and start+2H 860 */ 861 TimeZone *DATA_TZ [] = { 862 0, 0, 0 }; 863 864 int32_t DATA_INT [] [5] = { 865 // These years must be AFTER the Gregorian cutover 866 {1998, UCAL_SEPTEMBER, 30, 22, 0}, 867 {2000, UCAL_FEBRUARY, 28, 22, 0}, 868 {2000, UCAL_FEBRUARY, 29, 22, 0}, 869 }; 870 871 UBool DATA_BOOL [] = { 872 TRUE, 873 FALSE, 874 TRUE, 875 }; 876 877 UnicodeString zone [4];// = new String[4]; 878 DATA_TZ[0] = 879 new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/, 880 UCAL_APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR, 881 UCAL_OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR, status); 882 DATA_TZ[1] = asuncion; DATA_TZ[2] = asuncion; 883 884 for(int32_t j = 0; j < 3; j++) { 885 TimeZone *tz = (TimeZone*)DATA_TZ[j]; 886 TimeZone::setDefault(*tz); 887 fmt->setTimeZone(*tz); 888 889 // Must construct the Date object AFTER setting the default zone 890 int32_t *p = (int32_t*)DATA_INT[j]; 891 UDate d = CalendarRegressionTest::makeDate(p[0], p[1], p[2], p[3], p[4]); 892 UBool transitionExpected = DATA_BOOL[j]; 893 894 UnicodeString temp; 895 logln(tz->getID(temp) + ":"); 896 for (int32_t i = 0; i < 4; ++i) { 897 FieldPosition pos(FieldPosition::DONT_CARE); 898 zone[i].remove(); 899 zone[i] = fmt->format(d+ i*ONE_HOUR, zone[i], pos); 900 logln(UnicodeString("") + i + ": " + d + " / " + zone[i]); 901 //d += (double) ONE_HOUR; 902 } 903 if(zone[0] == zone[1] && 904 (zone[1] == zone[2]) != transitionExpected && 905 zone[2] == zone[3]) { 906 logln(UnicodeString("Ok: transition ") + transitionExpected); 907 } 908 else { 909 errln("Fail: boundary transition incorrect"); 910 } 911 } 912 delete fmt; 913 delete asuncion; 914 delete DATA_TZ[0]; 915 } 916 917 /** 918 * getDisplayName doesn't work with unusual savings/offsets. 919 */ 920 void TimeZoneRegressionTest::Test4176686() { 921 // Construct a zone that does not observe DST but 922 // that does have a DST savings (which should be ignored). 923 UErrorCode status = U_ZERO_ERROR; 924 int32_t offset = 90 * 60000; // 1:30 925 SimpleTimeZone* z1 = new SimpleTimeZone(offset, "_std_zone_"); 926 z1->setDSTSavings(45 * 60000, status); // 0:45 927 928 // Construct a zone that observes DST for the first 6 months. 929 SimpleTimeZone* z2 = new SimpleTimeZone(offset, "_dst_zone_"); 930 z2->setDSTSavings(45 * 60000, status); // 0:45 931 z2->setStartRule(UCAL_JANUARY, 1, 0, status); 932 z2->setEndRule(UCAL_JULY, 1, 0, status); 933 934 // Also check DateFormat 935 DateFormat* fmt1 = new SimpleDateFormat(UnicodeString("z"), status); 936 if (U_FAILURE(status)) { 937 dataerrln("Failure trying to construct: %s", u_errorName(status)); 938 return; 939 } 940 fmt1->setTimeZone(*z1); // Format uses standard zone 941 DateFormat* fmt2 = new SimpleDateFormat(UnicodeString("z"), status); 942 if(!assertSuccess("trying to construct", status))return; 943 fmt2->setTimeZone(*z2); // Format uses DST zone 944 Calendar* tempcal = Calendar::createInstance(status); 945 tempcal->clear(); 946 tempcal->set(1970, UCAL_FEBRUARY, 1); 947 UDate dst = tempcal->getTime(status); // Time in DST 948 tempcal->set(1970, UCAL_AUGUST, 1); 949 UDate std = tempcal->getTime(status); // Time in standard 950 951 // Description, Result, Expected Result 952 UnicodeString a,b,c,d,e,f,g,h,i,j,k,l; 953 UnicodeString DATA[] = { 954 "z1->getDisplayName(false, SHORT)/std zone", 955 z1->getDisplayName(FALSE, TimeZone::SHORT, a), "GMT+1:30", 956 "z1->getDisplayName(false, LONG)/std zone", 957 z1->getDisplayName(FALSE, TimeZone::LONG, b), "GMT+01:30", 958 "z1->getDisplayName(true, SHORT)/std zone", 959 z1->getDisplayName(TRUE, TimeZone::SHORT, c), "GMT+1:30", 960 "z1->getDisplayName(true, LONG)/std zone", 961 z1->getDisplayName(TRUE, TimeZone::LONG, d ), "GMT+01:30", 962 "z2->getDisplayName(false, SHORT)/dst zone", 963 z2->getDisplayName(FALSE, TimeZone::SHORT, e), "GMT+1:30", 964 "z2->getDisplayName(false, LONG)/dst zone", 965 z2->getDisplayName(FALSE, TimeZone::LONG, f ), "GMT+01:30", 966 "z2->getDisplayName(true, SHORT)/dst zone", 967 z2->getDisplayName(TRUE, TimeZone::SHORT, g), "GMT+2:15", 968 "z2->getDisplayName(true, LONG)/dst zone", 969 z2->getDisplayName(TRUE, TimeZone::LONG, h ), "GMT+02:15", 970 "DateFormat.format(std)/std zone", fmt1->format(std, i), "GMT+1:30", 971 "DateFormat.format(dst)/std zone", fmt1->format(dst, j), "GMT+1:30", 972 "DateFormat.format(std)/dst zone", fmt2->format(std, k), "GMT+1:30", 973 "DateFormat.format(dst)/dst zone", fmt2->format(dst, l), "GMT+2:15", 974 }; 975 976 for (int32_t idx=0; idx<UPRV_LENGTHOF(DATA); idx+=3) { 977 if (DATA[idx+1]!=(DATA[idx+2])) { 978 errln("FAIL: " + DATA[idx] + " -> " + DATA[idx+1] + ", exp " + DATA[idx+2]); 979 } 980 } 981 delete z1; 982 delete z2; 983 delete fmt1; 984 delete fmt2; 985 delete tempcal; 986 } 987 988 /** 989 * Make sure setStartRule and setEndRule set the DST savings to nonzero 990 * if it was zero. 991 */ 992 void TimeZoneRegressionTest::TestJ186() { 993 UErrorCode status = U_ZERO_ERROR; 994 // NOTE: Setting the DST savings to zero is illegal, so we 995 // are limited in the testing we can do here. This is why 996 // lines marked //~ are commented out. 997 SimpleTimeZone z(0, "ID"); 998 //~z.setDSTSavings(0, status); // Must do this! 999 z.setStartRule(UCAL_FEBRUARY, 1, UCAL_SUNDAY, 0, status); 1000 failure(status, "setStartRule()"); 1001 if (z.useDaylightTime()) { 1002 errln("Fail: useDaylightTime true with start rule only"); 1003 } 1004 //~if (z.getDSTSavings() != 0) { 1005 //~ errln("Fail: dst savings != 0 with start rule only"); 1006 //~} 1007 z.setEndRule(UCAL_MARCH, -1, UCAL_SUNDAY, 0, status); 1008 failure(status, "setStartRule()"); 1009 if (!z.useDaylightTime()) { 1010 errln("Fail: useDaylightTime false with rules set"); 1011 } 1012 if (z.getDSTSavings() == 0) { 1013 errln("Fail: dst savings == 0 with rules set"); 1014 } 1015 } 1016 1017 /** 1018 * Test to see if DateFormat understands zone equivalency groups. It 1019 * might seem that this should be a DateFormat test, but it's really a 1020 * TimeZone test -- the changes to DateFormat are minor. 1021 * 1022 * We use two known, stable zones that shouldn't change much over time 1023 * -- America/Vancouver and America/Los_Angeles. However, they MAY 1024 * change at some point -- if that happens, replace them with any two 1025 * zones in an equivalency group where one zone has localized name 1026 * data, and the other doesn't, in some locale. 1027 */ 1028 void TimeZoneRegressionTest::TestJ449() { 1029 UErrorCode status = U_ZERO_ERROR; 1030 UnicodeString str; 1031 1032 // Modify the following three as necessary. The two IDs must 1033 // specify two zones in the same equivalency group. One must have 1034 // locale data in 'loc'; the other must not. 1035 const char* idWithLocaleData = "America/Los_Angeles"; 1036 const char* idWithoutLocaleData = "US/Pacific"; 1037 const Locale loc("en", "", ""); 1038 1039 TimeZone *zoneWith = TimeZone::createTimeZone(idWithLocaleData); 1040 TimeZone *zoneWithout = TimeZone::createTimeZone(idWithoutLocaleData); 1041 // Make sure we got valid zones 1042 if (zoneWith->getID(str) != UnicodeString(idWithLocaleData) || 1043 zoneWithout->getID(str) != UnicodeString(idWithoutLocaleData)) { 1044 dataerrln(UnicodeString("Fail: Unable to create zones - wanted ") + idWithLocaleData + ", got " + zoneWith->getID(str) + ", and wanted " + idWithoutLocaleData + " but got " + zoneWithout->getID(str)); 1045 } else { 1046 GregorianCalendar calWith(*zoneWith, status); 1047 GregorianCalendar calWithout(*zoneWithout, status); 1048 SimpleDateFormat fmt("MMM d yyyy hh:mm a zzz", loc, status); 1049 if (U_FAILURE(status)) { 1050 errln("Fail: Unable to create GregorianCalendar/SimpleDateFormat"); 1051 } else { 1052 UDate date = 0; 1053 UnicodeString strWith, strWithout; 1054 fmt.setCalendar(calWith); 1055 fmt.format(date, strWith); 1056 fmt.setCalendar(calWithout); 1057 fmt.format(date, strWithout); 1058 if (strWith == strWithout) { 1059 logln((UnicodeString)"Ok: " + idWithLocaleData + " -> " + 1060 strWith + "; " + idWithoutLocaleData + " -> " + 1061 strWithout); 1062 } else { 1063 errln((UnicodeString)"FAIL: " + idWithLocaleData + " -> " + 1064 strWith + "; " + idWithoutLocaleData + " -> " + 1065 strWithout); 1066 } 1067 } 1068 } 1069 1070 delete zoneWith; 1071 delete zoneWithout; 1072 } 1073 1074 // test new API for JDK 1.2 8/31 putback 1075 void 1076 TimeZoneRegressionTest::TestJDK12API() 1077 { 1078 // TimeZone *pst = TimeZone::createTimeZone("PST"); 1079 // TimeZone *cst1 = TimeZone::createTimeZone("CST"); 1080 UErrorCode ec = U_ZERO_ERROR; 1081 //d,-28800,3,1,-1,120,w,9,-1,1,120,w,60 1082 TimeZone *pst = new SimpleTimeZone(-28800*U_MILLIS_PER_SECOND, 1083 "PST", 1084 3,1,-1,120*U_MILLIS_PER_MINUTE, 1085 SimpleTimeZone::WALL_TIME, 1086 9,-1,1,120*U_MILLIS_PER_MINUTE, 1087 SimpleTimeZone::WALL_TIME, 1088 60*U_MILLIS_PER_MINUTE,ec); 1089 //d,-21600,3,1,-1,120,w,9,-1,1,120,w,60 1090 TimeZone *cst1 = new SimpleTimeZone(-21600*U_MILLIS_PER_SECOND, 1091 "CST", 1092 3,1,-1,120*U_MILLIS_PER_MINUTE, 1093 SimpleTimeZone::WALL_TIME, 1094 9,-1,1,120*U_MILLIS_PER_MINUTE, 1095 SimpleTimeZone::WALL_TIME, 1096 60*U_MILLIS_PER_MINUTE,ec); 1097 if (U_FAILURE(ec)) { 1098 errln("FAIL: SimpleTimeZone constructor"); 1099 return; 1100 } 1101 1102 SimpleTimeZone *cst = dynamic_cast<SimpleTimeZone *>(cst1); 1103 1104 if(pst->hasSameRules(*cst)) { 1105 errln("FAILURE: PST and CST have same rules"); 1106 } 1107 1108 UErrorCode status = U_ZERO_ERROR; 1109 int32_t offset1 = pst->getOffset(1, 1110 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), status); 1111 failure(status, "getOffset() failed"); 1112 1113 1114 int32_t offset2 = cst->getOffset(1, 1115 1997, UCAL_OCTOBER, 26, UCAL_SUNDAY, (2*60*60*1000), 31, status); 1116 failure(status, "getOffset() failed"); 1117 1118 if(offset1 == offset2) 1119 errln("FAILURE: Sunday Oct. 26 1997 2:00 has same offset for PST and CST"); 1120 1121 // verify error checking 1122 pst->getOffset(1, 1123 1997, UCAL_FIELD_COUNT+1, 26, UCAL_SUNDAY, (2*60*60*1000), status); 1124 if(U_SUCCESS(status)) 1125 errln("FAILURE: getOffset() succeeded with -1 for month"); 1126 1127 status = U_ZERO_ERROR; 1128 cst->setDSTSavings(60*60*1000, status); 1129 failure(status, "setDSTSavings() failed"); 1130 1131 int32_t savings = cst->getDSTSavings(); 1132 if(savings != 60*60*1000) { 1133 errln("setDSTSavings() failed"); 1134 } 1135 1136 delete pst; 1137 delete cst; 1138 } 1139 /** 1140 * SimpleTimeZone allows invalid DOM values. 1141 */ 1142 void TimeZoneRegressionTest::Test4184229() { 1143 SimpleTimeZone* zone = NULL; 1144 UErrorCode status = U_ZERO_ERROR; 1145 zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, status); 1146 if(U_SUCCESS(status)){ 1147 errln("Failed. No exception has been thrown for DOM -1 startDay"); 1148 }else{ 1149 logln("(a) " + UnicodeString( u_errorName(status))); 1150 } 1151 status = U_ZERO_ERROR; 1152 delete zone; 1153 1154 zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, status); 1155 if(U_SUCCESS(status)){ 1156 errln("Failed. No exception has been thrown for DOM -1 endDay"); 1157 }else{ 1158 logln("(b) " + UnicodeString(u_errorName(status))); 1159 } 1160 status = U_ZERO_ERROR; 1161 delete zone; 1162 1163 zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 1000, status); 1164 if(U_SUCCESS(status)){ 1165 errln("Failed. No exception has been thrown for DOM -1 startDay+savings"); 1166 }else{ 1167 logln("(c) " + UnicodeString(u_errorName(status))); 1168 } 1169 status = U_ZERO_ERROR; 1170 delete zone; 1171 zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000, status); 1172 if(U_SUCCESS(status)){ 1173 errln("Failed. No exception has been thrown for DOM -1 endDay+ savings"); 1174 }else{ 1175 logln("(d) " + UnicodeString(u_errorName(status))); 1176 } 1177 status = U_ZERO_ERROR; 1178 delete zone; 1179 // Make a valid constructor call for subsequent tests. 1180 zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0, status); 1181 1182 zone->setStartRule(0, -1, 0, 0, status); 1183 if(U_SUCCESS(status)){ 1184 errln("Failed. No exception has been thrown for DOM -1 setStartRule +savings"); 1185 } else{ 1186 logln("(e) " + UnicodeString(u_errorName(status))); 1187 } 1188 zone->setStartRule(0, -1, 0, status); 1189 if(U_SUCCESS(status)){ 1190 errln("Failed. No exception has been thrown for DOM -1 setStartRule"); 1191 } else{ 1192 logln("(f) " + UnicodeString(u_errorName(status))); 1193 } 1194 1195 zone->setEndRule(0, -1, 0, 0, status); 1196 if(U_SUCCESS(status)){ 1197 errln("Failed. No exception has been thrown for DOM -1 setEndRule+savings"); 1198 } else{ 1199 logln("(g) " + UnicodeString(u_errorName(status))); 1200 } 1201 1202 zone->setEndRule(0, -1, 0, status); 1203 if(U_SUCCESS(status)){ 1204 errln("Failed. No exception has been thrown for DOM -1 setEndRule"); 1205 } else{ 1206 logln("(h) " + UnicodeString(u_errorName(status))); 1207 } 1208 delete zone; 1209 } 1210 1211 void TimeZoneRegressionTest::TestNegativeDaylightSaving() { 1212 UErrorCode status = U_ZERO_ERROR; 1213 int32_t stdOff = 1 * 60*60*1000; // Standard offset UTC+1 1214 int save = -1 * 60*60*1000; // DST saving amount -1 hour 1215 SimpleTimeZone stzDublin(stdOff, "Dublin-2018", 1216 UCAL_OCTOBER, -1, -UCAL_SUNDAY, 2*60*60*1000, 1217 UCAL_MARCH, -1, -UCAL_SUNDAY, 1*60*60*1000, 1218 save, status); 1219 failure(status, "SimpleTimeZone constructor"); 1220 1221 if (save != stzDublin.getDSTSavings()) { 1222 errln((UnicodeString)"FAIL: DST saving is not " + save); 1223 } 1224 1225 GregorianCalendar cal(* TimeZone::getGMT(), status); 1226 failure(status, "GregorianCalendar constructor"); 1227 1228 UDate testDate; 1229 int32_t rawOffset; 1230 int32_t dstOffset; 1231 1232 cal.set(2018, UCAL_JANUARY, 15, 0, 0, 0); 1233 testDate = cal.getTime(status); 1234 failure(status, "calendar getTime() - Jan 15"); 1235 1236 if (!stzDublin.inDaylightTime(testDate, status)) { 1237 errln("FAIL: The test date (Jan 15) must be in DST."); 1238 } 1239 failure(status, "inDaylightTime() - Jan 15"); 1240 1241 stzDublin.getOffset(testDate, FALSE, rawOffset, dstOffset, status); 1242 failure(status, "getOffset() - Jan 15"); 1243 if (rawOffset != stdOff || dstOffset != save) { 1244 errln((UnicodeString)"FAIL: Expected [stdoff=" + stdOff + ",save=" + save 1245 + "] on the test date (Jan 15), actual[stdoff=" + rawOffset 1246 + ",save=" + dstOffset + "]"); 1247 } 1248 1249 cal.set(2018, UCAL_JULY, 15, 0, 0, 0); 1250 testDate = cal.getTime(status); 1251 failure(status, "calendar getTime() - Jul 15"); 1252 1253 if (stzDublin.inDaylightTime(testDate, status)) { 1254 errln("FAIL: The test date (Jul 15) must be in DST."); 1255 } 1256 failure(status, "inDaylightTime() - Jul 15"); 1257 1258 stzDublin.getOffset(testDate, FALSE, rawOffset, dstOffset, status); 1259 failure(status, "getOffset() - Jul 15"); 1260 if (rawOffset != stdOff || dstOffset != 0) { 1261 errln((UnicodeString)"FAIL: Expected [stdoff=" + stdOff + ",save=" + 0 1262 + "] on the test date (Jul 15), actual[stdoff=" + rawOffset 1263 + ",save=" + dstOffset + "]"); 1264 } 1265 } 1266 1267 1268 #endif /* #if !UCONFIG_NO_FORMATTING */ 1269