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