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