1 /* 2 ******************************************************************************* 3 * Copyright (C) 2007-2012, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ******************************************************************************* 6 */ 7 8 #include "utypeinfo.h" // for 'typeid' to work 9 10 #include "unicode/utypes.h" 11 12 #if !UCONFIG_NO_FORMATTING 13 14 #include "unicode/rbtz.h" 15 #include "unicode/gregocal.h" 16 #include "uvector.h" 17 #include "gregoimp.h" 18 #include "cmemory.h" 19 20 U_NAMESPACE_BEGIN 21 22 /** 23 * A struct representing a time zone transition 24 */ 25 struct Transition { 26 UDate time; 27 TimeZoneRule* from; 28 TimeZoneRule* to; 29 }; 30 31 static UBool compareRules(UVector* rules1, UVector* rules2) { 32 if (rules1 == NULL && rules2 == NULL) { 33 return TRUE; 34 } else if (rules1 == NULL || rules2 == NULL) { 35 return FALSE; 36 } 37 int32_t size = rules1->size(); 38 if (size != rules2->size()) { 39 return FALSE; 40 } 41 for (int32_t i = 0; i < size; i++) { 42 TimeZoneRule *r1 = (TimeZoneRule*)rules1->elementAt(i); 43 TimeZoneRule *r2 = (TimeZoneRule*)rules2->elementAt(i); 44 if (*r1 != *r2) { 45 return FALSE; 46 } 47 } 48 return TRUE; 49 } 50 51 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone) 52 53 RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule) 54 : BasicTimeZone(id), fInitialRule(initialRule), fHistoricRules(NULL), fFinalRules(NULL), 55 fHistoricTransitions(NULL), fUpToDate(FALSE) { 56 } 57 58 RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone& source) 59 : BasicTimeZone(source), fInitialRule(source.fInitialRule->clone()), 60 fHistoricTransitions(NULL), fUpToDate(FALSE) { 61 fHistoricRules = copyRules(source.fHistoricRules); 62 fFinalRules = copyRules(source.fFinalRules); 63 if (source.fUpToDate) { 64 UErrorCode status = U_ZERO_ERROR; 65 complete(status); 66 } 67 } 68 69 RuleBasedTimeZone::~RuleBasedTimeZone() { 70 deleteTransitions(); 71 deleteRules(); 72 } 73 74 RuleBasedTimeZone& 75 RuleBasedTimeZone::operator=(const RuleBasedTimeZone& right) { 76 if (*this != right) { 77 BasicTimeZone::operator=(right); 78 deleteRules(); 79 fInitialRule = right.fInitialRule->clone(); 80 fHistoricRules = copyRules(right.fHistoricRules); 81 fFinalRules = copyRules(right.fFinalRules); 82 deleteTransitions(); 83 fUpToDate = FALSE; 84 } 85 return *this; 86 } 87 88 UBool 89 RuleBasedTimeZone::operator==(const TimeZone& that) const { 90 if (this == &that) { 91 return TRUE; 92 } 93 if (typeid(*this) != typeid(that) 94 || BasicTimeZone::operator==(that) == FALSE) { 95 return FALSE; 96 } 97 RuleBasedTimeZone *rbtz = (RuleBasedTimeZone*)&that; 98 if (*fInitialRule != *(rbtz->fInitialRule)) { 99 return FALSE; 100 } 101 if (compareRules(fHistoricRules, rbtz->fHistoricRules) 102 && compareRules(fFinalRules, rbtz->fFinalRules)) { 103 return TRUE; 104 } 105 return FALSE; 106 } 107 108 UBool 109 RuleBasedTimeZone::operator!=(const TimeZone& that) const { 110 return !operator==(that); 111 } 112 113 void 114 RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) { 115 if (U_FAILURE(status)) { 116 return; 117 } 118 AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule); 119 if (atzrule != NULL && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) { 120 // A final rule 121 if (fFinalRules == NULL) { 122 fFinalRules = new UVector(status); 123 if (U_FAILURE(status)) { 124 return; 125 } 126 } else if (fFinalRules->size() >= 2) { 127 // Cannot handle more than two final rules 128 status = U_INVALID_STATE_ERROR; 129 return; 130 } 131 fFinalRules->addElement((void*)rule, status); 132 } else { 133 // Non-final rule 134 if (fHistoricRules == NULL) { 135 fHistoricRules = new UVector(status); 136 if (U_FAILURE(status)) { 137 return; 138 } 139 } 140 fHistoricRules->addElement((void*)rule, status); 141 } 142 // Mark dirty, so transitions are recalculated at next complete() call 143 fUpToDate = FALSE; 144 } 145 146 void 147 RuleBasedTimeZone::complete(UErrorCode& status) { 148 if (U_FAILURE(status)) { 149 return; 150 } 151 if (fUpToDate) { 152 return; 153 } 154 // Make sure either no final rules or a pair of AnnualTimeZoneRules 155 // are available. 156 if (fFinalRules != NULL && fFinalRules->size() != 2) { 157 status = U_INVALID_STATE_ERROR; 158 return; 159 } 160 161 UBool *done = NULL; 162 // Create a TimezoneTransition and add to the list 163 if (fHistoricRules != NULL || fFinalRules != NULL) { 164 TimeZoneRule *curRule = fInitialRule; 165 UDate lastTransitionTime = MIN_MILLIS; 166 167 // Build the transition array which represents historical time zone 168 // transitions. 169 if (fHistoricRules != NULL && fHistoricRules->size() > 0) { 170 int32_t i; 171 int32_t historicCount = fHistoricRules->size(); 172 done = (UBool*)uprv_malloc(sizeof(UBool) * historicCount); 173 if (done == NULL) { 174 status = U_MEMORY_ALLOCATION_ERROR; 175 goto cleanup; 176 } 177 for (i = 0; i < historicCount; i++) { 178 done[i] = FALSE; 179 } 180 while (TRUE) { 181 int32_t curStdOffset = curRule->getRawOffset(); 182 int32_t curDstSavings = curRule->getDSTSavings(); 183 UDate nextTransitionTime = MAX_MILLIS; 184 TimeZoneRule *nextRule = NULL; 185 TimeZoneRule *r = NULL; 186 UBool avail; 187 UDate tt; 188 UnicodeString curName, name; 189 curRule->getName(curName); 190 191 for (i = 0; i < historicCount; i++) { 192 if (done[i]) { 193 continue; 194 } 195 r = (TimeZoneRule*)fHistoricRules->elementAt(i); 196 avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt); 197 if (!avail) { 198 // No more transitions from this rule - skip this rule next time 199 done[i] = TRUE; 200 } else { 201 r->getName(name); 202 if (*r == *curRule || 203 (name == curName && r->getRawOffset() == curRule->getRawOffset() 204 && r->getDSTSavings() == curRule->getDSTSavings())) { 205 continue; 206 } 207 if (tt < nextTransitionTime) { 208 nextTransitionTime = tt; 209 nextRule = r; 210 } 211 } 212 } 213 214 if (nextRule == NULL) { 215 // Check if all historic rules are done 216 UBool bDoneAll = TRUE; 217 for (int32_t j = 0; j < historicCount; j++) { 218 if (!done[j]) { 219 bDoneAll = FALSE; 220 break; 221 } 222 } 223 if (bDoneAll) { 224 break; 225 } 226 } 227 228 if (fFinalRules != NULL) { 229 // Check if one of final rules has earlier transition date 230 for (i = 0; i < 2 /* fFinalRules->size() */; i++) { 231 TimeZoneRule *fr = (TimeZoneRule*)fFinalRules->elementAt(i); 232 if (*fr == *curRule) { 233 continue; 234 } 235 r = (TimeZoneRule*)fFinalRules->elementAt(i); 236 avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt); 237 if (avail) { 238 if (tt < nextTransitionTime) { 239 nextTransitionTime = tt; 240 nextRule = r; 241 } 242 } 243 } 244 } 245 246 if (nextRule == NULL) { 247 // Nothing more 248 break; 249 } 250 251 if (fHistoricTransitions == NULL) { 252 fHistoricTransitions = new UVector(status); 253 if (U_FAILURE(status)) { 254 goto cleanup; 255 } 256 } 257 Transition *trst = (Transition*)uprv_malloc(sizeof(Transition)); 258 if (trst == NULL) { 259 status = U_MEMORY_ALLOCATION_ERROR; 260 goto cleanup; 261 } 262 trst->time = nextTransitionTime; 263 trst->from = curRule; 264 trst->to = nextRule; 265 fHistoricTransitions->addElement(trst, status); 266 if (U_FAILURE(status)) { 267 goto cleanup; 268 } 269 lastTransitionTime = nextTransitionTime; 270 curRule = nextRule; 271 } 272 } 273 if (fFinalRules != NULL) { 274 if (fHistoricTransitions == NULL) { 275 fHistoricTransitions = new UVector(status); 276 if (U_FAILURE(status)) { 277 goto cleanup; 278 } 279 } 280 // Append the first transition for each 281 TimeZoneRule *rule0 = (TimeZoneRule*)fFinalRules->elementAt(0); 282 TimeZoneRule *rule1 = (TimeZoneRule*)fFinalRules->elementAt(1); 283 UDate tt0, tt1; 284 UBool avail0 = rule0->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt0); 285 UBool avail1 = rule1->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt1); 286 if (!avail0 || !avail1) { 287 // Should not happen, because both rules are permanent 288 status = U_INVALID_STATE_ERROR; 289 goto cleanup; 290 } 291 Transition *final0 = (Transition*)uprv_malloc(sizeof(Transition)); 292 if (final0 == NULL) { 293 status = U_MEMORY_ALLOCATION_ERROR; 294 goto cleanup; 295 } 296 Transition *final1 = (Transition*)uprv_malloc(sizeof(Transition)); 297 if (final1 == NULL) { 298 uprv_free(final0); 299 status = U_MEMORY_ALLOCATION_ERROR; 300 goto cleanup; 301 } 302 if (tt0 < tt1) { 303 final0->time = tt0; 304 final0->from = curRule; 305 final0->to = rule0; 306 rule1->getNextStart(tt0, rule0->getRawOffset(), rule0->getDSTSavings(), false, final1->time); 307 final1->from = rule0; 308 final1->to = rule1; 309 } else { 310 final0->time = tt1; 311 final0->from = curRule; 312 final0->to = rule1; 313 rule0->getNextStart(tt1, rule1->getRawOffset(), rule1->getDSTSavings(), false, final1->time); 314 final1->from = rule1; 315 final1->to = rule0; 316 } 317 fHistoricTransitions->addElement(final0, status); 318 if (U_FAILURE(status)) { 319 goto cleanup; 320 } 321 fHistoricTransitions->addElement(final1, status); 322 if (U_FAILURE(status)) { 323 goto cleanup; 324 } 325 } 326 } 327 fUpToDate = TRUE; 328 if (done != NULL) { 329 uprv_free(done); 330 } 331 return; 332 333 cleanup: 334 deleteTransitions(); 335 if (done != NULL) { 336 uprv_free(done); 337 } 338 fUpToDate = FALSE; 339 } 340 341 TimeZone* 342 RuleBasedTimeZone::clone(void) const { 343 return new RuleBasedTimeZone(*this); 344 } 345 346 int32_t 347 RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, 348 uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const { 349 if (U_FAILURE(status)) { 350 return 0; 351 } 352 if (month < UCAL_JANUARY || month > UCAL_DECEMBER) { 353 status = U_ILLEGAL_ARGUMENT_ERROR; 354 return 0; 355 } else { 356 return getOffset(era, year, month, day, dayOfWeek, millis, 357 Grego::monthLength(year, month), status); 358 } 359 } 360 361 int32_t 362 RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, 363 uint8_t /*dayOfWeek*/, int32_t millis, 364 int32_t /*monthLength*/, UErrorCode& status) const { 365 // dayOfWeek and monthLength are unused 366 if (U_FAILURE(status)) { 367 return 0; 368 } 369 if (era == GregorianCalendar::BC) { 370 // Convert to extended year 371 year = 1 - year; 372 } 373 int32_t rawOffset, dstOffset; 374 UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis; 375 getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status); 376 if (U_FAILURE(status)) { 377 return 0; 378 } 379 return (rawOffset + dstOffset); 380 } 381 382 void 383 RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset, 384 int32_t& dstOffset, UErrorCode& status) const { 385 getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status); 386 } 387 388 void 389 RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, 390 int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ { 391 getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status); 392 } 393 394 395 /* 396 * The internal getOffset implementation 397 */ 398 void 399 RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local, 400 int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt, 401 int32_t& rawOffset, int32_t& dstOffset, 402 UErrorCode& status) const { 403 rawOffset = 0; 404 dstOffset = 0; 405 406 if (U_FAILURE(status)) { 407 return; 408 } 409 if (!fUpToDate) { 410 // Transitions are not yet resolved. We cannot do it here 411 // because this method is const. Thus, do nothing and return 412 // error status. 413 status = U_INVALID_STATE_ERROR; 414 return; 415 } 416 const TimeZoneRule *rule = NULL; 417 if (fHistoricTransitions == NULL) { 418 rule = fInitialRule; 419 } else { 420 UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0), 421 local, NonExistingTimeOpt, DuplicatedTimeOpt); 422 if (date < tstart) { 423 rule = fInitialRule; 424 } else { 425 int32_t idx = fHistoricTransitions->size() - 1; 426 UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx), 427 local, NonExistingTimeOpt, DuplicatedTimeOpt); 428 if (date > tend) { 429 if (fFinalRules != NULL) { 430 rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt); 431 } 432 if (rule == NULL) { 433 // no final rules or the given time is before the first transition 434 // specified by the final rules -> use the last rule 435 rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to; 436 } 437 } else { 438 // Find a historical transition 439 while (idx >= 0) { 440 if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx), 441 local, NonExistingTimeOpt, DuplicatedTimeOpt)) { 442 break; 443 } 444 idx--; 445 } 446 rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to; 447 } 448 } 449 } 450 if (rule != NULL) { 451 rawOffset = rule->getRawOffset(); 452 dstOffset = rule->getDSTSavings(); 453 } 454 } 455 456 void 457 RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) { 458 // We don't support this operation at this moment. 459 // Nothing to do! 460 } 461 462 int32_t 463 RuleBasedTimeZone::getRawOffset(void) const { 464 // Note: This implementation returns standard GMT offset 465 // as of current time. 466 UErrorCode status = U_ZERO_ERROR; 467 int32_t raw, dst; 468 getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND, 469 FALSE, raw, dst, status); 470 return raw; 471 } 472 473 UBool 474 RuleBasedTimeZone::useDaylightTime(void) const { 475 // Note: This implementation returns true when 476 // daylight saving time is used as of now or 477 // after the next transition. 478 UErrorCode status = U_ZERO_ERROR; 479 UDate now = uprv_getUTCtime() * U_MILLIS_PER_SECOND; 480 int32_t raw, dst; 481 getOffset(now, FALSE, raw, dst, status); 482 if (dst != 0) { 483 return TRUE; 484 } 485 // If DST is not used now, check if DST is used after the next transition 486 UDate time; 487 TimeZoneRule *from, *to; 488 UBool avail = findNext(now, FALSE, time, from, to); 489 if (avail && to->getDSTSavings() != 0) { 490 return TRUE; 491 } 492 return FALSE; 493 } 494 495 UBool 496 RuleBasedTimeZone::inDaylightTime(UDate date, UErrorCode& status) const { 497 if (U_FAILURE(status)) { 498 return FALSE; 499 } 500 int32_t raw, dst; 501 getOffset(date, FALSE, raw, dst, status); 502 if (dst != 0) { 503 return TRUE; 504 } 505 return FALSE; 506 } 507 508 UBool 509 RuleBasedTimeZone::hasSameRules(const TimeZone& other) const { 510 if (this == &other) { 511 return TRUE; 512 } 513 if (typeid(*this) != typeid(other)) { 514 return FALSE; 515 } 516 const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other; 517 if (*fInitialRule != *(that.fInitialRule)) { 518 return FALSE; 519 } 520 if (compareRules(fHistoricRules, that.fHistoricRules) 521 && compareRules(fFinalRules, that.fFinalRules)) { 522 return TRUE; 523 } 524 return FALSE; 525 } 526 527 UBool 528 RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ { 529 UErrorCode status = U_ZERO_ERROR; 530 complete(status); 531 if (U_FAILURE(status)) { 532 return FALSE; 533 } 534 UDate transitionTime; 535 TimeZoneRule *fromRule, *toRule; 536 UBool found = findNext(base, inclusive, transitionTime, fromRule, toRule); 537 if (found) { 538 result.setTime(transitionTime); 539 result.setFrom((const TimeZoneRule&)*fromRule); 540 result.setTo((const TimeZoneRule&)*toRule); 541 return TRUE; 542 } 543 return FALSE; 544 } 545 546 UBool 547 RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ { 548 UErrorCode status = U_ZERO_ERROR; 549 complete(status); 550 if (U_FAILURE(status)) { 551 return FALSE; 552 } 553 UDate transitionTime; 554 TimeZoneRule *fromRule, *toRule; 555 UBool found = findPrev(base, inclusive, transitionTime, fromRule, toRule); 556 if (found) { 557 result.setTime(transitionTime); 558 result.setFrom((const TimeZoneRule&)*fromRule); 559 result.setTo((const TimeZoneRule&)*toRule); 560 return TRUE; 561 } 562 return FALSE; 563 } 564 565 int32_t 566 RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ { 567 int32_t count = 0; 568 if (fHistoricRules != NULL) { 569 count += fHistoricRules->size(); 570 } 571 if (fFinalRules != NULL) { 572 count += fFinalRules->size(); 573 } 574 return count; 575 } 576 577 void 578 RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial, 579 const TimeZoneRule* trsrules[], 580 int32_t& trscount, 581 UErrorCode& status) /*const*/ { 582 if (U_FAILURE(status)) { 583 return; 584 } 585 // Initial rule 586 initial = fInitialRule; 587 588 // Transition rules 589 int32_t cnt = 0; 590 int32_t idx; 591 if (fHistoricRules != NULL && cnt < trscount) { 592 int32_t historicCount = fHistoricRules->size(); 593 idx = 0; 594 while (cnt < trscount && idx < historicCount) { 595 trsrules[cnt++] = (const TimeZoneRule*)fHistoricRules->elementAt(idx++); 596 } 597 } 598 if (fFinalRules != NULL && cnt < trscount) { 599 int32_t finalCount = fFinalRules->size(); 600 idx = 0; 601 while (cnt < trscount && idx < finalCount) { 602 trsrules[cnt++] = (const TimeZoneRule*)fFinalRules->elementAt(idx++); 603 } 604 } 605 // Set the result length 606 trscount = cnt; 607 } 608 609 void 610 RuleBasedTimeZone::deleteRules(void) { 611 delete fInitialRule; 612 fInitialRule = NULL; 613 if (fHistoricRules != NULL) { 614 while (!fHistoricRules->isEmpty()) { 615 delete (TimeZoneRule*)(fHistoricRules->orphanElementAt(0)); 616 } 617 delete fHistoricRules; 618 fHistoricRules = NULL; 619 } 620 if (fFinalRules != NULL) { 621 while (!fFinalRules->isEmpty()) { 622 delete (AnnualTimeZoneRule*)(fFinalRules->orphanElementAt(0)); 623 } 624 delete fFinalRules; 625 fFinalRules = NULL; 626 } 627 } 628 629 void 630 RuleBasedTimeZone::deleteTransitions(void) { 631 if (fHistoricTransitions != NULL) { 632 while (!fHistoricTransitions->isEmpty()) { 633 Transition *trs = (Transition*)fHistoricTransitions->orphanElementAt(0); 634 uprv_free(trs); 635 } 636 delete fHistoricTransitions; 637 } 638 fHistoricTransitions = NULL; 639 } 640 641 UVector* 642 RuleBasedTimeZone::copyRules(UVector* source) { 643 if (source == NULL) { 644 return NULL; 645 } 646 UErrorCode ec = U_ZERO_ERROR; 647 int32_t size = source->size(); 648 UVector *rules = new UVector(size, ec); 649 if (U_FAILURE(ec)) { 650 return NULL; 651 } 652 int32_t i; 653 for (i = 0; i < size; i++) { 654 rules->addElement(((TimeZoneRule*)source->elementAt(i))->clone(), ec); 655 if (U_FAILURE(ec)) { 656 break; 657 } 658 } 659 if (U_FAILURE(ec)) { 660 // In case of error, clean up 661 for (i = 0; i < rules->size(); i++) { 662 TimeZoneRule *rule = (TimeZoneRule*)rules->orphanElementAt(i); 663 delete rule; 664 } 665 delete rules; 666 return NULL; 667 } 668 return rules; 669 } 670 671 TimeZoneRule* 672 RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local, 673 int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const { 674 if (fFinalRules == NULL) { 675 return NULL; 676 } 677 678 AnnualTimeZoneRule* fr0 = (AnnualTimeZoneRule*)fFinalRules->elementAt(0); 679 AnnualTimeZoneRule* fr1 = (AnnualTimeZoneRule*)fFinalRules->elementAt(1); 680 if (fr0 == NULL || fr1 == NULL) { 681 return NULL; 682 } 683 684 UDate start0, start1; 685 UDate base; 686 int32_t localDelta; 687 688 base = date; 689 if (local) { 690 localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(), 691 fr0->getRawOffset(), fr0->getDSTSavings(), 692 NonExistingTimeOpt, DuplicatedTimeOpt); 693 base -= localDelta; 694 } 695 UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0); 696 697 base = date; 698 if (local) { 699 localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(), 700 fr1->getRawOffset(), fr1->getDSTSavings(), 701 NonExistingTimeOpt, DuplicatedTimeOpt); 702 base -= localDelta; 703 } 704 UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1); 705 706 if (!avail0 || !avail1) { 707 if (avail0) { 708 return fr0; 709 } else if (avail1) { 710 return fr1; 711 } 712 // Both rules take effect after the given time 713 return NULL; 714 } 715 716 return (start0 > start1) ? fr0 : fr1; 717 } 718 719 UBool 720 RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime, 721 TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const { 722 if (fHistoricTransitions == NULL) { 723 return FALSE; 724 } 725 UBool isFinal = FALSE; 726 UBool found = FALSE; 727 Transition result; 728 Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0); 729 UDate tt = tzt->time; 730 if (tt > base || (inclusive && tt == base)) { 731 result = *tzt; 732 found = TRUE; 733 } else { 734 int32_t idx = fHistoricTransitions->size() - 1; 735 tzt = (Transition*)fHistoricTransitions->elementAt(idx); 736 tt = tzt->time; 737 if (inclusive && tt == base) { 738 result = *tzt; 739 found = TRUE; 740 } else if (tt <= base) { 741 if (fFinalRules != NULL) { 742 // Find a transion time with finalRules 743 TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0); 744 TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1); 745 UDate start0, start1; 746 UBool avail0 = r0->getNextStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0); 747 UBool avail1 = r1->getNextStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1); 748 // avail0/avail1 should be always TRUE 749 if (!avail0 && !avail1) { 750 return FALSE; 751 } 752 if (!avail1 || start0 < start1) { 753 result.time = start0; 754 result.from = r1; 755 result.to = r0; 756 } else { 757 result.time = start1; 758 result.from = r0; 759 result.to = r1; 760 } 761 isFinal = TRUE; 762 found = TRUE; 763 } 764 } else { 765 // Find a transition within the historic transitions 766 idx--; 767 Transition *prev = tzt; 768 while (idx > 0) { 769 tzt = (Transition*)fHistoricTransitions->elementAt(idx); 770 tt = tzt->time; 771 if (tt < base || (!inclusive && tt == base)) { 772 break; 773 } 774 idx--; 775 prev = tzt; 776 } 777 result.time = prev->time; 778 result.from = prev->from; 779 result.to = prev->to; 780 found = TRUE; 781 } 782 } 783 if (found) { 784 // For now, this implementation ignore transitions with only zone name changes. 785 if (result.from->getRawOffset() == result.to->getRawOffset() 786 && result.from->getDSTSavings() == result.to->getDSTSavings()) { 787 if (isFinal) { 788 return FALSE; 789 } else { 790 // No offset changes. Try next one if not final 791 return findNext(result.time, FALSE /* always exclusive */, 792 transitionTime, fromRule, toRule); 793 } 794 } 795 transitionTime = result.time; 796 fromRule = result.from; 797 toRule = result.to; 798 return TRUE; 799 } 800 return FALSE; 801 } 802 803 UBool 804 RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime, 805 TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const { 806 if (fHistoricTransitions == NULL) { 807 return FALSE; 808 } 809 UBool found = FALSE; 810 Transition result; 811 Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0); 812 UDate tt = tzt->time; 813 if (inclusive && tt == base) { 814 result = *tzt; 815 found = TRUE; 816 } else if (tt < base) { 817 int32_t idx = fHistoricTransitions->size() - 1; 818 tzt = (Transition*)fHistoricTransitions->elementAt(idx); 819 tt = tzt->time; 820 if (inclusive && tt == base) { 821 result = *tzt; 822 found = TRUE; 823 } else if (tt < base) { 824 if (fFinalRules != NULL) { 825 // Find a transion time with finalRules 826 TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0); 827 TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1); 828 UDate start0, start1; 829 UBool avail0 = r0->getPreviousStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0); 830 UBool avail1 = r1->getPreviousStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1); 831 // avail0/avail1 should be always TRUE 832 if (!avail0 && !avail1) { 833 return FALSE; 834 } 835 if (!avail1 || start0 > start1) { 836 result.time = start0; 837 result.from = r1; 838 result.to = r0; 839 } else { 840 result.time = start1; 841 result.from = r0; 842 result.to = r1; 843 } 844 } else { 845 result = *tzt; 846 } 847 found = TRUE; 848 } else { 849 // Find a transition within the historic transitions 850 idx--; 851 while (idx >= 0) { 852 tzt = (Transition*)fHistoricTransitions->elementAt(idx); 853 tt = tzt->time; 854 if (tt < base || (inclusive && tt == base)) { 855 break; 856 } 857 idx--; 858 } 859 result = *tzt; 860 found = TRUE; 861 } 862 } 863 if (found) { 864 // For now, this implementation ignore transitions with only zone name changes. 865 if (result.from->getRawOffset() == result.to->getRawOffset() 866 && result.from->getDSTSavings() == result.to->getDSTSavings()) { 867 // No offset changes. Try next one if not final 868 return findPrev(result.time, FALSE /* always exclusive */, 869 transitionTime, fromRule, toRule); 870 } 871 transitionTime = result.time; 872 fromRule = result.from; 873 toRule = result.to; 874 return TRUE; 875 } 876 return FALSE; 877 } 878 879 UDate 880 RuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local, 881 int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const { 882 UDate time = transition->time; 883 if (local) { 884 time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(), 885 transition->to->getRawOffset(), transition->to->getDSTSavings(), 886 NonExistingTimeOpt, DuplicatedTimeOpt); 887 } 888 return time; 889 } 890 891 int32_t 892 RuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter, 893 int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const { 894 int32_t delta = 0; 895 896 int32_t offsetBefore = rawBefore + dstBefore; 897 int32_t offsetAfter = rawAfter + dstAfter; 898 899 UBool dstToStd = (dstBefore != 0) && (dstAfter == 0); 900 UBool stdToDst = (dstBefore == 0) && (dstAfter != 0); 901 902 if (offsetAfter - offsetBefore >= 0) { 903 // Positive transition, which makes a non-existing local time range 904 if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd) 905 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { 906 delta = offsetBefore; 907 } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst) 908 || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { 909 delta = offsetAfter; 910 } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) { 911 delta = offsetBefore; 912 } else { 913 // Interprets the time with rule before the transition, 914 // default for non-existing time range 915 delta = offsetAfter; 916 } 917 } else { 918 // Negative transition, which makes a duplicated local time range 919 if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd) 920 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { 921 delta = offsetAfter; 922 } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst) 923 || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { 924 delta = offsetBefore; 925 } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) { 926 delta = offsetBefore; 927 } else { 928 // Interprets the time with rule after the transition, 929 // default for duplicated local time range 930 delta = offsetAfter; 931 } 932 } 933 return delta; 934 } 935 936 U_NAMESPACE_END 937 938 #endif /* #if !UCONFIG_NO_FORMATTING */ 939 940 //eof 941 942