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