1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2007-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ******************************************************************************* 8 */ 9 10 #include "unicode/utypes.h" 11 12 #if !UCONFIG_NO_FORMATTING 13 14 #include "unicode/dtrule.h" 15 #include "unicode/tzrule.h" 16 #include "unicode/rbtz.h" 17 #include "unicode/simpletz.h" 18 #include "unicode/tzrule.h" 19 #include "unicode/calendar.h" 20 #include "unicode/gregocal.h" 21 #include "unicode/strenum.h" 22 #include "unicode/ucal.h" 23 #include "unicode/unistr.h" 24 #include "unicode/ustring.h" 25 #include "unicode/tztrans.h" 26 #include "unicode/vtzone.h" 27 #include "tzrulets.h" 28 #include "zrule.h" 29 #include "ztrans.h" 30 #include "vzone.h" 31 #include "cmemory.h" 32 33 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break 34 #define HOUR (60*60*1000) 35 36 static const char *const TESTZIDS[] = { 37 "AGT", 38 "America/New_York", 39 "America/Los_Angeles", 40 "America/Indiana/Indianapolis", 41 "America/Havana", 42 "Europe/Lisbon", 43 "Europe/Paris", 44 "Asia/Tokyo", 45 "Asia/Sakhalin", 46 "Africa/Cairo", 47 "Africa/Windhoek", 48 "Australia/Sydney", 49 "Etc/GMT+8" 50 }; 51 52 static UBool hasEquivalentTransitions(/*const*/ BasicTimeZone& tz1, /*const*/BasicTimeZone& tz2, 53 UDate start, UDate end, 54 UBool ignoreDstAmount, int32_t maxTransitionTimeDelta, 55 UErrorCode& status); 56 57 class TestZIDEnumeration : public StringEnumeration { 58 public: 59 TestZIDEnumeration(UBool all = FALSE); 60 ~TestZIDEnumeration(); 61 62 virtual int32_t count(UErrorCode& /*status*/) const { 63 return len; 64 } 65 virtual const UnicodeString *snext(UErrorCode& status); 66 virtual void reset(UErrorCode& status); 67 static inline UClassID getStaticClassID() { 68 return (UClassID)&fgClassID; 69 } 70 virtual UClassID getDynamicClassID() const { 71 return getStaticClassID(); 72 } 73 private: 74 static const char fgClassID; 75 int32_t idx; 76 int32_t len; 77 StringEnumeration *tzenum; 78 }; 79 80 const char TestZIDEnumeration::fgClassID = 0; 81 82 TestZIDEnumeration::TestZIDEnumeration(UBool all) 83 : idx(0) { 84 UErrorCode status = U_ZERO_ERROR; 85 if (all) { 86 tzenum = TimeZone::createEnumeration(); 87 len = tzenum->count(status); 88 } else { 89 tzenum = NULL; 90 len = UPRV_LENGTHOF(TESTZIDS); 91 } 92 } 93 94 TestZIDEnumeration::~TestZIDEnumeration() { 95 if (tzenum != NULL) { 96 delete tzenum; 97 } 98 } 99 100 const UnicodeString* 101 TestZIDEnumeration::snext(UErrorCode& status) { 102 if (tzenum != NULL) { 103 return tzenum->snext(status); 104 } else if (U_SUCCESS(status) && idx < len) { 105 unistr = UnicodeString(TESTZIDS[idx++], ""); 106 return &unistr; 107 } 108 return NULL; 109 } 110 111 void 112 TestZIDEnumeration::reset(UErrorCode& status) { 113 if (tzenum != NULL) { 114 tzenum->reset(status); 115 } else { 116 idx = 0; 117 } 118 } 119 120 121 void TimeZoneRuleTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 122 { 123 if (exec) { 124 logln("TestSuite TestTimeZoneRule"); 125 } 126 switch (index) { 127 CASE(0, TestSimpleRuleBasedTimeZone); 128 CASE(1, TestHistoricalRuleBasedTimeZone); 129 CASE(2, TestOlsonTransition); 130 CASE(3, TestRBTZTransition); 131 CASE(4, TestHasEquivalentTransitions); 132 CASE(5, TestVTimeZoneRoundTrip); 133 CASE(6, TestVTimeZoneRoundTripPartial); 134 CASE(7, TestVTimeZoneSimpleWrite); 135 CASE(8, TestVTimeZoneHeaderProps); 136 CASE(9, TestGetSimpleRules); 137 CASE(10, TestTimeZoneRuleCoverage); 138 CASE(11, TestSimpleTimeZoneCoverage); 139 CASE(12, TestVTimeZoneCoverage); 140 CASE(13, TestVTimeZoneParse); 141 CASE(14, TestT6216); 142 CASE(15, TestT6669); 143 CASE(16, TestVTimeZoneWrapper); 144 CASE(17, TestT8943); 145 default: name = ""; break; 146 } 147 } 148 149 /* 150 * Compare SimpleTimeZone with equivalent RBTZ 151 */ 152 void 153 TimeZoneRuleTest::TestSimpleRuleBasedTimeZone(void) { 154 UErrorCode status = U_ZERO_ERROR; 155 SimpleTimeZone stz(-1*HOUR, "TestSTZ", 156 UCAL_SEPTEMBER, -30, -UCAL_SATURDAY, 1*HOUR, SimpleTimeZone::WALL_TIME, 157 UCAL_FEBRUARY, 2, UCAL_SUNDAY, 1*HOUR, SimpleTimeZone::WALL_TIME, 158 1*HOUR, status); 159 if (U_FAILURE(status)) { 160 errln("FAIL: Couldn't create SimpleTimezone."); 161 } 162 163 DateTimeRule *dtr; 164 AnnualTimeZoneRule *atzr; 165 int32_t STARTYEAR = 2000; 166 167 InitialTimeZoneRule *ir = new InitialTimeZoneRule( 168 "RBTZ_Initial", // Initial time Name 169 -1*HOUR, // Raw offset 170 1*HOUR); // DST saving amount 171 172 // Original rules 173 RuleBasedTimeZone *rbtz1 = new RuleBasedTimeZone("RBTZ1", ir->clone()); 174 dtr = new DateTimeRule(UCAL_SEPTEMBER, 30, UCAL_SATURDAY, FALSE, 175 1*HOUR, DateTimeRule::WALL_TIME); // SUN<=30 in September, at 1AM wall time 176 atzr = new AnnualTimeZoneRule("RBTZ_DST1", 177 -1*HOUR /*rawOffset*/, 1*HOUR /*dstSavings*/, dtr, 178 STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 179 rbtz1->addTransitionRule(atzr, status); 180 if (U_FAILURE(status)) { 181 errln("FAIL: couldn't add AnnualTimeZoneRule 1-1."); 182 } 183 dtr = new DateTimeRule(UCAL_FEBRUARY, 2, UCAL_SUNDAY, 184 1*HOUR, DateTimeRule::WALL_TIME); // 2nd Sunday in February, at 1AM wall time 185 atzr = new AnnualTimeZoneRule("RBTZ_STD1", 186 -1*HOUR /*rawOffset*/, 0 /*dstSavings*/, dtr, 187 STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 188 rbtz1->addTransitionRule(atzr, status); 189 if (U_FAILURE(status)) { 190 errln("FAIL: couldn't add AnnualTimeZoneRule 1-2."); 191 } 192 rbtz1->complete(status); 193 if (U_FAILURE(status)) { 194 errln("FAIL: couldn't complete RBTZ 1."); 195 } 196 197 // Equivalent, but different date rule type 198 RuleBasedTimeZone *rbtz2 = new RuleBasedTimeZone("RBTZ2", ir->clone()); 199 dtr = new DateTimeRule(UCAL_SEPTEMBER, -1, UCAL_SATURDAY, 200 1*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in September at 1AM wall time 201 atzr = new AnnualTimeZoneRule("RBTZ_DST2", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 202 rbtz2->addTransitionRule(atzr, status); 203 if (U_FAILURE(status)) { 204 errln("FAIL: couldn't add AnnualTimeZoneRule 2-1."); 205 } 206 dtr = new DateTimeRule(UCAL_FEBRUARY, 8, UCAL_SUNDAY, true, 207 1*HOUR, DateTimeRule::WALL_TIME); // SUN>=8 in February, at 1AM wall time 208 atzr = new AnnualTimeZoneRule("RBTZ_STD2", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 209 rbtz2->addTransitionRule(atzr, status); 210 if (U_FAILURE(status)) { 211 errln("FAIL: couldn't add AnnualTimeZoneRule 2-2."); 212 } 213 rbtz2->complete(status); 214 if (U_FAILURE(status)) { 215 errln("FAIL: couldn't complete RBTZ 2"); 216 } 217 218 // Equivalent, but different time rule type 219 RuleBasedTimeZone *rbtz3 = new RuleBasedTimeZone("RBTZ3", ir->clone()); 220 dtr = new DateTimeRule(UCAL_SEPTEMBER, 30, UCAL_SATURDAY, false, 221 2*HOUR, DateTimeRule::UTC_TIME); 222 atzr = new AnnualTimeZoneRule("RBTZ_DST3", -1*HOUR, 1*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 223 rbtz3->addTransitionRule(atzr, status); 224 if (U_FAILURE(status)) { 225 errln("FAIL: couldn't add AnnualTimeZoneRule 3-1."); 226 } 227 dtr = new DateTimeRule(UCAL_FEBRUARY, 2, UCAL_SUNDAY, 228 0*HOUR, DateTimeRule::STANDARD_TIME); 229 atzr = new AnnualTimeZoneRule("RBTZ_STD3", -1*HOUR, 0, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 230 rbtz3->addTransitionRule(atzr, status); 231 if (U_FAILURE(status)) { 232 errln("FAIL: couldn't add AnnualTimeZoneRule 3-2."); 233 } 234 rbtz3->complete(status); 235 if (U_FAILURE(status)) { 236 errln("FAIL: couldn't complete RBTZ 3"); 237 } 238 239 // Check equivalency for 10 years 240 UDate start = getUTCMillis(STARTYEAR, UCAL_JANUARY, 1); 241 UDate until = getUTCMillis(STARTYEAR + 10, UCAL_JANUARY, 1); 242 243 if (!(stz.hasEquivalentTransitions(*rbtz1, start, until, TRUE, status))) { 244 errln("FAIL: rbtz1 must be equivalent to the SimpleTimeZone in the time range."); 245 } 246 if (U_FAILURE(status)) { 247 errln("FAIL: error returned from hasEquivalentTransitions"); 248 } 249 if (!(stz.hasEquivalentTransitions(*rbtz2, start, until, TRUE, status))) { 250 errln("FAIL: rbtz2 must be equivalent to the SimpleTimeZone in the time range."); 251 } 252 if (U_FAILURE(status)) { 253 errln("FAIL: error returned from hasEquivalentTransitions"); 254 } 255 if (!(stz.hasEquivalentTransitions(*rbtz3, start, until, TRUE, status))) { 256 errln("FAIL: rbtz3 must be equivalent to the SimpleTimeZone in the time range."); 257 } 258 if (U_FAILURE(status)) { 259 errln("FAIL: error returned from hasEquivalentTransitions"); 260 } 261 262 // hasSameRules 263 if (rbtz1->hasSameRules(*rbtz2)) { 264 errln("FAIL: rbtz1 and rbtz2 have different rules, but returned true."); 265 } 266 if (rbtz1->hasSameRules(*rbtz3)) { 267 errln("FAIL: rbtz1 and rbtz3 have different rules, but returned true."); 268 } 269 RuleBasedTimeZone *rbtz1c = (RuleBasedTimeZone*)rbtz1->clone(); 270 if (!rbtz1->hasSameRules(*rbtz1c)) { 271 errln("FAIL: Cloned RuleBasedTimeZone must have the same rules with the original."); 272 } 273 274 // getOffset 275 int32_t era, year, month, dayOfMonth, dayOfWeek, millisInDay; 276 UDate time; 277 int32_t offset, dstSavings; 278 UBool dst; 279 280 GregorianCalendar *cal = new GregorianCalendar(status); 281 if (U_FAILURE(status)) { 282 dataerrln("FAIL: Could not create a Gregorian calendar instance.: %s", u_errorName(status)); 283 delete rbtz1; 284 delete rbtz2; 285 delete rbtz3; 286 delete rbtz1c; 287 return; 288 } 289 cal->setTimeZone(*rbtz1); 290 cal->clear(); 291 292 // Jan 1, 1000 BC 293 cal->set(UCAL_ERA, GregorianCalendar::BC); 294 cal->set(1000, UCAL_JANUARY, 1); 295 296 era = cal->get(UCAL_ERA, status); 297 year = cal->get(UCAL_YEAR, status); 298 month = cal->get(UCAL_MONTH, status); 299 dayOfMonth = cal->get(UCAL_DAY_OF_MONTH, status); 300 dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); 301 millisInDay = cal->get(UCAL_MILLISECONDS_IN_DAY, status); 302 time = cal->getTime(status); 303 if (U_FAILURE(status)) { 304 errln("FAIL: Could not get calendar field values."); 305 } 306 offset = rbtz1->getOffset(era, year, month, dayOfMonth, dayOfWeek, millisInDay, status); 307 if (U_FAILURE(status)) { 308 errln("FAIL: getOffset(7 args) failed."); 309 } 310 if (offset != 0) { 311 errln(UnicodeString("FAIL: Invalid time zone offset: ") + offset + " /expected: 0"); 312 } 313 dst = rbtz1->inDaylightTime(time, status); 314 if (U_FAILURE(status)) { 315 errln("FAIL: inDaylightTime failed."); 316 } 317 if (!dst) { 318 errln("FAIL: Invalid daylight saving time"); 319 } 320 rbtz1->getOffset(time, TRUE, offset, dstSavings, status); 321 if (U_FAILURE(status)) { 322 errln("FAIL: getOffset(5 args) failed."); 323 } 324 if (offset != -3600000) { 325 errln(UnicodeString("FAIL: Invalid time zone raw offset: ") + offset + " /expected: -3600000"); 326 } 327 if (dstSavings != 3600000) { 328 errln(UnicodeString("FAIL: Invalid DST amount: ") + dstSavings + " /expected: 3600000"); 329 } 330 331 // July 1, 2000, AD 332 cal->set(UCAL_ERA, GregorianCalendar::AD); 333 cal->set(2000, UCAL_JULY, 1); 334 335 era = cal->get(UCAL_ERA, status); 336 year = cal->get(UCAL_YEAR, status); 337 month = cal->get(UCAL_MONTH, status); 338 dayOfMonth = cal->get(UCAL_DAY_OF_MONTH, status); 339 dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); 340 millisInDay = cal->get(UCAL_MILLISECONDS_IN_DAY, status); 341 time = cal->getTime(status); 342 if (U_FAILURE(status)) { 343 errln("FAIL: Could not get calendar field values."); 344 } 345 offset = rbtz1->getOffset(era, year, month, dayOfMonth, dayOfWeek, millisInDay, status); 346 if (U_FAILURE(status)) { 347 errln("FAIL: getOffset(7 args) failed."); 348 } 349 if (offset != -3600000) { 350 errln((UnicodeString)"FAIL: Invalid time zone offset: " + offset + " /expected: -3600000"); 351 } 352 dst = rbtz1->inDaylightTime(time, status); 353 if (U_FAILURE(status)) { 354 errln("FAIL: inDaylightTime failed."); 355 } 356 if (dst) { 357 errln("FAIL: Invalid daylight saving time"); 358 } 359 rbtz1->getOffset(time, TRUE, offset, dstSavings, status); 360 if (U_FAILURE(status)) { 361 errln("FAIL: getOffset(5 args) failed."); 362 } 363 if (offset != -3600000) { 364 errln((UnicodeString)"FAIL: Invalid time zone raw offset: " + offset + " /expected: -3600000"); 365 } 366 if (dstSavings != 0) { 367 errln((UnicodeString)"FAIL: Invalid DST amount: " + dstSavings + " /expected: 0"); 368 } 369 370 // getRawOffset 371 offset = rbtz1->getRawOffset(); 372 if (offset != -1*HOUR) { 373 errln((UnicodeString)"FAIL: Invalid time zone raw offset returned by getRawOffset: " 374 + offset + " /expected: -3600000"); 375 } 376 377 // operator=/==/!= 378 RuleBasedTimeZone rbtz0("RBTZ1", ir->clone()); 379 if (rbtz0 == *rbtz1 || !(rbtz0 != *rbtz1)) { 380 errln("FAIL: RuleBasedTimeZone rbtz0 is not equal to rbtz1, but got wrong result"); 381 } 382 rbtz0 = *rbtz1; 383 if (rbtz0 != *rbtz1 || !(rbtz0 == *rbtz1)) { 384 errln("FAIL: RuleBasedTimeZone rbtz0 is equal to rbtz1, but got wrong result"); 385 } 386 387 // setRawOffset 388 const int32_t RAW = -10*HOUR; 389 rbtz0.setRawOffset(RAW); 390 if (rbtz0.getRawOffset() != RAW) { 391 logln("setRawOffset is implemented in RuleBasedTimeZone"); 392 } 393 394 // useDaylightTime 395 if (!rbtz1->useDaylightTime()) { 396 errln("FAIL: useDaylightTime returned FALSE"); 397 } 398 399 // Try to add 3rd final rule 400 dtr = new DateTimeRule(UCAL_OCTOBER, 15, 1*HOUR, DateTimeRule::WALL_TIME); 401 atzr = new AnnualTimeZoneRule("3RD_ATZ", -1*HOUR, 2*HOUR, dtr, STARTYEAR, AnnualTimeZoneRule::MAX_YEAR); 402 rbtz1->addTransitionRule(atzr, status); 403 if (U_SUCCESS(status)) { 404 errln("FAIL: 3rd final rule must be rejected"); 405 } else { 406 delete atzr; 407 } 408 409 // Try to add an initial rule 410 InitialTimeZoneRule *ir1 = new InitialTimeZoneRule("Test Initial", 2*HOUR, 0); 411 rbtz1->addTransitionRule(ir1, status); 412 if (U_SUCCESS(status)) { 413 errln("FAIL: InitialTimeZoneRule must be rejected"); 414 } else { 415 delete ir1; 416 } 417 418 delete ir; 419 delete rbtz1; 420 delete rbtz2; 421 delete rbtz3; 422 delete rbtz1c; 423 delete cal; 424 } 425 426 /* 427 * Test equivalency between OlsonTimeZone and custom RBTZ representing the 428 * equivalent rules in a certain time range 429 */ 430 void 431 TimeZoneRuleTest::TestHistoricalRuleBasedTimeZone(void) { 432 UErrorCode status = U_ZERO_ERROR; 433 434 // Compare to America/New_York with equivalent RBTZ 435 BasicTimeZone *ny = (BasicTimeZone*)TimeZone::createTimeZone("America/New_York"); 436 437 //RBTZ 438 InitialTimeZoneRule *ir = new InitialTimeZoneRule("EST", -5*HOUR, 0); 439 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone("EST5EDT", ir); 440 441 DateTimeRule *dtr; 442 AnnualTimeZoneRule *tzr; 443 444 // Standard time 445 dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY, 446 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in October, at 2AM wall time 447 tzr = new AnnualTimeZoneRule("EST", -5*HOUR /*rawOffset*/, 0 /*dstSavings*/, dtr, 1967, 2006); 448 rbtz->addTransitionRule(tzr, status); 449 if (U_FAILURE(status)) { 450 errln("FAIL: couldn't add AnnualTimeZoneRule 1."); 451 } 452 453 dtr = new DateTimeRule(UCAL_NOVEMBER, 1, UCAL_SUNDAY, 454 true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=1 in November, at 2AM wall time 455 tzr = new AnnualTimeZoneRule("EST", -5*HOUR, 0, dtr, 2007, AnnualTimeZoneRule::MAX_YEAR); 456 rbtz->addTransitionRule(tzr, status); 457 if (U_FAILURE(status)) { 458 errln("FAIL: couldn't add AnnualTimeZoneRule 2."); 459 } 460 461 // Daylight saving time 462 dtr = new DateTimeRule(UCAL_APRIL, -1, UCAL_SUNDAY, 463 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in April, at 2AM wall time 464 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1967, 1973); 465 rbtz->addTransitionRule(tzr, status); 466 if (U_FAILURE(status)) { 467 errln("FAIL: couldn't add AnnualTimeZoneRule 3."); 468 } 469 470 dtr = new DateTimeRule(UCAL_JANUARY, 6, 471 2*HOUR, DateTimeRule::WALL_TIME); // January 6, at 2AM wall time 472 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1974, 1974); 473 rbtz->addTransitionRule(tzr, status); 474 if (U_FAILURE(status)) { 475 errln("FAIL: couldn't add AnnualTimeZoneRule 4."); 476 } 477 478 dtr = new DateTimeRule(UCAL_FEBRUARY, 23, 479 2*HOUR, DateTimeRule::WALL_TIME); // February 23, at 2AM wall time 480 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1975, 1975); 481 rbtz->addTransitionRule(tzr, status); 482 if (U_FAILURE(status)) { 483 errln("FAIL: couldn't add AnnualTimeZoneRule 5."); 484 } 485 486 dtr = new DateTimeRule(UCAL_APRIL, -1, UCAL_SUNDAY, 487 2*HOUR, DateTimeRule::WALL_TIME); // Last Sunday in April, at 2AM wall time 488 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1976, 1986); 489 rbtz->addTransitionRule(tzr, status); 490 if (U_FAILURE(status)) { 491 errln("FAIL: couldn't add AnnualTimeZoneRule 6."); 492 } 493 494 dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY, 495 true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=1 in April, at 2AM wall time 496 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 1987, 2006); 497 rbtz->addTransitionRule(tzr, status); 498 if (U_FAILURE(status)) { 499 errln("FAIL: couldn't add AnnualTimeZoneRule 7."); 500 } 501 502 dtr = new DateTimeRule(UCAL_MARCH, 8, UCAL_SUNDAY, 503 true, 2*HOUR, DateTimeRule::WALL_TIME); // SUN>=8 in March, at 2AM wall time 504 tzr = new AnnualTimeZoneRule("EDT", -5*HOUR, 1*HOUR, dtr, 2007, AnnualTimeZoneRule::MAX_YEAR); 505 rbtz->addTransitionRule(tzr, status); 506 if (U_FAILURE(status)) { 507 errln("FAIL: couldn't add AnnualTimeZoneRule 7."); 508 } 509 510 rbtz->complete(status); 511 if (U_FAILURE(status)) { 512 errln("FAIL: couldn't complete RBTZ."); 513 } 514 515 // hasEquivalentTransitions 516 UDate jan1_1950 = getUTCMillis(1950, UCAL_JANUARY, 1); 517 UDate jan1_1967 = getUTCMillis(1971, UCAL_JANUARY, 1); 518 UDate jan1_2010 = getUTCMillis(2010, UCAL_JANUARY, 1); 519 520 if (!ny->hasEquivalentTransitions(*rbtz, jan1_1967, jan1_2010, TRUE, status)) { 521 dataerrln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010"); 522 } 523 if (U_FAILURE(status)) { 524 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1967-2010"); 525 } 526 if (ny->hasEquivalentTransitions(*rbtz, jan1_1950, jan1_2010, TRUE, status)) { 527 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010"); 528 } 529 if (U_FAILURE(status)) { 530 errln("FAIL: error returned from hasEquivalentTransitions for ny/rbtz 1950-2010"); 531 } 532 533 // Same with above, but calling RBTZ#hasEquivalentTransitions against OlsonTimeZone 534 if (!rbtz->hasEquivalentTransitions(*ny, jan1_1967, jan1_2010, TRUE, status)) { 535 dataerrln("FAIL: The RBTZ must be equivalent to America/New_York between 1967 and 2010 "); 536 } 537 if (U_FAILURE(status)) { 538 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1967-2010"); 539 } 540 if (rbtz->hasEquivalentTransitions(*ny, jan1_1950, jan1_2010, TRUE, status)) { 541 errln("FAIL: The RBTZ must not be equivalent to America/New_York between 1950 and 2010"); 542 } 543 if (U_FAILURE(status)) { 544 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/ny 1950-2010"); 545 } 546 547 // TimeZone APIs 548 if (ny->hasSameRules(*rbtz) || rbtz->hasSameRules(*ny)) { 549 errln("FAIL: hasSameRules must return false"); 550 } 551 RuleBasedTimeZone *rbtzc = (RuleBasedTimeZone*)rbtz->clone(); 552 if (!rbtz->hasSameRules(*rbtzc) || !rbtz->hasEquivalentTransitions(*rbtzc, jan1_1950, jan1_2010, TRUE, status)) { 553 errln("FAIL: hasSameRules/hasEquivalentTransitions must return true for cloned RBTZs"); 554 } 555 if (U_FAILURE(status)) { 556 errln("FAIL: error returned from hasEquivalentTransitions for rbtz/rbtzc 1950-2010"); 557 } 558 559 UDate times[] = { 560 getUTCMillis(2006, UCAL_MARCH, 15), 561 getUTCMillis(2006, UCAL_NOVEMBER, 1), 562 getUTCMillis(2007, UCAL_MARCH, 15), 563 getUTCMillis(2007, UCAL_NOVEMBER, 1), 564 getUTCMillis(2008, UCAL_MARCH, 15), 565 getUTCMillis(2008, UCAL_NOVEMBER, 1), 566 0 567 }; 568 int32_t offset1, dst1; 569 int32_t offset2, dst2; 570 571 for (int i = 0; times[i] != 0; i++) { 572 // Check getOffset - must return the same results for these time data 573 rbtz->getOffset(times[i], FALSE, offset1, dst1, status); 574 if (U_FAILURE(status)) { 575 errln("FAIL: rbtz->getOffset failed"); 576 } 577 ny->getOffset(times[i], FALSE, offset2, dst2, status); 578 if (U_FAILURE(status)) { 579 errln("FAIL: ny->getOffset failed"); 580 } 581 if (offset1 != offset2 || dst1 != dst2) { 582 dataerrln("FAIL: Incompatible time zone offset/dstSavings for ny and rbtz"); 583 } 584 585 // Check inDaylightTime 586 if (rbtz->inDaylightTime(times[i], status) != ny->inDaylightTime(times[i], status)) { 587 dataerrln("FAIL: Incompatible daylight saving time for ny and rbtz"); 588 } 589 if (U_FAILURE(status)) { 590 errln("FAIL: inDaylightTime failed"); 591 } 592 } 593 594 delete ny; 595 delete rbtz; 596 delete rbtzc; 597 } 598 599 /* 600 * Check if transitions returned by getNextTransition/getPreviousTransition 601 * are actual time transitions. 602 */ 603 void 604 TimeZoneRuleTest::TestOlsonTransition(void) { 605 606 const int32_t TESTYEARS[][2] = { 607 {1895, 1905}, // including int32 minimum second 608 {1965, 1975}, // including the epoch 609 {1995, 2015}, // practical year range 610 {0,0} 611 }; 612 613 UErrorCode status = U_ZERO_ERROR; 614 TestZIDEnumeration tzenum(!quick); 615 while (TRUE) { 616 const UnicodeString *tzid = tzenum.snext(status); 617 if (tzid == NULL) { 618 break; 619 } 620 if (U_FAILURE(status)) { 621 errln("FAIL: error returned while enumerating timezone IDs."); 622 break; 623 } 624 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid); 625 for (int32_t i = 0; TESTYEARS[i][0] != 0 || TESTYEARS[i][1] != 0; i++) { 626 UDate lo = getUTCMillis(TESTYEARS[i][0], UCAL_JANUARY, 1); 627 UDate hi = getUTCMillis(TESTYEARS[i][1], UCAL_JANUARY, 1); 628 verifyTransitions(*tz, lo, hi); 629 } 630 delete tz; 631 } 632 } 633 634 /* 635 * Check if an OlsonTimeZone and its equivalent RBTZ have the exact same 636 * transitions. 637 */ 638 void 639 TimeZoneRuleTest::TestRBTZTransition(void) { 640 const int32_t STARTYEARS[] = { 641 1900, 642 1960, 643 1990, 644 2010, 645 0 646 }; 647 648 UErrorCode status = U_ZERO_ERROR; 649 TestZIDEnumeration tzenum(!quick); 650 while (TRUE) { 651 const UnicodeString *tzid = tzenum.snext(status); 652 if (tzid == NULL) { 653 break; 654 } 655 if (U_FAILURE(status)) { 656 errln("FAIL: error returned while enumerating timezone IDs."); 657 break; 658 } 659 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid); 660 int32_t ruleCount = tz->countTransitionRules(status); 661 662 const InitialTimeZoneRule *initial; 663 const TimeZoneRule **trsrules = new const TimeZoneRule*[ruleCount]; 664 tz->getTimeZoneRules(initial, trsrules, ruleCount, status); 665 if (U_FAILURE(status)) { 666 errln((UnicodeString)"FAIL: failed to get the TimeZoneRules from time zone " + *tzid); 667 } 668 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(*tzid, initial->clone()); 669 if (U_FAILURE(status)) { 670 errln((UnicodeString)"FAIL: failed to get the transition rule count from time zone " + *tzid); 671 } 672 for (int32_t i = 0; i < ruleCount; i++) { 673 rbtz->addTransitionRule(trsrules[i]->clone(), status); 674 if (U_FAILURE(status)) { 675 errln((UnicodeString)"FAIL: failed to add a transition rule at index " + i + " to the RBTZ for " + *tzid); 676 } 677 } 678 rbtz->complete(status); 679 if (U_FAILURE(status)) { 680 errln((UnicodeString)"FAIL: complete() failed for the RBTZ for " + *tzid); 681 } 682 683 for (int32_t idx = 0; STARTYEARS[idx] != 0; idx++) { 684 UDate start = getUTCMillis(STARTYEARS[idx], UCAL_JANUARY, 1); 685 UDate until = getUTCMillis(STARTYEARS[idx] + 20, UCAL_JANUARY, 1); 686 // Compare the original OlsonTimeZone with the RBTZ starting the startTime for 20 years 687 688 // Ascending 689 compareTransitionsAscending(*tz, *rbtz, start, until, FALSE); 690 // Ascending/inclusive 691 compareTransitionsAscending(*tz, *rbtz, start + 1, until, TRUE); 692 // Descending 693 compareTransitionsDescending(*tz, *rbtz, start, until, FALSE); 694 // Descending/inclusive 695 compareTransitionsDescending(*tz, *rbtz, start + 1, until, TRUE); 696 } 697 delete [] trsrules; 698 delete rbtz; 699 delete tz; 700 } 701 } 702 703 void 704 TimeZoneRuleTest::TestHasEquivalentTransitions(void) { 705 // America/New_York and America/Indiana/Indianapolis are equivalent 706 // since 2006 707 UErrorCode status = U_ZERO_ERROR; 708 BasicTimeZone *newyork = (BasicTimeZone*)TimeZone::createTimeZone("America/New_York"); 709 BasicTimeZone *indianapolis = (BasicTimeZone*)TimeZone::createTimeZone("America/Indiana/Indianapolis"); 710 BasicTimeZone *gmt_5 = (BasicTimeZone*)TimeZone::createTimeZone("Etc/GMT+5"); 711 712 UDate jan1_1971 = getUTCMillis(1971, UCAL_JANUARY, 1); 713 UDate jan1_2005 = getUTCMillis(2005, UCAL_JANUARY, 1); 714 UDate jan1_2006 = getUTCMillis(2006, UCAL_JANUARY, 1); 715 UDate jan1_2007 = getUTCMillis(2007, UCAL_JANUARY, 1); 716 UDate jan1_2011 = getUTCMillis(2010, UCAL_JANUARY, 1); 717 718 if (newyork->hasEquivalentTransitions(*indianapolis, jan1_2005, jan1_2011, TRUE, status)) { 719 dataerrln("FAIL: New_York is not equivalent to Indianapolis between 2005 and 2010"); 720 } 721 if (U_FAILURE(status)) { 722 errln("FAIL: error status is returned from hasEquivalentTransition"); 723 } 724 if (!newyork->hasEquivalentTransitions(*indianapolis, jan1_2006, jan1_2011, TRUE, status)) { 725 errln("FAIL: New_York is equivalent to Indianapolis between 2006 and 2010"); 726 } 727 if (U_FAILURE(status)) { 728 errln("FAIL: error status is returned from hasEquivalentTransition"); 729 } 730 731 if (!indianapolis->hasEquivalentTransitions(*gmt_5, jan1_1971, jan1_2006, TRUE, status)) { 732 errln("FAIL: Indianapolis is equivalent to GMT+5 between 1971 and 2005"); 733 } 734 if (U_FAILURE(status)) { 735 errln("FAIL: error status is returned from hasEquivalentTransition"); 736 } 737 if (indianapolis->hasEquivalentTransitions(*gmt_5, jan1_1971, jan1_2007, TRUE, status)) { 738 dataerrln("FAIL: Indianapolis is not equivalent to GMT+5 between 1971 and 2006"); 739 } 740 if (U_FAILURE(status)) { 741 errln("FAIL: error status is returned from hasEquivalentTransition"); 742 } 743 744 // Cloned TimeZone 745 BasicTimeZone *newyork2 = (BasicTimeZone*)newyork->clone(); 746 if (!newyork->hasEquivalentTransitions(*newyork2, jan1_1971, jan1_2011, FALSE, status)) { 747 errln("FAIL: Cloned TimeZone must have the same transitions"); 748 } 749 if (U_FAILURE(status)) { 750 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2"); 751 } 752 if (!newyork->hasEquivalentTransitions(*newyork2, jan1_1971, jan1_2011, TRUE, status)) { 753 errln("FAIL: Cloned TimeZone must have the same transitions"); 754 } 755 if (U_FAILURE(status)) { 756 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/newyork2"); 757 } 758 759 // America/New_York and America/Los_Angeles has same DST start rules, but 760 // raw offsets are different 761 BasicTimeZone *losangeles = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles"); 762 if (newyork->hasEquivalentTransitions(*losangeles, jan1_2006, jan1_2011, TRUE, status)) { 763 dataerrln("FAIL: New_York is not equivalent to Los Angeles, but returned true"); 764 } 765 if (U_FAILURE(status)) { 766 errln("FAIL: error status is returned from hasEquivalentTransition for newyork/losangeles"); 767 } 768 769 delete newyork; 770 delete newyork2; 771 delete indianapolis; 772 delete gmt_5; 773 delete losangeles; 774 } 775 776 /* 777 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format, create a new 778 * VTimeZone from the VTIMEZONE data, then compare transitions 779 */ 780 void 781 TimeZoneRuleTest::TestVTimeZoneRoundTrip(void) { 782 UDate startTime = getUTCMillis(1850, UCAL_JANUARY, 1); 783 UDate endTime = getUTCMillis(2050, UCAL_JANUARY, 1); 784 785 UErrorCode status = U_ZERO_ERROR; 786 TestZIDEnumeration tzenum(!quick); 787 while (TRUE) { 788 const UnicodeString *tzid = tzenum.snext(status); 789 if (tzid == NULL) { 790 break; 791 } 792 if (U_FAILURE(status)) { 793 errln("FAIL: error returned while enumerating timezone IDs."); 794 break; 795 } 796 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid); 797 VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid); 798 vtz_org->setTZURL("http://source.icu-project.org/timezone"); 799 vtz_org->setLastModified(Calendar::getNow()); 800 VTimeZone *vtz_new = NULL; 801 UnicodeString vtzdata; 802 // Write out VTIMEZONE data 803 vtz_org->write(vtzdata, status); 804 if (U_FAILURE(status)) { 805 errln((UnicodeString)"FAIL: error returned while writing time zone rules for " + 806 *tzid + " into VTIMEZONE format."); 807 } else { 808 // Read VTIMEZONE data 809 vtz_new = VTimeZone::createVTimeZone(vtzdata, status); 810 if (U_FAILURE(status)) { 811 errln((UnicodeString)"FAIL: error returned while reading VTIMEZONE data for " + *tzid); 812 } else { 813 // Write out VTIMEZONE one more time 814 UnicodeString vtzdata1; 815 vtz_new->write(vtzdata1, status); 816 if (U_FAILURE(status)) { 817 errln((UnicodeString)"FAIL: error returned while writing time zone rules for " + 818 *tzid + "(vtz_new) into VTIMEZONE format."); 819 } else { 820 // Make sure VTIMEZONE data is exactly same with the first one 821 if (vtzdata != vtzdata1) { 822 errln((UnicodeString)"FAIL: different VTIMEZONE data after round trip for " + *tzid); 823 } 824 } 825 // Check equivalency after the first transition. 826 // The DST information before the first transition might be lost 827 // because there is no good way to represent the initial time with 828 // VTIMEZONE. 829 int32_t raw1, raw2, dst1, dst2; 830 tz->getOffset(startTime, FALSE, raw1, dst1, status); 831 vtz_new->getOffset(startTime, FALSE, raw2, dst2, status); 832 if (U_FAILURE(status)) { 833 errln("FAIL: error status is returned from getOffset"); 834 } else { 835 if (raw1 + dst1 != raw2 + dst2) { 836 errln("FAIL: VTimeZone for " + *tzid + 837 " is not equivalent to its OlsonTimeZone corresponding at " 838 + dateToString(startTime)); 839 } 840 TimeZoneTransition trans; 841 UBool avail = tz->getNextTransition(startTime, FALSE, trans); 842 if (avail) { 843 if (!vtz_new->hasEquivalentTransitions(*tz, trans.getTime(), 844 endTime, TRUE, status)) { 845 int32_t maxDelta = 1000; 846 if (!hasEquivalentTransitions(*vtz_new, *tz, trans.getTime() + maxDelta, 847 endTime, TRUE, maxDelta, status)) { 848 errln("FAIL: VTimeZone for " + *tzid + 849 " is not equivalent to its OlsonTimeZone corresponding."); 850 } else { 851 logln("VTimeZone for " + *tzid + 852 " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta); 853 } 854 } 855 if (U_FAILURE(status)) { 856 errln("FAIL: error status is returned from hasEquivalentTransition"); 857 } 858 } 859 } 860 } 861 if (vtz_new != NULL) { 862 delete vtz_new; 863 vtz_new = NULL; 864 } 865 } 866 delete tz; 867 delete vtz_org; 868 } 869 } 870 871 /* 872 * Write out time zone rules of OlsonTimeZone after a cutover date into VTIMEZONE format, 873 * create a new VTimeZone from the VTIMEZONE data, then compare transitions 874 */ 875 void 876 TimeZoneRuleTest::TestVTimeZoneRoundTripPartial(void) { 877 const int32_t STARTYEARS[] = { 878 1900, 879 1950, 880 2020, 881 0 882 }; 883 UDate endTime = getUTCMillis(2050, UCAL_JANUARY, 1); 884 885 UErrorCode status = U_ZERO_ERROR; 886 TestZIDEnumeration tzenum(!quick); 887 while (TRUE) { 888 const UnicodeString *tzid = tzenum.snext(status); 889 if (tzid == NULL) { 890 break; 891 } 892 if (U_FAILURE(status)) { 893 errln("FAIL: error returned while enumerating timezone IDs."); 894 break; 895 } 896 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid); 897 VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid); 898 VTimeZone *vtz_new = NULL; 899 UnicodeString vtzdata; 900 901 for (int32_t i = 0; STARTYEARS[i] != 0; i++) { 902 // Write out VTIMEZONE 903 UDate startTime = getUTCMillis(STARTYEARS[i], UCAL_JANUARY, 1); 904 vtz_org->write(startTime, vtzdata, status); 905 if (U_FAILURE(status)) { 906 errln((UnicodeString)"FAIL: error returned while writing time zone rules for " + 907 *tzid + " into VTIMEZONE format since " + dateToString(startTime)); 908 } else { 909 // Read VTIMEZONE data 910 vtz_new = VTimeZone::createVTimeZone(vtzdata, status); 911 if (U_FAILURE(status)) { 912 errln((UnicodeString)"FAIL: error returned while reading VTIMEZONE data for " + *tzid 913 + " since " + dateToString(startTime)); 914 } else { 915 // Check equivalency after the first transition. 916 // The DST information before the first transition might be lost 917 // because there is no good way to represent the initial time with 918 // VTIMEZONE. 919 int32_t raw1, raw2, dst1, dst2; 920 tz->getOffset(startTime, FALSE, raw1, dst1, status); 921 vtz_new->getOffset(startTime, FALSE, raw2, dst2, status); 922 if (U_FAILURE(status)) { 923 errln("FAIL: error status is returned from getOffset"); 924 } else { 925 if (raw1 + dst1 != raw2 + dst2) { 926 errln("FAIL: VTimeZone for " + *tzid + 927 " is not equivalent to its OlsonTimeZone corresponding at " 928 + dateToString(startTime)); 929 } 930 TimeZoneTransition trans; 931 UBool avail = tz->getNextTransition(startTime, FALSE, trans); 932 if (avail) { 933 if (!vtz_new->hasEquivalentTransitions(*tz, trans.getTime(), 934 endTime, TRUE, status)) { 935 int32_t maxDelta = 1000; 936 if (!hasEquivalentTransitions(*vtz_new, *tz, trans.getTime() + maxDelta, 937 endTime, TRUE, maxDelta, status)) { 938 errln("FAIL: VTimeZone for " + *tzid + 939 " is not equivalent to its OlsonTimeZone corresponding."); 940 } else { 941 logln("VTimeZone for " + *tzid + 942 " differs from its OlsonTimeZone corresponding with maximum transition time delta - " + maxDelta); 943 } 944 945 } 946 if (U_FAILURE(status)) { 947 errln("FAIL: error status is returned from hasEquivalentTransition"); 948 } 949 } 950 } 951 } 952 } 953 if (vtz_new != NULL) { 954 delete vtz_new; 955 vtz_new = NULL; 956 } 957 } 958 delete tz; 959 delete vtz_org; 960 } 961 } 962 963 /* 964 * Write out simple time zone rules from an OlsonTimeZone at various time into VTIMEZONE 965 * format and create a new VTimeZone from the VTIMEZONE data, then make sure the raw offset 966 * and DST savings are same in these two time zones. 967 */ 968 void 969 TimeZoneRuleTest::TestVTimeZoneSimpleWrite(void) { 970 const int32_t TESTDATES[][3] = { 971 {2006, UCAL_JANUARY, 1}, 972 {2006, UCAL_MARCH, 15}, 973 {2006, UCAL_MARCH, 31}, 974 {2006, UCAL_OCTOBER, 25}, 975 {2006, UCAL_NOVEMBER, 1}, 976 {2006, UCAL_NOVEMBER, 5}, 977 {2007, UCAL_JANUARY, 1}, 978 {0, 0, 0} 979 }; 980 981 UErrorCode status = U_ZERO_ERROR; 982 TestZIDEnumeration tzenum(!quick); 983 while (TRUE) { 984 const UnicodeString *tzid = tzenum.snext(status); 985 if (tzid == NULL) { 986 break; 987 } 988 if (U_FAILURE(status)) { 989 errln("FAIL: error returned while enumerating timezone IDs."); 990 break; 991 } 992 VTimeZone *vtz_org = VTimeZone::createVTimeZoneByID(*tzid); 993 VTimeZone *vtz_new = NULL; 994 UnicodeString vtzdata; 995 996 for (int32_t i = 0; TESTDATES[i][0] != 0; i++) { 997 // Write out VTIMEZONE 998 UDate time = getUTCMillis(TESTDATES[i][0], TESTDATES[i][1], TESTDATES[i][2]); 999 vtz_org->writeSimple(time, vtzdata, status); 1000 if (U_FAILURE(status)) { 1001 errln((UnicodeString)"FAIL: error returned while writing simple time zone rules for " + 1002 *tzid + " into VTIMEZONE format at " + dateToString(time)); 1003 } else { 1004 // Read VTIMEZONE data 1005 vtz_new = VTimeZone::createVTimeZone(vtzdata, status); 1006 if (U_FAILURE(status)) { 1007 errln((UnicodeString)"FAIL: error returned while reading simple VTIMEZONE data for " + *tzid 1008 + " at " + dateToString(time)); 1009 } else { 1010 // Check equivalency 1011 int32_t raw0, dst0; 1012 int32_t raw1, dst1; 1013 vtz_org->getOffset(time, FALSE, raw0, dst0, status); 1014 vtz_new->getOffset(time, FALSE, raw1, dst1, status); 1015 if (U_SUCCESS(status)) { 1016 if (raw0 != raw1 || dst0 != dst1) { 1017 errln("FAIL: VTimeZone writeSimple for " + *tzid + " at " 1018 + dateToString(time) + " failed to the round trip."); 1019 } 1020 } else { 1021 errln("FAIL: getOffset returns error status"); 1022 } 1023 } 1024 } 1025 if (vtz_new != NULL) { 1026 delete vtz_new; 1027 vtz_new = NULL; 1028 } 1029 } 1030 delete vtz_org; 1031 } 1032 } 1033 1034 /* 1035 * Write out time zone rules of OlsonTimeZone into VTIMEZONE format with RFC2445 header TZURL and 1036 * LAST-MODIFIED, create a new VTimeZone from the VTIMEZONE data to see if the headers are preserved. 1037 */ 1038 void 1039 TimeZoneRuleTest::TestVTimeZoneHeaderProps(void) { 1040 const UnicodeString TESTURL1("http://source.icu-project.org"); 1041 const UnicodeString TESTURL2("http://www.ibm.com"); 1042 1043 UErrorCode status = U_ZERO_ERROR; 1044 UnicodeString tzurl; 1045 UDate lmod; 1046 UDate lastmod = getUTCMillis(2007, UCAL_JUNE, 1); 1047 VTimeZone *vtz = VTimeZone::createVTimeZoneByID("America/Chicago"); 1048 vtz->setTZURL(TESTURL1); 1049 vtz->setLastModified(lastmod); 1050 1051 // Roundtrip conversion 1052 UnicodeString vtzdata; 1053 vtz->write(vtzdata, status); 1054 VTimeZone *newvtz1 = NULL; 1055 if (U_FAILURE(status)) { 1056 errln("FAIL: error returned while writing VTIMEZONE data 1"); 1057 return; 1058 } 1059 // Create a new one 1060 newvtz1 = VTimeZone::createVTimeZone(vtzdata, status); 1061 if (U_FAILURE(status)) { 1062 errln("FAIL: error returned while loading VTIMEZONE data 1"); 1063 } else { 1064 // Check if TZURL and LAST-MODIFIED properties are preserved 1065 newvtz1->getTZURL(tzurl); 1066 if (tzurl != TESTURL1) { 1067 errln("FAIL: TZURL 1 was not preserved"); 1068 } 1069 vtz->getLastModified(lmod); 1070 if (lastmod != lmod) { 1071 errln("FAIL: LAST-MODIFIED was not preserved"); 1072 } 1073 } 1074 1075 if (U_SUCCESS(status)) { 1076 // Set different tzurl 1077 newvtz1->setTZURL(TESTURL2); 1078 1079 // Second roundtrip, with a cutover 1080 newvtz1->write(vtzdata, status); 1081 if (U_FAILURE(status)) { 1082 errln("FAIL: error returned while writing VTIMEZONE data 2"); 1083 } else { 1084 VTimeZone *newvtz2 = VTimeZone::createVTimeZone(vtzdata, status); 1085 if (U_FAILURE(status)) { 1086 errln("FAIL: error returned while loading VTIMEZONE data 2"); 1087 } else { 1088 // Check if TZURL and LAST-MODIFIED properties are preserved 1089 newvtz2->getTZURL(tzurl); 1090 if (tzurl != TESTURL2) { 1091 errln("FAIL: TZURL was not preserved in the second roundtrip"); 1092 } 1093 vtz->getLastModified(lmod); 1094 if (lastmod != lmod) { 1095 errln("FAIL: LAST-MODIFIED was not preserved in the second roundtrip"); 1096 } 1097 } 1098 delete newvtz2; 1099 } 1100 } 1101 delete newvtz1; 1102 delete vtz; 1103 } 1104 1105 /* 1106 * Extract simple rules from an OlsonTimeZone and make sure the rule format matches 1107 * the expected format. 1108 */ 1109 void 1110 TimeZoneRuleTest::TestGetSimpleRules(void) { 1111 UDate testTimes[] = { 1112 getUTCMillis(1970, UCAL_JANUARY, 1), 1113 getUTCMillis(2000, UCAL_MARCH, 31), 1114 getUTCMillis(2005, UCAL_JULY, 1), 1115 getUTCMillis(2010, UCAL_NOVEMBER, 1), 1116 }; 1117 int32_t numTimes = UPRV_LENGTHOF(testTimes); 1118 UErrorCode status = U_ZERO_ERROR; 1119 TestZIDEnumeration tzenum(!quick); 1120 InitialTimeZoneRule *initial; 1121 AnnualTimeZoneRule *std, *dst; 1122 for (int32_t i = 0; i < numTimes ; i++) { 1123 while (TRUE) { 1124 const UnicodeString *tzid = tzenum.snext(status); 1125 if (tzid == NULL) { 1126 break; 1127 } 1128 if (U_FAILURE(status)) { 1129 errln("FAIL: error returned while enumerating timezone IDs."); 1130 break; 1131 } 1132 BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid); 1133 initial = NULL; 1134 std = dst = NULL; 1135 tz->getSimpleRulesNear(testTimes[i], initial, std, dst, status); 1136 if (U_FAILURE(status)) { 1137 errln("FAIL: getSimpleRules failed."); 1138 break; 1139 } 1140 if (initial == NULL) { 1141 errln("FAIL: initial rule must not be NULL"); 1142 break; 1143 } else if (!((std == NULL && dst == NULL) || (std != NULL && dst != NULL))) { 1144 errln("FAIL: invalid std/dst pair."); 1145 break; 1146 } 1147 if (std != NULL) { 1148 const DateTimeRule *dtr = std->getRule(); 1149 if (dtr->getDateRuleType() != DateTimeRule::DOW) { 1150 errln("FAIL: simple std rull must use DateTimeRule::DOW as date rule."); 1151 break; 1152 } 1153 if (dtr->getTimeRuleType() != DateTimeRule::WALL_TIME) { 1154 errln("FAIL: simple std rull must use DateTimeRule::WALL_TIME as time rule."); 1155 break; 1156 } 1157 dtr = dst->getRule(); 1158 if (dtr->getDateRuleType() != DateTimeRule::DOW) { 1159 errln("FAIL: simple dst rull must use DateTimeRule::DOW as date rule."); 1160 break; 1161 } 1162 if (dtr->getTimeRuleType() != DateTimeRule::WALL_TIME) { 1163 errln("FAIL: simple dst rull must use DateTimeRule::WALL_TIME as time rule."); 1164 break; 1165 } 1166 } 1167 // Create an RBTZ from the rules and compare the offsets at the date 1168 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(*tzid, initial); 1169 if (std != NULL) { 1170 rbtz->addTransitionRule(std, status); 1171 if (U_FAILURE(status)) { 1172 errln("FAIL: couldn't add std rule."); 1173 } 1174 rbtz->addTransitionRule(dst, status); 1175 if (U_FAILURE(status)) { 1176 errln("FAIL: couldn't add dst rule."); 1177 } 1178 } 1179 rbtz->complete(status); 1180 if (U_FAILURE(status)) { 1181 errln("FAIL: couldn't complete rbtz for " + *tzid); 1182 } 1183 1184 int32_t raw0, dst0, raw1, dst1; 1185 tz->getOffset(testTimes[i], FALSE, raw0, dst0, status); 1186 if (U_FAILURE(status)) { 1187 errln("FAIL: couldn't get offsets from tz for " + *tzid); 1188 } 1189 rbtz->getOffset(testTimes[i], FALSE, raw1, dst1, status); 1190 if (U_FAILURE(status)) { 1191 errln("FAIL: couldn't get offsets from rbtz for " + *tzid); 1192 } 1193 if (raw0 != raw1 || dst0 != dst1) { 1194 errln("FAIL: rbtz created by simple rule does not match the original tz for tzid " + *tzid); 1195 } 1196 delete rbtz; 1197 delete tz; 1198 } 1199 } 1200 } 1201 1202 /* 1203 * API coverage tests for TimeZoneRule 1204 */ 1205 void 1206 TimeZoneRuleTest::TestTimeZoneRuleCoverage(void) { 1207 UDate time1 = getUTCMillis(2005, UCAL_JULY, 4); 1208 UDate time2 = getUTCMillis(2015, UCAL_JULY, 4); 1209 UDate time3 = getUTCMillis(1950, UCAL_JULY, 4); 1210 1211 DateTimeRule *dtr1 = new DateTimeRule(UCAL_FEBRUARY, 29, UCAL_SUNDAY, FALSE, 1212 3*HOUR, DateTimeRule::WALL_TIME); // Last Sunday on or before Feb 29, at 3 AM, wall time 1213 DateTimeRule *dtr2 = new DateTimeRule(UCAL_MARCH, 11, 2*HOUR, 1214 DateTimeRule::STANDARD_TIME); // Mar 11, at 2 AM, standard time 1215 DateTimeRule *dtr3 = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SATURDAY, 1216 6*HOUR, DateTimeRule::UTC_TIME); //Last Saturday in Oct, at 6 AM, UTC 1217 DateTimeRule *dtr4 = new DateTimeRule(UCAL_MARCH, 8, UCAL_SUNDAY, TRUE, 1218 2*HOUR, DateTimeRule::WALL_TIME); // First Sunday on or after Mar 8, at 2 AM, wall time 1219 1220 AnnualTimeZoneRule *a1 = new AnnualTimeZoneRule("a1", -3*HOUR, 1*HOUR, *dtr1, 1221 2000, AnnualTimeZoneRule::MAX_YEAR); 1222 AnnualTimeZoneRule *a2 = new AnnualTimeZoneRule("a2", -3*HOUR, 1*HOUR, *dtr1, 1223 2000, AnnualTimeZoneRule::MAX_YEAR); 1224 AnnualTimeZoneRule *a3 = new AnnualTimeZoneRule("a3", -3*HOUR, 1*HOUR, *dtr1, 1225 2000, 2010); 1226 1227 InitialTimeZoneRule *i1 = new InitialTimeZoneRule("i1", -3*HOUR, 0); 1228 InitialTimeZoneRule *i2 = new InitialTimeZoneRule("i2", -3*HOUR, 0); 1229 InitialTimeZoneRule *i3 = new InitialTimeZoneRule("i3", -3*HOUR, 1*HOUR); 1230 1231 UDate trtimes1[] = {0.0}; 1232 UDate trtimes2[] = {0.0, 10000000.0}; 1233 1234 TimeArrayTimeZoneRule *t1 = new TimeArrayTimeZoneRule("t1", -3*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME); 1235 TimeArrayTimeZoneRule *t2 = new TimeArrayTimeZoneRule("t2", -3*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME); 1236 TimeArrayTimeZoneRule *t3 = new TimeArrayTimeZoneRule("t3", -3*HOUR, 0, trtimes2, 2, DateTimeRule::UTC_TIME); 1237 TimeArrayTimeZoneRule *t4 = new TimeArrayTimeZoneRule("t4", -3*HOUR, 0, trtimes1, 1, DateTimeRule::STANDARD_TIME); 1238 TimeArrayTimeZoneRule *t5 = new TimeArrayTimeZoneRule("t5", -4*HOUR, 1*HOUR, trtimes1, 1, DateTimeRule::WALL_TIME); 1239 1240 // DateTimeRule::operator=/clone 1241 DateTimeRule dtr0(UCAL_MAY, 31, 2*HOUR, DateTimeRule::WALL_TIME); 1242 if (dtr0 == *dtr1 || !(dtr0 != *dtr1)) { 1243 errln("FAIL: DateTimeRule dtr0 is not equal to dtr1, but got wrong result"); 1244 } 1245 dtr0 = *dtr1; 1246 if (dtr0 != *dtr1 || !(dtr0 == *dtr1)) { 1247 errln("FAIL: DateTimeRule dtr0 is equal to dtr1, but got wrong result"); 1248 } 1249 DateTimeRule *dtr0c = dtr0.clone(); 1250 if (*dtr0c != *dtr1 || !(*dtr0c == *dtr1)) { 1251 errln("FAIL: DateTimeRule dtr0c is equal to dtr1, but got wrong result"); 1252 } 1253 delete dtr0c; 1254 1255 // AnnualTimeZonerule::operator=/clone 1256 AnnualTimeZoneRule a0("a0", 5*HOUR, 1*HOUR, *dtr1, 1990, AnnualTimeZoneRule::MAX_YEAR); 1257 if (a0 == *a1 || !(a0 != *a1)) { 1258 errln("FAIL: AnnualTimeZoneRule a0 is not equal to a1, but got wrong result"); 1259 } 1260 a0 = *a1; 1261 if (a0 != *a1 || !(a0 == *a1)) { 1262 errln("FAIL: AnnualTimeZoneRule a0 is equal to a1, but got wrong result"); 1263 } 1264 AnnualTimeZoneRule *a0c = a0.clone(); 1265 if (*a0c != *a1 || !(*a0c == *a1)) { 1266 errln("FAIL: AnnualTimeZoneRule a0c is equal to a1, but got wrong result"); 1267 } 1268 delete a0c; 1269 1270 // AnnualTimeZoneRule::getRule 1271 if (*(a1->getRule()) != *(a2->getRule())) { 1272 errln("FAIL: The same DateTimeRule must be returned from AnnualTimeZoneRule a1 and a2"); 1273 } 1274 1275 // AnnualTimeZoneRule::getStartYear 1276 int32_t startYear = a1->getStartYear(); 1277 if (startYear != 2000) { 1278 errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a1 must be 2000 - returned: " + startYear); 1279 } 1280 1281 // AnnualTimeZoneRule::getEndYear 1282 int32_t endYear = a1->getEndYear(); 1283 if (endYear != AnnualTimeZoneRule::MAX_YEAR) { 1284 errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a1 must be MAX_YEAR - returned: " + endYear); 1285 } 1286 endYear = a3->getEndYear(); 1287 if (endYear != 2010) { 1288 errln((UnicodeString)"FAIL: The start year of AnnualTimeZoneRule a3 must be 2010 - returned: " + endYear); 1289 } 1290 1291 // AnnualTimeZone::getStartInYear 1292 UBool b1, b2; 1293 UDate d1, d2; 1294 b1 = a1->getStartInYear(2005, -3*HOUR, 0, d1); 1295 b2 = a3->getStartInYear(2005, -3*HOUR, 0, d2); 1296 if (!b1 || !b2 || d1 != d2) { 1297 errln("FAIL: AnnualTimeZoneRule::getStartInYear did not work as expected"); 1298 } 1299 b2 = a3->getStartInYear(2015, -3*HOUR, 0, d2); 1300 if (b2) { 1301 errln("FAIL: AnnualTimeZoneRule::getStartInYear returned TRUE for 2015 which is out of rule range"); 1302 } 1303 1304 // AnnualTimeZone::getFirstStart 1305 b1 = a1->getFirstStart(-3*HOUR, 0, d1); 1306 b2 = a1->getFirstStart(-4*HOUR, 1*HOUR, d2); 1307 if (!b1 || !b2 || d1 != d2) { 1308 errln("FAIL: The same start time should be returned by getFirstStart"); 1309 } 1310 1311 // AnnualTimeZone::getFinalStart 1312 b1 = a1->getFinalStart(-3*HOUR, 0, d1); 1313 if (b1) { 1314 errln("FAIL: getFinalStart returned TRUE for a1"); 1315 } 1316 b1 = a1->getStartInYear(2010, -3*HOUR, 0, d1); 1317 b2 = a3->getFinalStart(-3*HOUR, 0, d2); 1318 if (!b1 || !b2 || d1 != d2) { 1319 errln("FAIL: Bad date is returned by getFinalStart"); 1320 } 1321 1322 // AnnualTimeZone::getNextStart / getPreviousStart 1323 b1 = a1->getNextStart(time1, -3*HOUR, 0, FALSE, d1); 1324 if (!b1) { 1325 errln("FAIL: getNextStart returned FALSE for ai"); 1326 } else { 1327 b2 = a1->getPreviousStart(d1, -3*HOUR, 0, TRUE, d2); 1328 if (!b2 || d1 != d2) { 1329 errln("FAIL: Bad Date is returned by getPreviousStart"); 1330 } 1331 } 1332 b1 = a3->getNextStart(time2, -3*HOUR, 0, FALSE, d1); 1333 if (b1) { 1334 dataerrln("FAIL: getNextStart must return FALSE when no start time is available after the base time"); 1335 } 1336 b1 = a3->getFinalStart(-3*HOUR, 0, d1); 1337 b2 = a3->getPreviousStart(time2, -3*HOUR, 0, FALSE, d2); 1338 if (!b1 || !b2 || d1 != d2) { 1339 dataerrln("FAIL: getPreviousStart does not match with getFinalStart after the end year"); 1340 } 1341 1342 // AnnualTimeZone::isEquavalentTo 1343 if (!a1->isEquivalentTo(*a2)) { 1344 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to a2, but returned FALSE"); 1345 } 1346 if (a1->isEquivalentTo(*a3)) { 1347 errln("FAIL: AnnualTimeZoneRule a1 is not equivalent to a3, but returned TRUE"); 1348 } 1349 if (!a1->isEquivalentTo(*a1)) { 1350 errln("FAIL: AnnualTimeZoneRule a1 is equivalent to itself, but returned FALSE"); 1351 } 1352 if (a1->isEquivalentTo(*t1)) { 1353 errln("FAIL: AnnualTimeZoneRule is not equivalent to TimeArrayTimeZoneRule, but returned TRUE"); 1354 } 1355 1356 // InitialTimezoneRule::operator=/clone 1357 InitialTimeZoneRule i0("i0", 10*HOUR, 0); 1358 if (i0 == *i1 || !(i0 != *i1)) { 1359 errln("FAIL: InitialTimeZoneRule i0 is not equal to i1, but got wrong result"); 1360 } 1361 i0 = *i1; 1362 if (i0 != *i1 || !(i0 == *i1)) { 1363 errln("FAIL: InitialTimeZoneRule i0 is equal to i1, but got wrong result"); 1364 } 1365 InitialTimeZoneRule *i0c = i0.clone(); 1366 if (*i0c != *i1 || !(*i0c == *i1)) { 1367 errln("FAIL: InitialTimeZoneRule i0c is equal to i1, but got wrong result"); 1368 } 1369 delete i0c; 1370 1371 // InitialTimeZoneRule::isEquivalentRule 1372 if (!i1->isEquivalentTo(*i2)) { 1373 errln("FAIL: InitialTimeZoneRule i1 is equivalent to i2, but returned FALSE"); 1374 } 1375 if (i1->isEquivalentTo(*i3)) { 1376 errln("FAIL: InitialTimeZoneRule i1 is not equivalent to i3, but returned TRUE"); 1377 } 1378 if (i1->isEquivalentTo(*a1)) { 1379 errln("FAIL: An InitialTimeZoneRule is not equivalent to an AnnualTimeZoneRule, but returned TRUE"); 1380 } 1381 1382 // InitialTimeZoneRule::getFirstStart/getFinalStart/getNextStart/getPreviousStart 1383 b1 = i1->getFirstStart(0, 0, d1); 1384 if (b1) { 1385 errln("FAIL: InitialTimeZone::getFirstStart returned TRUE"); 1386 } 1387 b1 = i1->getFinalStart(0, 0, d1); 1388 if (b1) { 1389 errln("FAIL: InitialTimeZone::getFinalStart returned TRUE"); 1390 } 1391 b1 = i1->getNextStart(time1, 0, 0, FALSE, d1); 1392 if (b1) { 1393 errln("FAIL: InitialTimeZone::getNextStart returned TRUE"); 1394 } 1395 b1 = i1->getPreviousStart(time1, 0, 0, FALSE, d1); 1396 if (b1) { 1397 errln("FAIL: InitialTimeZone::getPreviousStart returned TRUE"); 1398 } 1399 1400 // TimeArrayTimeZoneRule::operator=/clone 1401 TimeArrayTimeZoneRule t0("t0", 4*HOUR, 0, trtimes1, 1, DateTimeRule::UTC_TIME); 1402 if (t0 == *t1 || !(t0 != *t1)) { 1403 errln("FAIL: TimeArrayTimeZoneRule t0 is not equal to t1, but got wrong result"); 1404 } 1405 t0 = *t1; 1406 if (t0 != *t1 || !(t0 == *t1)) { 1407 errln("FAIL: TimeArrayTimeZoneRule t0 is equal to t1, but got wrong result"); 1408 } 1409 TimeArrayTimeZoneRule *t0c = t0.clone(); 1410 if (*t0c != *t1 || !(*t0c == *t1)) { 1411 errln("FAIL: TimeArrayTimeZoneRule t0c is equal to t1, but got wrong result"); 1412 } 1413 delete t0c; 1414 1415 // TimeArrayTimeZoneRule::countStartTimes 1416 if (t1->countStartTimes() != 1) { 1417 errln("FAIL: Bad start time count is returned by TimeArrayTimeZoneRule::countStartTimes"); 1418 } 1419 1420 // TimeArrayTimeZoneRule::getStartTimeAt 1421 b1 = t1->getStartTimeAt(-1, d1); 1422 if (b1) { 1423 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index -1"); 1424 } 1425 b1 = t1->getStartTimeAt(0, d1); 1426 if (!b1 || d1 != trtimes1[0]) { 1427 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned incorrect result for index 0"); 1428 } 1429 b1 = t1->getStartTimeAt(1, d1); 1430 if (b1) { 1431 errln("FAIL: TimeArrayTimeZoneRule::getStartTimeAt returned TRUE for index 1"); 1432 } 1433 1434 // TimeArrayTimeZoneRule::getTimeType 1435 if (t1->getTimeType() != DateTimeRule::UTC_TIME) { 1436 errln("FAIL: TimeArrayTimeZoneRule t1 uses UTC_TIME, but different type is returned"); 1437 } 1438 if (t4->getTimeType() != DateTimeRule::STANDARD_TIME) { 1439 errln("FAIL: TimeArrayTimeZoneRule t4 uses STANDARD_TIME, but different type is returned"); 1440 } 1441 if (t5->getTimeType() != DateTimeRule::WALL_TIME) { 1442 errln("FAIL: TimeArrayTimeZoneRule t5 uses WALL_TIME, but different type is returned"); 1443 } 1444 1445 // TimeArrayTimeZoneRule::getFirstStart/getFinalStart 1446 b1 = t1->getFirstStart(0, 0, d1); 1447 if (!b1 || d1 != trtimes1[0]) { 1448 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t1"); 1449 } 1450 b1 = t1->getFinalStart(0, 0, d1); 1451 if (!b1 || d1 != trtimes1[0]) { 1452 errln("FAIL: Bad final start time returned from TimeArrayTimeZoneRule t1"); 1453 } 1454 b1 = t4->getFirstStart(-4*HOUR, 1*HOUR, d1); 1455 if (!b1 || d1 != (trtimes1[0] + 4*HOUR)) { 1456 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t4"); 1457 } 1458 b1 = t5->getFirstStart(-4*HOUR, 1*HOUR, d1); 1459 if (!b1 || d1 != (trtimes1[0] + 3*HOUR)) { 1460 errln("FAIL: Bad first start time returned from TimeArrayTimeZoneRule t5"); 1461 } 1462 1463 // TimeArrayTimeZoneRule::getNextStart/getPreviousStart 1464 b1 = t3->getNextStart(time1, -3*HOUR, 1*HOUR, FALSE, d1); 1465 if (b1) { 1466 dataerrln("FAIL: getNextStart returned TRUE after the final transition for t3"); 1467 } 1468 b1 = t3->getPreviousStart(time1, -3*HOUR, 1*HOUR, FALSE, d1); 1469 if (!b1 || d1 != trtimes2[1]) { 1470 dataerrln("FAIL: Bad start time returned by getPreviousStart for t3"); 1471 } else { 1472 b2 = t3->getPreviousStart(d1, -3*HOUR, 1*HOUR, FALSE, d2); 1473 if (!b2 || d2 != trtimes2[0]) { 1474 errln("FAIL: Bad start time returned by getPreviousStart for t3"); 1475 } 1476 } 1477 b1 = t3->getPreviousStart(time3, -3*HOUR, 1*HOUR, FALSE, d1); //time3 - year 1950, no result expected 1478 if (b1) { 1479 errln("FAIL: getPreviousStart returned TRUE before the first transition for t3"); 1480 } 1481 1482 // TimeArrayTimeZoneRule::isEquivalentTo 1483 if (!t1->isEquivalentTo(*t2)) { 1484 errln("FAIL: TimeArrayTimeZoneRule t1 is equivalent to t2, but returned FALSE"); 1485 } 1486 if (t1->isEquivalentTo(*t3)) { 1487 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t3, but returned TRUE"); 1488 } 1489 if (t1->isEquivalentTo(*t4)) { 1490 errln("FAIL: TimeArrayTimeZoneRule t1 is not equivalent to t4, but returned TRUE"); 1491 } 1492 if (t1->isEquivalentTo(*a1)) { 1493 errln("FAIL: TimeArrayTimeZoneRule is not equivalent to AnnualTimeZoneRule, but returned TRUE"); 1494 } 1495 1496 delete dtr1; 1497 delete dtr2; 1498 delete dtr3; 1499 delete dtr4; 1500 delete a1; 1501 delete a2; 1502 delete a3; 1503 delete i1; 1504 delete i2; 1505 delete i3; 1506 delete t1; 1507 delete t2; 1508 delete t3; 1509 delete t4; 1510 delete t5; 1511 } 1512 1513 /* 1514 * API coverage test for BasicTimeZone APIs in SimpleTimeZone 1515 */ 1516 void 1517 TimeZoneRuleTest::TestSimpleTimeZoneCoverage(void) { 1518 UDate time1 = getUTCMillis(1990, UCAL_JUNE, 1); 1519 UDate time2 = getUTCMillis(2000, UCAL_JUNE, 1); 1520 1521 TimeZoneTransition tzt1, tzt2; 1522 UBool avail1, avail2; 1523 UErrorCode status = U_ZERO_ERROR; 1524 const TimeZoneRule *trrules[2]; 1525 const InitialTimeZoneRule *ir = NULL; 1526 int32_t numTzRules; 1527 1528 // BasicTimeZone API implementation in SimpleTimeZone 1529 SimpleTimeZone *stz1 = new SimpleTimeZone(-5*HOUR, "GMT-5"); 1530 1531 avail1 = stz1->getNextTransition(time1, FALSE, tzt1); 1532 if (avail1) { 1533 errln("FAIL: No transition must be returned by getNextTranstion for SimpleTimeZone with no DST rule"); 1534 } 1535 avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1); 1536 if (avail1) { 1537 errln("FAIL: No transition must be returned by getPreviousTransition for SimpleTimeZone with no DST rule"); 1538 } 1539 1540 numTzRules = stz1->countTransitionRules(status); 1541 if (U_FAILURE(status)) { 1542 errln("FAIL: countTransitionRules failed"); 1543 } 1544 if (numTzRules != 0) { 1545 errln((UnicodeString)"FAIL: countTransitionRules returned " + numTzRules); 1546 } 1547 numTzRules = 2; 1548 stz1->getTimeZoneRules(ir, trrules, numTzRules, status); 1549 if (U_FAILURE(status)) { 1550 errln("FAIL: getTimeZoneRules failed"); 1551 } 1552 if (numTzRules != 0) { 1553 errln("FAIL: Incorrect transition rule count"); 1554 } 1555 if (ir == NULL || ir->getRawOffset() != stz1->getRawOffset()) { 1556 errln("FAIL: Bad initial time zone rule"); 1557 } 1558 1559 // Set DST rule 1560 stz1->setStartRule(UCAL_MARCH, 11, 2*HOUR, status); // March 11 1561 stz1->setEndRule(UCAL_NOVEMBER, 1, UCAL_SUNDAY, 2*HOUR, status); // First Sunday in November 1562 if (U_FAILURE(status)) { 1563 errln("FAIL: Failed to set DST rules in a SimpleTimeZone"); 1564 } 1565 1566 avail1 = stz1->getNextTransition(time1, FALSE, tzt1); 1567 if (!avail1) { 1568 errln("FAIL: Non-null transition must be returned by getNextTranstion for SimpleTimeZone with a DST rule"); 1569 } 1570 avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1); 1571 if (!avail1) { 1572 errln("FAIL: Non-null transition must be returned by getPreviousTransition for SimpleTimeZone with a DST rule"); 1573 } 1574 1575 numTzRules = stz1->countTransitionRules(status); 1576 if (U_FAILURE(status)) { 1577 errln("FAIL: countTransitionRules failed"); 1578 } 1579 if (numTzRules != 2) { 1580 errln((UnicodeString)"FAIL: countTransitionRules returned " + numTzRules); 1581 } 1582 1583 numTzRules = 2; 1584 trrules[0] = NULL; 1585 trrules[1] = NULL; 1586 stz1->getTimeZoneRules(ir, trrules, numTzRules, status); 1587 if (U_FAILURE(status)) { 1588 errln("FAIL: getTimeZoneRules failed"); 1589 } 1590 if (numTzRules != 2) { 1591 errln("FAIL: Incorrect transition rule count"); 1592 } 1593 if (ir == NULL || ir->getRawOffset() != stz1->getRawOffset()) { 1594 errln("FAIL: Bad initial time zone rule"); 1595 } 1596 if (trrules[0] == NULL || trrules[0]->getRawOffset() != stz1->getRawOffset()) { 1597 errln("FAIL: Bad transition rule 0"); 1598 } 1599 if (trrules[1] == NULL || trrules[1]->getRawOffset() != stz1->getRawOffset()) { 1600 errln("FAIL: Bad transition rule 1"); 1601 } 1602 1603 // Set DST start year 1604 stz1->setStartYear(2007); 1605 avail1 = stz1->getPreviousTransition(time1, FALSE, tzt1); 1606 if (avail1) { 1607 errln("FAIL: No transition must be returned before 1990"); 1608 } 1609 avail1 = stz1->getNextTransition(time1, FALSE, tzt1); // transition after 1990-06-01 1610 avail2 = stz1->getNextTransition(time2, FALSE, tzt2); // transition after 2000-06-01 1611 if (!avail1 || !avail2 || tzt1 != tzt2) { 1612 errln("FAIL: Bad transition returned by SimpleTimeZone::getNextTransition"); 1613 } 1614 delete stz1; 1615 } 1616 1617 /* 1618 * API coverage test for VTimeZone 1619 */ 1620 void 1621 TimeZoneRuleTest::TestVTimeZoneCoverage(void) { 1622 UErrorCode status = U_ZERO_ERROR; 1623 UnicodeString TZID("Europe/Moscow"); 1624 1625 BasicTimeZone *otz = (BasicTimeZone*)TimeZone::createTimeZone(TZID); 1626 VTimeZone *vtz = VTimeZone::createVTimeZoneByID(TZID); 1627 1628 // getOffset(era, year, month, day, dayOfWeek, milliseconds, ec) 1629 int32_t offset1 = otz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, status); 1630 if (U_FAILURE(status)) { 1631 errln("FAIL: getOffset(7 args) failed for otz"); 1632 } 1633 int32_t offset2 = vtz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, status); 1634 if (U_FAILURE(status)) { 1635 errln("FAIL: getOffset(7 args) failed for vtz"); 1636 } 1637 if (offset1 != offset2) { 1638 errln("FAIL: getOffset(7 args) returned different results in VTimeZone and OlsonTimeZone"); 1639 } 1640 1641 // getOffset(era, year, month, day, dayOfWeek, milliseconds, monthLength, ec) 1642 offset1 = otz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, 31, status); 1643 if (U_FAILURE(status)) { 1644 errln("FAIL: getOffset(8 args) failed for otz"); 1645 } 1646 offset2 = vtz->getOffset(GregorianCalendar::AD, 2007, UCAL_JULY, 1, UCAL_SUNDAY, 0, 31, status); 1647 if (U_FAILURE(status)) { 1648 errln("FAIL: getOffset(8 args) failed for vtz"); 1649 } 1650 if (offset1 != offset2) { 1651 errln("FAIL: getOffset(8 args) returned different results in VTimeZone and OlsonTimeZone"); 1652 } 1653 1654 1655 // getOffset(date, local, rawOffset, dstOffset, ec) 1656 UDate t = Calendar::getNow(); 1657 int32_t rawOffset1, dstSavings1; 1658 int32_t rawOffset2, dstSavings2; 1659 1660 otz->getOffset(t, FALSE, rawOffset1, dstSavings1, status); 1661 if (U_FAILURE(status)) { 1662 errln("FAIL: getOffset(5 args) failed for otz"); 1663 } 1664 vtz->getOffset(t, FALSE, rawOffset2, dstSavings2, status); 1665 if (U_FAILURE(status)) { 1666 errln("FAIL: getOffset(5 args) failed for vtz"); 1667 } 1668 if (rawOffset1 != rawOffset2 || dstSavings1 != dstSavings2) { 1669 errln("FAIL: getOffset(long,boolean,int[]) returned different results in VTimeZone and OlsonTimeZone"); 1670 } 1671 1672 // getRawOffset 1673 if (otz->getRawOffset() != vtz->getRawOffset()) { 1674 errln("FAIL: getRawOffset returned different results in VTimeZone and OlsonTimeZone"); 1675 } 1676 1677 // inDaylightTime 1678 UBool inDst1, inDst2; 1679 inDst1 = otz->inDaylightTime(t, status); 1680 if (U_FAILURE(status)) { 1681 dataerrln("FAIL: inDaylightTime failed for otz: %s", u_errorName(status)); 1682 } 1683 inDst2 = vtz->inDaylightTime(t, status); 1684 if (U_FAILURE(status)) { 1685 dataerrln("FAIL: inDaylightTime failed for vtz: %s", u_errorName(status)); 1686 } 1687 if (inDst1 != inDst2) { 1688 errln("FAIL: inDaylightTime returned different results in VTimeZone and OlsonTimeZone"); 1689 } 1690 1691 // useDaylightTime 1692 if (otz->useDaylightTime() != vtz->useDaylightTime()) { 1693 errln("FAIL: useDaylightTime returned different results in VTimeZone and OlsonTimeZone"); 1694 } 1695 1696 // setRawOffset 1697 const int32_t RAW = -10*HOUR; 1698 VTimeZone *tmpvtz = (VTimeZone*)vtz->clone(); 1699 tmpvtz->setRawOffset(RAW); 1700 if (tmpvtz->getRawOffset() != RAW) { 1701 logln("setRawOffset is implemented in VTimeZone"); 1702 } 1703 1704 // hasSameRules 1705 UBool bSame = otz->hasSameRules(*vtz); 1706 logln((UnicodeString)"OlsonTimeZone::hasSameRules(VTimeZone) should return FALSE always for now - actual: " + bSame); 1707 1708 // getTZURL/setTZURL 1709 UnicodeString TZURL("http://icu-project.org/timezone"); 1710 UnicodeString url; 1711 if (vtz->getTZURL(url)) { 1712 errln("FAIL: getTZURL returned TRUE"); 1713 } 1714 vtz->setTZURL(TZURL); 1715 if (!vtz->getTZURL(url) || url != TZURL) { 1716 errln("FAIL: URL returned by getTZURL does not match the one set by setTZURL"); 1717 } 1718 1719 // getLastModified/setLastModified 1720 UDate lastmod; 1721 if (vtz->getLastModified(lastmod)) { 1722 errln("FAIL: getLastModified returned TRUE"); 1723 } 1724 vtz->setLastModified(t); 1725 if (!vtz->getLastModified(lastmod) || lastmod != t) { 1726 errln("FAIL: Date returned by getLastModified does not match the one set by setLastModified"); 1727 } 1728 1729 // getNextTransition/getPreviousTransition 1730 UDate base = getUTCMillis(2007, UCAL_JULY, 1); 1731 TimeZoneTransition tzt1, tzt2; 1732 UBool btr1 = otz->getNextTransition(base, TRUE, tzt1); 1733 UBool btr2 = vtz->getNextTransition(base, TRUE, tzt2); 1734 if (!btr1 || !btr2 || tzt1 != tzt2) { 1735 dataerrln("FAIL: getNextTransition returned different results in VTimeZone and OlsonTimeZone"); 1736 } 1737 btr1 = otz->getPreviousTransition(base, FALSE, tzt1); 1738 btr2 = vtz->getPreviousTransition(base, FALSE, tzt2); 1739 if (!btr1 || !btr2 || tzt1 != tzt2) { 1740 dataerrln("FAIL: getPreviousTransition returned different results in VTimeZone and OlsonTimeZone"); 1741 } 1742 1743 // TimeZoneTransition constructor/clone 1744 TimeZoneTransition *tzt1c = tzt1.clone(); 1745 if (*tzt1c != tzt1 || !(*tzt1c == tzt1)) { 1746 errln("FAIL: TimeZoneTransition tzt1c is equal to tzt1, but got wrong result"); 1747 } 1748 delete tzt1c; 1749 TimeZoneTransition tzt3(tzt1); 1750 if (tzt3 != tzt1 || !(tzt3 == tzt1)) { 1751 errln("FAIL: TimeZoneTransition tzt3 is equal to tzt1, but got wrong result"); 1752 } 1753 1754 // hasEquivalentTransitions 1755 UDate time1 = getUTCMillis(1950, UCAL_JANUARY, 1); 1756 UDate time2 = getUTCMillis(2020, UCAL_JANUARY, 1); 1757 UBool equiv = vtz->hasEquivalentTransitions(*otz, time1, time2, FALSE, status); 1758 if (U_FAILURE(status)) { 1759 dataerrln("FAIL: hasEquivalentTransitions failed for vtz/otz: %s", u_errorName(status)); 1760 } 1761 if (!equiv) { 1762 dataerrln("FAIL: hasEquivalentTransitons returned false for the same time zone"); 1763 } 1764 1765 // operator=/operator==/operator!= 1766 VTimeZone *vtz1 = VTimeZone::createVTimeZoneByID("America/Los_Angeles"); 1767 if (*vtz1 == *vtz || !(*vtz1 != *vtz)) { 1768 errln("FAIL: VTimeZone vtz1 is not equal to vtz, but got wrong result"); 1769 } 1770 *vtz1 = *vtz; 1771 if (*vtz1 != *vtz || !(*vtz1 == *vtz)) { 1772 errln("FAIL: VTimeZone vtz1 is equal to vtz, but got wrong result"); 1773 } 1774 1775 // Creation from BasicTimeZone 1776 // 1777 status = U_ZERO_ERROR; 1778 VTimeZone *vtzFromBasic = NULL; 1779 SimpleTimeZone *simpleTZ = new SimpleTimeZone(28800000, "Asia/Singapore"); 1780 simpleTZ->setStartYear(1970); 1781 simpleTZ->setStartRule(0, // month 1782 1, // day of week 1783 0, // time 1784 status); 1785 simpleTZ->setEndRule(1, 1, 0, status); 1786 if (U_FAILURE(status)) { 1787 errln("File %s, line %d, failed with status = %s", __FILE__, __LINE__, u_errorName(status)); 1788 goto end_basic_tz_test; 1789 } 1790 vtzFromBasic = VTimeZone::createVTimeZoneFromBasicTimeZone(*simpleTZ, status); 1791 if (U_FAILURE(status) || vtzFromBasic == NULL) { 1792 dataerrln("File %s, line %d, failed with status = %s", __FILE__, __LINE__, u_errorName(status)); 1793 goto end_basic_tz_test; 1794 } 1795 1796 // delete the source time zone, to make sure there are no dependencies on it. 1797 delete simpleTZ; 1798 1799 // Create another simple time zone w the same rules, and check that it is the 1800 // same as the test VTimeZone created above. 1801 { 1802 SimpleTimeZone simpleTZ2(28800000, "Asia/Singapore"); 1803 simpleTZ2.setStartYear(1970); 1804 simpleTZ2.setStartRule(0, // month 1805 1, // day of week 1806 0, // time 1807 status); 1808 simpleTZ2.setEndRule(1, 1, 0, status); 1809 if (U_FAILURE(status)) { 1810 errln("File %s, line %d, failed with status = %s", __FILE__, __LINE__, u_errorName(status)); 1811 goto end_basic_tz_test; 1812 } 1813 if (vtzFromBasic->hasSameRules(simpleTZ2) == FALSE) { 1814 errln("File %s, line %d, failed hasSameRules() ", __FILE__, __LINE__); 1815 goto end_basic_tz_test; 1816 } 1817 } 1818 end_basic_tz_test: 1819 delete vtzFromBasic; 1820 1821 delete otz; 1822 delete vtz; 1823 delete tmpvtz; 1824 delete vtz1; 1825 } 1826 1827 1828 void 1829 TimeZoneRuleTest::TestVTimeZoneParse(void) { 1830 UErrorCode status = U_ZERO_ERROR; 1831 1832 // Trying to create VTimeZone from empty data 1833 UnicodeString emptyData; 1834 VTimeZone *empty = VTimeZone::createVTimeZone(emptyData, status); 1835 if (U_SUCCESS(status) || empty != NULL) { 1836 delete empty; 1837 errln("FAIL: Non-null VTimeZone is returned for empty VTIMEZONE data"); 1838 } 1839 status = U_ZERO_ERROR; 1840 1841 // Create VTimeZone for Asia/Tokyo 1842 UnicodeString asiaTokyoID("Asia/Tokyo"); 1843 static const UChar asiaTokyo[] = { 1844 /* "BEGIN:VTIMEZONE\x0D\x0A" */ 1845 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A, 1846 /* "TZID:Asia\x0D\x0A" */ 1847 0x54,0x5A,0x49,0x44,0x3A,0x41,0x73,0x69,0x61,0x0D,0x0A, 1848 /* "\x09/Tokyo\x0D\x0A" */ 1849 0x09,0x2F,0x54,0x6F,0x6B,0x79,0x6F,0x0D,0x0A, 1850 /* "BEGIN:STANDARD\x0D\x0A" */ 1851 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A, 1852 /* "TZOFFSETFROM:+0900\x0D\x0A" */ 1853 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A, 1854 /* "TZOFFSETTO:+0900\x0D\x0A" */ 1855 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2B,0x30,0x39,0x30,0x30,0x0D,0x0A, 1856 /* "TZNAME:JST\x0D\x0A" */ 1857 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x4A,0x53,0x54,0x0D,0x0A, 1858 /* "DTSTART:19700101\x0D\x0A" */ 1859 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x31,0x39,0x37,0x30,0x30,0x31,0x30,0x31,0x0D,0x0A, 1860 /* " T000000\x0D\x0A" */ 1861 0x20,0x54,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A, 1862 /* "END:STANDARD\x0D\x0A" */ 1863 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A, 1864 /* "END:VTIMEZONE" */ 1865 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45, 1866 0 1867 }; 1868 VTimeZone *tokyo = VTimeZone::createVTimeZone(asiaTokyo, status); 1869 if (U_FAILURE(status) || tokyo == NULL) { 1870 errln("FAIL: Failed to create a VTimeZone tokyo"); 1871 } else { 1872 // Check ID 1873 UnicodeString tzid; 1874 tokyo->getID(tzid); 1875 if (tzid != asiaTokyoID) { 1876 errln((UnicodeString)"FAIL: Invalid TZID: " + tzid); 1877 } 1878 // Make sure offsets are correct 1879 int32_t rawOffset, dstSavings; 1880 tokyo->getOffset(Calendar::getNow(), FALSE, rawOffset, dstSavings, status); 1881 if (U_FAILURE(status)) { 1882 errln("FAIL: getOffset failed for tokyo"); 1883 } 1884 if (rawOffset != 9*HOUR || dstSavings != 0) { 1885 errln("FAIL: Bad offsets returned by a VTimeZone created for Tokyo"); 1886 } 1887 } 1888 delete tokyo; 1889 1890 // Create VTimeZone from VTIMEZONE data 1891 static const UChar fooData[] = { 1892 /* "BEGIN:VCALENDAR\x0D\x0A" */ 1893 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52,0x0D,0x0A, 1894 /* "BEGIN:VTIMEZONE\x0D\x0A" */ 1895 0x42,0x45,0x47,0x49,0x4E,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A, 1896 /* "TZID:FOO\x0D\x0A" */ 1897 0x54,0x5A,0x49,0x44,0x3A,0x46,0x4F,0x4F,0x0D,0x0A, 1898 /* "BEGIN:STANDARD\x0D\x0A" */ 1899 0x42,0x45,0x47,0x49,0x4E,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A, 1900 /* "TZOFFSETFROM:-0700\x0D\x0A" */ 1901 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A, 1902 /* "TZOFFSETTO:-0800\x0D\x0A" */ 1903 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A, 1904 /* "TZNAME:FST\x0D\x0A" */ 1905 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x53,0x54,0x0D,0x0A, 1906 /* "DTSTART:20071010T010000\x0D\x0A" */ 1907 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x32,0x30,0x30,0x37,0x31,0x30,0x31,0x30,0x54,0x30,0x31,0x30,0x30,0x30,0x30,0x0D,0x0A, 1908 /* "RRULE:FREQ=YEARLY;BYDAY=WE;BYMONTHDAY=10,11,12,13,14,15,16;BYMONTH=10\x0D\x0A" */ 1909 0x52,0x52,0x55,0x4C,0x45,0x3A,0x46,0x52,0x45,0x51,0x3D,0x59,0x45,0x41,0x52,0x4C,0x59,0x3B,0x42,0x59,0x44,0x41,0x59,0x3D,0x57,0x45,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x44,0x41,0x59,0x3D,0x31,0x30,0x2C,0x31,0x31,0x2C,0x31,0x32,0x2C,0x31,0x33,0x2C,0x31,0x34,0x2C,0x31,0x35,0x2C,0x31,0x36,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x3D,0x31,0x30,0x0D,0x0A, 1910 /* "END:STANDARD\x0D\x0A" */ 1911 0x45,0x4E,0x44,0x3A,0x53,0x54,0x41,0x4E,0x44,0x41,0x52,0x44,0x0D,0x0A, 1912 /* "BEGIN:DAYLIGHT\x0D\x0A" */ 1913 0x42,0x45,0x47,0x49,0x4E,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A, 1914 /* "TZOFFSETFROM:-0800\x0D\x0A" */ 1915 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4F,0x4D,0x3A,0x2D,0x30,0x38,0x30,0x30,0x0D,0x0A, 1916 /* "TZOFFSETTO:-0700\x0D\x0A" */ 1917 0x54,0x5A,0x4F,0x46,0x46,0x53,0x45,0x54,0x54,0x4F,0x3A,0x2D,0x30,0x37,0x30,0x30,0x0D,0x0A, 1918 /* "TZNAME:FDT\x0D\x0A" */ 1919 0x54,0x5A,0x4E,0x41,0x4D,0x45,0x3A,0x46,0x44,0x54,0x0D,0x0A, 1920 /* "DTSTART:20070415T010000\x0D\x0A" */ 1921 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3A,0x32,0x30,0x30,0x37,0x30,0x34,0x31,0x35,0x54,0x30,0x31,0x30,0x30,0x30,0x30,0x0D,0x0A, 1922 /* "RRULE:FREQ=YEARLY;BYMONTHDAY=15;BYMONTH=4\x0D\x0A" */ 1923 0x52,0x52,0x55,0x4C,0x45,0x3A,0x46,0x52,0x45,0x51,0x3D,0x59,0x45,0x41,0x52,0x4C,0x59,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x44,0x41,0x59,0x3D,0x31,0x35,0x3B,0x42,0x59,0x4D,0x4F,0x4E,0x54,0x48,0x3D,0x34,0x0D,0x0A, 1924 /* "END:DAYLIGHT\x0D\x0A" */ 1925 0x45,0x4E,0x44,0x3A,0x44,0x41,0x59,0x4C,0x49,0x47,0x48,0x54,0x0D,0x0A, 1926 /* "END:VTIMEZONE\x0D\x0A" */ 1927 0x45,0x4E,0x44,0x3A,0x56,0x54,0x49,0x4D,0x45,0x5A,0x4F,0x4E,0x45,0x0D,0x0A, 1928 /* "END:VCALENDAR" */ 1929 0x45,0x4E,0x44,0x3A,0x56,0x43,0x41,0x4C,0x45,0x4E,0x44,0x41,0x52, 1930 0 1931 }; 1932 1933 VTimeZone *foo = VTimeZone::createVTimeZone(fooData, status); 1934 if (U_FAILURE(status) || foo == NULL) { 1935 errln("FAIL: Failed to create a VTimeZone foo"); 1936 } else { 1937 // Write VTIMEZONE data 1938 UnicodeString fooData2; 1939 foo->write(getUTCMillis(2005, UCAL_JANUARY, 1), fooData2, status); 1940 if (U_FAILURE(status)) { 1941 errln("FAIL: Failed to write VTIMEZONE data for foo"); 1942 } 1943 logln(fooData2); 1944 } 1945 delete foo; 1946 } 1947 1948 void 1949 TimeZoneRuleTest::TestT6216(void) { 1950 // Test case in #6216 1951 static const UChar tokyoTZ[] = { 1952 /* "BEGIN:VCALENDAR\r\n" */ 1953 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a, 1954 /* "VERSION:2.0\r\n" */ 1955 0x56,0x45,0x52,0x53,0x49,0x4f,0x4e,0x3a,0x32,0x2e,0x30,0x0d,0x0a, 1956 /* "PRODID:-//PYVOBJECT//NONSGML Version 1//EN\r\n" */ 1957 0x50,0x52,0x4f,0x44,0x49,0x44,0x3a,0x2d,0x2f,0x2f,0x50,0x59,0x56,0x4f,0x42,0x4a,0x45,0x43,0x54,0x2f,0x2f,0x4e,0x4f,0x4e,0x53,0x47,0x4d,0x4c,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2f,0x2f,0x45,0x4e,0x0d,0x0a, 1958 /* "BEGIN:VTIMEZONE\r\n" */ 1959 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a, 1960 /* "TZID:Asia/Tokyo\r\n" */ 1961 0x54,0x5a,0x49,0x44,0x3a,0x41,0x73,0x69,0x61,0x2f,0x54,0x6f,0x6b,0x79,0x6f,0x0d,0x0a, 1962 /* "BEGIN:STANDARD\r\n" */ 1963 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 1964 /* "DTSTART:20000101T000000\r\n" */ 1965 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3a,0x32,0x30,0x30,0x30,0x30,0x31,0x30,0x31,0x54,0x30,0x30,0x30,0x30,0x30,0x30,0x0d,0x0a, 1966 /* "RRULE:FREQ=YEARLY;BYMONTH=1\r\n" */ 1967 0x52,0x52,0x55,0x4c,0x45,0x3a,0x46,0x52,0x45,0x51,0x3d,0x59,0x45,0x41,0x52,0x4c,0x59,0x3b,0x42,0x59,0x4d,0x4f,0x4e,0x54,0x48,0x3d,0x31,0x0d,0x0a, 1968 /* "TZNAME:Asia/Tokyo\r\n" */ 1969 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x41,0x73,0x69,0x61,0x2f,0x54,0x6f,0x6b,0x79,0x6f,0x0d,0x0a, 1970 /* "TZOFFSETFROM:+0900\r\n" */ 1971 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2b,0x30,0x39,0x30,0x30,0x0d,0x0a, 1972 /* "TZOFFSETTO:+0900\r\n" */ 1973 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2b,0x30,0x39,0x30,0x30,0x0d,0x0a, 1974 /* "END:STANDARD\r\n" */ 1975 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 1976 /* "END:VTIMEZONE\r\n" */ 1977 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a, 1978 /* "END:VCALENDAR" */ 1979 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a, 1980 0 1981 }; 1982 // Single final rule, overlapping with another 1983 static const UChar finalOverlap[] = { 1984 /* "BEGIN:VCALENDAR\r\n" */ 1985 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a, 1986 /* "BEGIN:VTIMEZONE\r\n" */ 1987 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a, 1988 /* "TZID:FinalOverlap\r\n" */ 1989 0x54,0x5a,0x49,0x44,0x3a,0x46,0x69,0x6e,0x61,0x6c,0x4f,0x76,0x65,0x72,0x6c,0x61,0x70,0x0d,0x0a, 1990 /* "BEGIN:STANDARD\r\n" */ 1991 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 1992 /* "TZOFFSETFROM:-0200\r\n" */ 1993 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a, 1994 /* "TZOFFSETTO:-0300\r\n" */ 1995 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a, 1996 /* "TZNAME:STD\r\n" */ 1997 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x0d,0x0a, 1998 /* "DTSTART:20001029T020000\r\n" */ 1999 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3a,0x32,0x30,0x30,0x30,0x31,0x30,0x32,0x39,0x54,0x30,0x32,0x30,0x30,0x30,0x30,0x0d,0x0a, 2000 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" */ 2001 0x52,0x52,0x55,0x4c,0x45,0x3a,0x46,0x52,0x45,0x51,0x3d,0x59,0x45,0x41,0x52,0x4c,0x59,0x3b,0x42,0x59,0x44,0x41,0x59,0x3d,0x2d,0x31,0x53,0x55,0x3b,0x42,0x59,0x4d,0x4f,0x4e,0x54,0x48,0x3d,0x31,0x30,0x0d,0x0a, 2002 /* "END:STANDARD\r\n" */ 2003 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 2004 /* "BEGIN:DAYLIGHT\r\n" */ 2005 0x42,0x45,0x47,0x49,0x4e,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a, 2006 /* "TZOFFSETFROM:-0300\r\n" */ 2007 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a, 2008 /* "TZOFFSETTO:-0200\r\n" */ 2009 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a, 2010 /* "TZNAME:DST\r\n" */ 2011 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x44,0x53,0x54,0x0d,0x0a, 2012 /* "DTSTART:19990404T020000\r\n" */ 2013 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3a,0x31,0x39,0x39,0x39,0x30,0x34,0x30,0x34,0x54,0x30,0x32,0x30,0x30,0x30,0x30,0x0d,0x0a, 2014 /* "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" */ 2015 0x52,0x52,0x55,0x4c,0x45,0x3a,0x46,0x52,0x45,0x51,0x3d,0x59,0x45,0x41,0x52,0x4c,0x59,0x3b,0x42,0x59,0x44,0x41,0x59,0x3d,0x31,0x53,0x55,0x3b,0x42,0x59,0x4d,0x4f,0x4e,0x54,0x48,0x3d,0x34,0x3b,0x55,0x4e,0x54,0x49,0x4c,0x3d,0x32,0x30,0x30,0x35,0x30,0x34,0x30,0x33,0x54,0x30,0x34,0x30,0x30,0x30,0x30,0x5a,0x0d,0x0a, 2016 /* "END:DAYLIGHT\r\n" */ 2017 0x45,0x4e,0x44,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a, 2018 /* "END:VTIMEZONE\r\n" */ 2019 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a, 2020 /* "END:VCALENDAR" */ 2021 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a, 2022 0 2023 }; 2024 // Single final rule, no overlapping with another 2025 static const UChar finalNonOverlap[] = { 2026 /* "BEGIN:VCALENDAR\r\n" */ 2027 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a, 2028 /* "BEGIN:VTIMEZONE\r\n" */ 2029 0x42,0x45,0x47,0x49,0x4e,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a, 2030 /* "TZID:FinalNonOverlap\r\n" */ 2031 0x54,0x5a,0x49,0x44,0x3a,0x46,0x69,0x6e,0x61,0x6c,0x4e,0x6f,0x6e,0x4f,0x76,0x65,0x72,0x6c,0x61,0x70,0x0d,0x0a, 2032 /* "BEGIN:STANDARD\r\n" */ 2033 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 2034 /* "TZOFFSETFROM:-0200\r\n" */ 2035 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a, 2036 /* "TZOFFSETTO:-0300\r\n" */ 2037 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a, 2038 /* "TZNAME:STD\r\n" */ 2039 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x0d,0x0a, 2040 /* "DTSTART:20001029T020000\r\n" */ 2041 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3a,0x32,0x30,0x30,0x30,0x31,0x30,0x32,0x39,0x54,0x30,0x32,0x30,0x30,0x30,0x30,0x0d,0x0a, 2042 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10;UNTIL=20041031T040000Z\r\n" */ 2043 0x52,0x52,0x55,0x4c,0x45,0x3a,0x46,0x52,0x45,0x51,0x3d,0x59,0x45,0x41,0x52,0x4c,0x59,0x3b,0x42,0x59,0x44,0x41,0x59,0x3d,0x2d,0x31,0x53,0x55,0x3b,0x42,0x59,0x4d,0x4f,0x4e,0x54,0x48,0x3d,0x31,0x30,0x3b,0x55,0x4e,0x54,0x49,0x4c,0x3d,0x32,0x30,0x30,0x34,0x31,0x30,0x33,0x31,0x54,0x30,0x34,0x30,0x30,0x30,0x30,0x5a,0x0d,0x0a, 2044 /* "END:STANDARD\r\n" */ 2045 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 2046 /* "BEGIN:DAYLIGHT\r\n" */ 2047 0x42,0x45,0x47,0x49,0x4e,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a, 2048 /* "TZOFFSETFROM:-0300\r\n" */ 2049 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a, 2050 /* "TZOFFSETTO:-0200\r\n" */ 2051 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a, 2052 /* "TZNAME:DST\r\n" */ 2053 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x44,0x53,0x54,0x0d,0x0a, 2054 /* "DTSTART:19990404T020000\r\n" */ 2055 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3a,0x31,0x39,0x39,0x39,0x30,0x34,0x30,0x34,0x54,0x30,0x32,0x30,0x30,0x30,0x30,0x0d,0x0a, 2056 /* "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T040000Z\r\n" */ 2057 0x52,0x52,0x55,0x4c,0x45,0x3a,0x46,0x52,0x45,0x51,0x3d,0x59,0x45,0x41,0x52,0x4c,0x59,0x3b,0x42,0x59,0x44,0x41,0x59,0x3d,0x31,0x53,0x55,0x3b,0x42,0x59,0x4d,0x4f,0x4e,0x54,0x48,0x3d,0x34,0x3b,0x55,0x4e,0x54,0x49,0x4c,0x3d,0x32,0x30,0x30,0x35,0x30,0x34,0x30,0x33,0x54,0x30,0x34,0x30,0x30,0x30,0x30,0x5a,0x0d,0x0a, 2058 /* "END:DAYLIGHT\r\n" */ 2059 0x45,0x4e,0x44,0x3a,0x44,0x41,0x59,0x4c,0x49,0x47,0x48,0x54,0x0d,0x0a, 2060 /* "BEGIN:STANDARD\r\n" */ 2061 0x42,0x45,0x47,0x49,0x4e,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 2062 /* "TZOFFSETFROM:-0200\r\n" */ 2063 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x46,0x52,0x4f,0x4d,0x3a,0x2d,0x30,0x32,0x30,0x30,0x0d,0x0a, 2064 /* "TZOFFSETTO:-0300\r\n" */ 2065 0x54,0x5a,0x4f,0x46,0x46,0x53,0x45,0x54,0x54,0x4f,0x3a,0x2d,0x30,0x33,0x30,0x30,0x0d,0x0a, 2066 /* "TZNAME:STDFINAL\r\n" */ 2067 0x54,0x5a,0x4e,0x41,0x4d,0x45,0x3a,0x53,0x54,0x44,0x46,0x49,0x4e,0x41,0x4c,0x0d,0x0a, 2068 /* "DTSTART:20071028T020000\r\n" */ 2069 0x44,0x54,0x53,0x54,0x41,0x52,0x54,0x3a,0x32,0x30,0x30,0x37,0x31,0x30,0x32,0x38,0x54,0x30,0x32,0x30,0x30,0x30,0x30,0x0d,0x0a, 2070 /* "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\r\n" */ 2071 0x52,0x52,0x55,0x4c,0x45,0x3a,0x46,0x52,0x45,0x51,0x3d,0x59,0x45,0x41,0x52,0x4c,0x59,0x3b,0x42,0x59,0x44,0x41,0x59,0x3d,0x2d,0x31,0x53,0x55,0x3b,0x42,0x59,0x4d,0x4f,0x4e,0x54,0x48,0x3d,0x31,0x30,0x0d,0x0a, 2072 /* "END:STANDARD\r\n" */ 2073 0x45,0x4e,0x44,0x3a,0x53,0x54,0x41,0x4e,0x44,0x41,0x52,0x44,0x0d,0x0a, 2074 /* "END:VTIMEZONE\r\n" */ 2075 0x45,0x4e,0x44,0x3a,0x56,0x54,0x49,0x4d,0x45,0x5a,0x4f,0x4e,0x45,0x0d,0x0a, 2076 /* "END:VCALENDAR" */ 2077 0x45,0x4e,0x44,0x3a,0x56,0x43,0x41,0x4c,0x45,0x4e,0x44,0x41,0x52,0x0d,0x0a, 2078 0 2079 }; 2080 2081 static const int32_t TestDates[][3] = { 2082 {1995, UCAL_JANUARY, 1}, 2083 {1995, UCAL_JULY, 1}, 2084 {2000, UCAL_JANUARY, 1}, 2085 {2000, UCAL_JULY, 1}, 2086 {2005, UCAL_JANUARY, 1}, 2087 {2005, UCAL_JULY, 1}, 2088 {2010, UCAL_JANUARY, 1}, 2089 {2010, UCAL_JULY, 1}, 2090 {0, 0, 0} 2091 }; 2092 2093 /*static*/ const UnicodeString TestZones[] = { 2094 UnicodeString(tokyoTZ), 2095 UnicodeString(finalOverlap), 2096 UnicodeString(finalNonOverlap), 2097 UnicodeString() 2098 }; 2099 2100 int32_t Expected[][8] = { 2101 // JAN90 JUL90 JAN00 JUL00 JAN05 JUL05 JAN10 JUL10 2102 { 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000, 32400000}, 2103 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000}, 2104 {-10800000, -10800000, -7200000, -7200000, -10800000, -7200000, -10800000, -10800000} 2105 }; 2106 2107 int32_t i, j; 2108 2109 // Get test times 2110 UDate times[UPRV_LENGTHOF(TestDates)]; 2111 int32_t numTimes; 2112 2113 UErrorCode status = U_ZERO_ERROR; 2114 TimeZone *utc = TimeZone::createTimeZone("Etc/GMT"); 2115 GregorianCalendar cal(utc, status); 2116 if (U_FAILURE(status)) { 2117 dataerrln("FAIL: Failed to creat a GregorianCalendar: %s", u_errorName(status)); 2118 return; 2119 } 2120 for (i = 0; TestDates[i][2] != 0; i++) { 2121 cal.clear(); 2122 cal.set(TestDates[i][0], TestDates[i][1], TestDates[i][2]); 2123 times[i] = cal.getTime(status); 2124 if (U_FAILURE(status)) { 2125 errln("FAIL: getTime failed"); 2126 return; 2127 } 2128 } 2129 numTimes = i; 2130 2131 // Test offset 2132 for (i = 0; !TestZones[i].isEmpty(); i++) { 2133 VTimeZone *vtz = VTimeZone::createVTimeZone(TestZones[i], status); 2134 if (U_FAILURE(status)) { 2135 errln("FAIL: failed to create VTimeZone"); 2136 continue; 2137 } 2138 for (j = 0; j < numTimes; j++) { 2139 int32_t raw, dst; 2140 status = U_ZERO_ERROR; 2141 vtz->getOffset(times[j], FALSE, raw, dst, status); 2142 if (U_FAILURE(status)) { 2143 errln((UnicodeString)"FAIL: getOffset failed for time zone " + i + " at " + times[j]); 2144 } 2145 int32_t offset = raw + dst; 2146 if (offset != Expected[i][j]) { 2147 errln((UnicodeString)"FAIL: Invalid offset at time(" + times[j] + "):" + offset + " Expected:" + Expected[i][j]); 2148 } 2149 } 2150 delete vtz; 2151 } 2152 } 2153 2154 void 2155 TimeZoneRuleTest::TestT6669(void) { 2156 UErrorCode status = U_ZERO_ERROR; 2157 SimpleTimeZone stz(0, "CustomID", UCAL_JANUARY, 1, UCAL_SUNDAY, 0, UCAL_JULY, 1, UCAL_SUNDAY, 0, status); 2158 if (U_FAILURE(status)) { 2159 errln("FAIL: Failed to creat a SimpleTimeZone"); 2160 return; 2161 } 2162 2163 UDate t = 1230681600000.0; //2008-12-31T00:00:00 2164 UDate expectedNext = 1231027200000.0; //2009-01-04T00:00:00 2165 UDate expectedPrev = 1215298800000.0; //2008-07-06T00:00:00 2166 2167 TimeZoneTransition tzt; 2168 UBool avail = stz.getNextTransition(t, FALSE, tzt); 2169 if (!avail) { 2170 errln("FAIL: No transition returned by getNextTransition."); 2171 } else if (tzt.getTime() != expectedNext) { 2172 errln((UnicodeString)"FAIL: Wrong transition time returned by getNextTransition - " 2173 + tzt.getTime() + " Expected: " + expectedNext); 2174 } 2175 2176 avail = stz.getPreviousTransition(t, TRUE, tzt); 2177 if (!avail) { 2178 errln("FAIL: No transition returned by getPreviousTransition."); 2179 } else if (tzt.getTime() != expectedPrev) { 2180 errln((UnicodeString)"FAIL: Wrong transition time returned by getPreviousTransition - " 2181 + tzt.getTime() + " Expected: " + expectedPrev); 2182 } 2183 } 2184 2185 void 2186 TimeZoneRuleTest::TestVTimeZoneWrapper(void) { 2187 #if 0 2188 // local variables 2189 UBool b; 2190 UChar * data = NULL; 2191 int32_t length = 0; 2192 int32_t i; 2193 UDate result; 2194 UDate base = 1231027200000.0; //2009-01-04T00:00:00 2195 UErrorCode status; 2196 2197 const char *name = "Test Initial"; 2198 UChar uname[20]; 2199 2200 UClassID cid1; 2201 UClassID cid2; 2202 2203 ZRule * r; 2204 IZRule* ir1; 2205 IZRule* ir2; 2206 ZTrans* zt1; 2207 ZTrans* zt2; 2208 VZone* v1; 2209 VZone* v2; 2210 2211 uprv_memset(uname, 0, sizeof(uname)); 2212 u_uastrcpy(uname, name); 2213 2214 // create rules 2215 ir1 = izrule_open(uname, 13, 2*HOUR, 0); 2216 ir2 = izrule_clone(ir1); 2217 2218 // test equality 2219 b = izrule_equals(ir1, ir2); 2220 b = izrule_isEquivalentTo(ir1, ir2); 2221 2222 // test accessors 2223 izrule_getName(ir1, data, length); 2224 i = izrule_getRawOffset(ir1); 2225 i = izrule_getDSTSavings(ir1); 2226 2227 b = izrule_getFirstStart(ir1, 2*HOUR, 0, result); 2228 b = izrule_getFinalStart(ir1, 2*HOUR, 0, result); 2229 b = izrule_getNextStart(ir1, base , 2*HOUR, 0, true, result); 2230 b = izrule_getPreviousStart(ir1, base, 2*HOUR, 0, true, result); 2231 2232 // test class ids 2233 cid1 = izrule_getStaticClassID(ir1); 2234 cid2 = izrule_getDynamicClassID(ir1); 2235 2236 // test transitions 2237 zt1 = ztrans_open(base, ir1, ir2); 2238 zt2 = ztrans_clone(zt1); 2239 zt2 = ztrans_openEmpty(); 2240 2241 // test equality 2242 b = ztrans_equals(zt1, zt2); 2243 2244 // test accessors 2245 result = ztrans_getTime(zt1); 2246 ztrans_setTime(zt1, result); 2247 2248 r = (ZRule*)ztrans_getFrom(zt1); 2249 ztrans_setFrom(zt1, (void*)ir1); 2250 ztrans_adoptFrom(zt1, (void*)ir1); 2251 2252 r = (ZRule*)ztrans_getTo(zt1); 2253 ztrans_setTo(zt1, (void*)ir2); 2254 ztrans_adoptTo(zt1, (void*)ir2); 2255 2256 // test class ids 2257 cid1 = ztrans_getStaticClassID(zt1); 2258 cid2 = ztrans_getDynamicClassID(zt2); 2259 2260 // test vzone 2261 v1 = vzone_openID((UChar*)"America/Chicago", sizeof("America/Chicago")); 2262 v2 = vzone_clone(v1); 2263 //v2 = vzone_openData(const UChar* vtzdata, int32_t vtzdataLength, UErrorCode& status); 2264 2265 // test equality 2266 b = vzone_equals(v1, v2); 2267 b = vzone_hasSameRules(v1, v2); 2268 2269 // test accessors 2270 b = vzone_getTZURL(v1, data, length); 2271 vzone_setTZURL(v1, data, length); 2272 2273 b = vzone_getLastModified(v1, result); 2274 vzone_setLastModified(v1, result); 2275 2276 // test writers 2277 vzone_write(v1, data, length, status); 2278 vzone_writeFromStart(v1, result, data, length, status); 2279 vzone_writeSimple(v1, result, data, length, status); 2280 2281 // test more accessors 2282 i = vzone_getRawOffset(v1); 2283 vzone_setRawOffset(v1, i); 2284 2285 b = vzone_useDaylightTime(v1); 2286 b = vzone_inDaylightTime(v1, result, status); 2287 2288 b = vzone_getNextTransition(v1, result, false, zt1); 2289 b = vzone_getPreviousTransition(v1, result, false, zt1); 2290 i = vzone_countTransitionRules(v1, status); 2291 2292 cid1 = vzone_getStaticClassID(v1); 2293 cid2 = vzone_getDynamicClassID(v1); 2294 2295 // cleanup 2296 vzone_close(v1); 2297 vzone_close(v2); 2298 ztrans_close(zt1); 2299 ztrans_close(zt2); 2300 #endif 2301 } 2302 2303 //----------- private test helpers ------------------------------------------------- 2304 2305 UDate 2306 TimeZoneRuleTest::getUTCMillis(int32_t y, int32_t m, int32_t d, 2307 int32_t hr, int32_t min, int32_t sec, int32_t msec) { 2308 UErrorCode status = U_ZERO_ERROR; 2309 const TimeZone *tz = TimeZone::getGMT(); 2310 Calendar *cal = Calendar::createInstance(*tz, status); 2311 if (U_FAILURE(status)) { 2312 delete cal; 2313 dataerrln("FAIL: Calendar::createInstance failed: %s", u_errorName(status)); 2314 return 0.0; 2315 } 2316 cal->set(y, m, d, hr, min, sec); 2317 cal->set(UCAL_MILLISECOND, msec); 2318 UDate utc = cal->getTime(status); 2319 if (U_FAILURE(status)) { 2320 delete cal; 2321 errln("FAIL: Calendar::getTime failed"); 2322 return 0.0; 2323 } 2324 delete cal; 2325 return utc; 2326 } 2327 2328 /* 2329 * Check if a time shift really happens on each transition returned by getNextTransition or 2330 * getPreviousTransition in the specified time range 2331 */ 2332 void 2333 TimeZoneRuleTest::verifyTransitions(BasicTimeZone& icutz, UDate start, UDate end) { 2334 UErrorCode status = U_ZERO_ERROR; 2335 UDate time; 2336 int32_t raw, dst, raw0, dst0; 2337 TimeZoneTransition tzt, tzt0; 2338 UBool avail; 2339 UBool first = TRUE; 2340 UnicodeString tzid; 2341 2342 // Ascending 2343 time = start; 2344 while (TRUE) { 2345 avail = icutz.getNextTransition(time, FALSE, tzt); 2346 if (!avail) { 2347 break; 2348 } 2349 time = tzt.getTime(); 2350 if (time >= end) { 2351 break; 2352 } 2353 icutz.getOffset(time, FALSE, raw, dst, status); 2354 icutz.getOffset(time - 1, FALSE, raw0, dst0, status); 2355 if (U_FAILURE(status)) { 2356 errln("FAIL: Error in getOffset"); 2357 break; 2358 } 2359 2360 if (raw == raw0 && dst == dst0) { 2361 errln((UnicodeString)"FAIL: False transition returned by getNextTransition for " 2362 + icutz.getID(tzid) + " at " + dateToString(time)); 2363 } 2364 if (!first && 2365 (tzt0.getTo()->getRawOffset() != tzt.getFrom()->getRawOffset() 2366 || tzt0.getTo()->getDSTSavings() != tzt.getFrom()->getDSTSavings())) { 2367 errln((UnicodeString)"FAIL: TO rule of the previous transition does not match FROM rule of this transtion at " 2368 + dateToString(time) + " for " + icutz.getID(tzid)); 2369 } 2370 tzt0 = tzt; 2371 first = FALSE; 2372 } 2373 2374 // Descending 2375 first = TRUE; 2376 time = end; 2377 while(true) { 2378 avail = icutz.getPreviousTransition(time, FALSE, tzt); 2379 if (!avail) { 2380 break; 2381 } 2382 time = tzt.getTime(); 2383 if (time <= start) { 2384 break; 2385 } 2386 icutz.getOffset(time, FALSE, raw, dst, status); 2387 icutz.getOffset(time - 1, FALSE, raw0, dst0, status); 2388 if (U_FAILURE(status)) { 2389 errln("FAIL: Error in getOffset"); 2390 break; 2391 } 2392 2393 if (raw == raw0 && dst == dst0) { 2394 errln((UnicodeString)"FAIL: False transition returned by getPreviousTransition for " 2395 + icutz.getID(tzid) + " at " + dateToString(time)); 2396 } 2397 2398 if (!first && 2399 (tzt0.getFrom()->getRawOffset() != tzt.getTo()->getRawOffset() 2400 || tzt0.getFrom()->getDSTSavings() != tzt.getTo()->getDSTSavings())) { 2401 errln((UnicodeString)"FAIL: TO rule of the next transition does not match FROM rule in this transtion at " 2402 + dateToString(time) + " for " + icutz.getID(tzid)); 2403 } 2404 tzt0 = tzt; 2405 first = FALSE; 2406 } 2407 } 2408 2409 /* 2410 * Compare all time transitions in 2 time zones in the specified time range in ascending order 2411 */ 2412 void 2413 TimeZoneRuleTest::compareTransitionsAscending(BasicTimeZone& z1, BasicTimeZone& z2, 2414 UDate start, UDate end, UBool inclusive) { 2415 UnicodeString zid1, zid2; 2416 TimeZoneTransition tzt1, tzt2; 2417 UBool avail1, avail2; 2418 UBool inRange1, inRange2; 2419 2420 z1.getID(zid1); 2421 z2.getID(zid2); 2422 2423 UDate time = start; 2424 while (TRUE) { 2425 avail1 = z1.getNextTransition(time, inclusive, tzt1); 2426 avail2 = z2.getNextTransition(time, inclusive, tzt2); 2427 2428 inRange1 = inRange2 = FALSE; 2429 if (avail1) { 2430 if (tzt1.getTime() < end || (inclusive && tzt1.getTime() == end)) { 2431 inRange1 = TRUE; 2432 } 2433 } 2434 if (avail2) { 2435 if (tzt2.getTime() < end || (inclusive && tzt2.getTime() == end)) { 2436 inRange2 = TRUE; 2437 } 2438 } 2439 if (!inRange1 && !inRange2) { 2440 // No more transition in the range 2441 break; 2442 } 2443 if (!inRange1) { 2444 errln((UnicodeString)"FAIL: " + zid1 + " does not have any transitions after " 2445 + dateToString(time) + " before " + dateToString(end)); 2446 break; 2447 } 2448 if (!inRange2) { 2449 errln((UnicodeString)"FAIL: " + zid2 + " does not have any transitions after " 2450 + dateToString(time) + " before " + dateToString(end)); 2451 break; 2452 } 2453 if (tzt1.getTime() != tzt2.getTime()) { 2454 errln((UnicodeString)"FAIL: First transition after " + dateToString(time) + " " 2455 + zid1 + "[" + dateToString(tzt1.getTime()) + "] " 2456 + zid2 + "[" + dateToString(tzt2.getTime()) + "]"); 2457 break; 2458 } 2459 time = tzt1.getTime(); 2460 if (inclusive) { 2461 time += 1; 2462 } 2463 } 2464 } 2465 2466 /* 2467 * Compare all time transitions in 2 time zones in the specified time range in descending order 2468 */ 2469 void 2470 TimeZoneRuleTest::compareTransitionsDescending(BasicTimeZone& z1, BasicTimeZone& z2, 2471 UDate start, UDate end, UBool inclusive) { 2472 UnicodeString zid1, zid2; 2473 TimeZoneTransition tzt1, tzt2; 2474 UBool avail1, avail2; 2475 UBool inRange1, inRange2; 2476 2477 z1.getID(zid1); 2478 z2.getID(zid2); 2479 2480 UDate time = end; 2481 while (TRUE) { 2482 avail1 = z1.getPreviousTransition(time, inclusive, tzt1); 2483 avail2 = z2.getPreviousTransition(time, inclusive, tzt2); 2484 2485 inRange1 = inRange2 = FALSE; 2486 if (avail1) { 2487 if (tzt1.getTime() > start || (inclusive && tzt1.getTime() == start)) { 2488 inRange1 = TRUE; 2489 } 2490 } 2491 if (avail2) { 2492 if (tzt2.getTime() > start || (inclusive && tzt2.getTime() == start)) { 2493 inRange2 = TRUE; 2494 } 2495 } 2496 if (!inRange1 && !inRange2) { 2497 // No more transition in the range 2498 break; 2499 } 2500 if (!inRange1) { 2501 errln((UnicodeString)"FAIL: " + zid1 + " does not have any transitions before " 2502 + dateToString(time) + " after " + dateToString(start)); 2503 break; 2504 } 2505 if (!inRange2) { 2506 errln((UnicodeString)"FAIL: " + zid2 + " does not have any transitions before " 2507 + dateToString(time) + " after " + dateToString(start)); 2508 break; 2509 } 2510 if (tzt1.getTime() != tzt2.getTime()) { 2511 errln((UnicodeString)"FAIL: Last transition before " + dateToString(time) + " " 2512 + zid1 + "[" + dateToString(tzt1.getTime()) + "] " 2513 + zid2 + "[" + dateToString(tzt2.getTime()) + "]"); 2514 break; 2515 } 2516 time = tzt1.getTime(); 2517 if (inclusive) { 2518 time -= 1; 2519 } 2520 } 2521 } 2522 2523 // Slightly modified version of BasicTimeZone::hasEquivalentTransitions. 2524 // This version returns TRUE if transition time delta is within the given 2525 // delta range. 2526 static UBool hasEquivalentTransitions(/*const*/ BasicTimeZone& tz1, /*const*/BasicTimeZone& tz2, 2527 UDate start, UDate end, 2528 UBool ignoreDstAmount, int32_t maxTransitionTimeDelta, 2529 UErrorCode& status) { 2530 if (U_FAILURE(status)) { 2531 return FALSE; 2532 } 2533 if (tz1.hasSameRules(tz2)) { 2534 return TRUE; 2535 } 2536 // Check the offsets at the start time 2537 int32_t raw1, raw2, dst1, dst2; 2538 tz1.getOffset(start, FALSE, raw1, dst1, status); 2539 if (U_FAILURE(status)) { 2540 return FALSE; 2541 } 2542 tz2.getOffset(start, FALSE, raw2, dst2, status); 2543 if (U_FAILURE(status)) { 2544 return FALSE; 2545 } 2546 if (ignoreDstAmount) { 2547 if ((raw1 + dst1 != raw2 + dst2) 2548 || (dst1 != 0 && dst2 == 0) 2549 || (dst1 == 0 && dst2 != 0)) { 2550 return FALSE; 2551 } 2552 } else { 2553 if (raw1 != raw2 || dst1 != dst2) { 2554 return FALSE; 2555 } 2556 } 2557 // Check transitions in the range 2558 UDate time = start; 2559 TimeZoneTransition tr1, tr2; 2560 while (TRUE) { 2561 UBool avail1 = tz1.getNextTransition(time, FALSE, tr1); 2562 UBool avail2 = tz2.getNextTransition(time, FALSE, tr2); 2563 2564 if (ignoreDstAmount) { 2565 // Skip a transition which only differ the amount of DST savings 2566 while (TRUE) { 2567 if (avail1 2568 && tr1.getTime() <= end 2569 && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings() 2570 == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()) 2571 && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) { 2572 tz1.getNextTransition(tr1.getTime(), FALSE, tr1); 2573 } else { 2574 break; 2575 } 2576 } 2577 while (TRUE) { 2578 if (avail2 2579 && tr2.getTime() <= end 2580 && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings() 2581 == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()) 2582 && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) { 2583 tz2.getNextTransition(tr2.getTime(), FALSE, tr2); 2584 } else { 2585 break; 2586 } 2587 } 2588 } 2589 2590 UBool inRange1 = (avail1 && tr1.getTime() <= end); 2591 UBool inRange2 = (avail2 && tr2.getTime() <= end); 2592 if (!inRange1 && !inRange2) { 2593 // No more transition in the range 2594 break; 2595 } 2596 if (!inRange1 || !inRange2) { 2597 return FALSE; 2598 } 2599 double delta = tr1.getTime() >= tr2.getTime() ? tr1.getTime() - tr2.getTime() : tr2.getTime() - tr1.getTime(); 2600 if (delta > (double)maxTransitionTimeDelta) { 2601 return FALSE; 2602 } 2603 if (ignoreDstAmount) { 2604 if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings() 2605 != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings() 2606 || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0) 2607 || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) { 2608 return FALSE; 2609 } 2610 } else { 2611 if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() || 2612 tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) { 2613 return FALSE; 2614 } 2615 } 2616 time = tr1.getTime() > tr2.getTime() ? tr1.getTime() : tr2.getTime(); 2617 } 2618 return TRUE; 2619 } 2620 2621 // Test case for ticket#8943 2622 // RuleBasedTimeZone#getOffsets throws NPE 2623 void 2624 TimeZoneRuleTest::TestT8943(void) { 2625 UErrorCode status = U_ZERO_ERROR; 2626 UnicodeString id("Ekaterinburg Time"); 2627 UnicodeString stdName("Ekaterinburg Standard Time"); 2628 UnicodeString dstName("Ekaterinburg Daylight Time"); 2629 2630 InitialTimeZoneRule *initialRule = new InitialTimeZoneRule(stdName, 18000000, 0); 2631 RuleBasedTimeZone *rbtz = new RuleBasedTimeZone(id, initialRule); 2632 2633 DateTimeRule *dtRule = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY, 10800000, DateTimeRule::WALL_TIME); 2634 AnnualTimeZoneRule *atzRule = new AnnualTimeZoneRule(stdName, 18000000, 0, dtRule, 2000, 2010); 2635 rbtz->addTransitionRule(atzRule, status); 2636 2637 dtRule = new DateTimeRule(UCAL_MARCH, -1, UCAL_SUNDAY, 7200000, DateTimeRule::WALL_TIME); 2638 atzRule = new AnnualTimeZoneRule(dstName, 18000000, 3600000, dtRule, 2000, 2010); 2639 rbtz->addTransitionRule(atzRule, status); 2640 2641 dtRule = new DateTimeRule(UCAL_JANUARY, 1, 0, DateTimeRule::WALL_TIME); 2642 atzRule = new AnnualTimeZoneRule(stdName, 21600000, 0, dtRule, 2011, AnnualTimeZoneRule::MAX_YEAR); 2643 rbtz->addTransitionRule(atzRule, status); 2644 2645 dtRule = new DateTimeRule(UCAL_JANUARY, 1, 1, DateTimeRule::WALL_TIME); 2646 atzRule = new AnnualTimeZoneRule(dstName, 21600000, 0, dtRule, 2011, AnnualTimeZoneRule::MAX_YEAR); 2647 rbtz->addTransitionRule(atzRule, status); 2648 rbtz->complete(status); 2649 2650 if (U_FAILURE(status)) { 2651 errln("Failed to construct a RuleBasedTimeZone"); 2652 } else { 2653 int32_t raw, dst; 2654 rbtz->getOffset(1293822000000.0 /* 2010-12-31 19:00:00 UTC */, FALSE, raw, dst, status); 2655 if (U_FAILURE(status)) { 2656 errln("Error invoking getOffset"); 2657 } else if (raw != 21600000 || dst != 0) { 2658 errln(UnicodeString("Fail: Wrong offsets: ") + raw + "/" + dst + " Expected: 21600000/0"); 2659 } 2660 } 2661 2662 delete rbtz; 2663 } 2664 2665 #endif /* #if !UCONFIG_NO_FORMATTING */ 2666 2667 //eof 2668