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