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