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