diff options
author | neksard <neksard@yandex-team.ru> | 2022-02-10 16:45:23 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:23 +0300 |
commit | 8f7cf138264e0caa318144bf8a2c950e0b0a8593 (patch) | |
tree | 83bf5c8c8047c42d8475e6095df90ccdc3d1b57f /contrib/libs/icu/i18n/basictz.cpp | |
parent | d3a398281c6fd1d3672036cb2d63f842d2cb28c5 (diff) | |
download | ydb-8f7cf138264e0caa318144bf8a2c950e0b0a8593.tar.gz |
Restoring authorship annotation for <neksard@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/icu/i18n/basictz.cpp')
-rw-r--r-- | contrib/libs/icu/i18n/basictz.cpp | 1122 |
1 files changed, 561 insertions, 561 deletions
diff --git a/contrib/libs/icu/i18n/basictz.cpp b/contrib/libs/icu/i18n/basictz.cpp index 54ee5a1a2b..36b0e404ef 100644 --- a/contrib/libs/icu/i18n/basictz.cpp +++ b/contrib/libs/icu/i18n/basictz.cpp @@ -1,562 +1,562 @@ // © 2016 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html -/* -******************************************************************************* -* Copyright (C) 2007-2013, International Business Machines Corporation and -* others. All Rights Reserved. -******************************************************************************* -*/ - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -#include "unicode/basictz.h" -#include "gregoimp.h" -#include "uvector.h" -#include "cmemory.h" - -U_NAMESPACE_BEGIN - -#define MILLIS_PER_YEAR (365*24*60*60*1000.0) - -BasicTimeZone::BasicTimeZone() -: TimeZone() { -} - -BasicTimeZone::BasicTimeZone(const UnicodeString &id) -: TimeZone(id) { -} - -BasicTimeZone::BasicTimeZone(const BasicTimeZone& source) -: TimeZone(source) { -} - -BasicTimeZone::~BasicTimeZone() { -} - -UBool -BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end, - UBool ignoreDstAmount, UErrorCode& status) const { - if (U_FAILURE(status)) { - return FALSE; - } - if (hasSameRules(tz)) { - return TRUE; - } - // Check the offsets at the start time - int32_t raw1, raw2, dst1, dst2; - getOffset(start, FALSE, raw1, dst1, status); - if (U_FAILURE(status)) { - return FALSE; - } - tz.getOffset(start, FALSE, raw2, dst2, status); - if (U_FAILURE(status)) { - return FALSE; - } - if (ignoreDstAmount) { - if ((raw1 + dst1 != raw2 + dst2) - || (dst1 != 0 && dst2 == 0) - || (dst1 == 0 && dst2 != 0)) { - return FALSE; - } - } else { - if (raw1 != raw2 || dst1 != dst2) { - return FALSE; - } - } - // Check transitions in the range - UDate time = start; - TimeZoneTransition tr1, tr2; - while (TRUE) { - UBool avail1 = getNextTransition(time, FALSE, tr1); - UBool avail2 = tz.getNextTransition(time, FALSE, tr2); - - if (ignoreDstAmount) { - // Skip a transition which only differ the amount of DST savings - while (TRUE) { - if (avail1 - && tr1.getTime() <= end - && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings() - == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()) - && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) { - getNextTransition(tr1.getTime(), FALSE, tr1); - } else { - break; - } - } - while (TRUE) { - if (avail2 - && tr2.getTime() <= end - && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings() - == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()) - && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) { - tz.getNextTransition(tr2.getTime(), FALSE, tr2); - } else { - break; - } - } - } - - UBool inRange1 = (avail1 && tr1.getTime() <= end); - UBool inRange2 = (avail2 && tr2.getTime() <= end); - if (!inRange1 && !inRange2) { - // No more transition in the range - break; - } - if (!inRange1 || !inRange2) { - return FALSE; - } - if (tr1.getTime() != tr2.getTime()) { - return FALSE; - } - if (ignoreDstAmount) { - if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings() - != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings() - || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0) - || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) { - return FALSE; - } - } else { - if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() || - tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) { - return FALSE; - } - } - time = tr1.getTime(); - } - return TRUE; -} - -void -BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial, - AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const { - initial = NULL; - std = NULL; - dst = NULL; - if (U_FAILURE(status)) { - return; - } - int32_t initialRaw, initialDst; - UnicodeString initialName; - - AnnualTimeZoneRule *ar1 = NULL; - AnnualTimeZoneRule *ar2 = NULL; - UnicodeString name; - - UBool avail; - TimeZoneTransition tr; - // Get the next transition - avail = getNextTransition(date, FALSE, tr); - if (avail) { - tr.getFrom()->getName(initialName); - initialRaw = tr.getFrom()->getRawOffset(); - initialDst = tr.getFrom()->getDSTSavings(); - - // Check if the next transition is either DST->STD or STD->DST and - // within roughly 1 year from the specified date - UDate nextTransitionTime = tr.getTime(); - if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) - || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) - && (date + MILLIS_PER_YEAR > nextTransitionTime)) { - - int32_t year, month, dom, dow, doy, mid; - UDate d; - - // Get local wall time for the next transition time - Grego::timeToFields(nextTransitionTime + initialRaw + initialDst, - year, month, dom, dow, doy, mid); - int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); - // Create DOW rule - DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); - tr.getTo()->getName(name); - - // Note: SimpleTimeZone does not support raw offset change. - // So we always use raw offset of the given time for the rule, - // even raw offset is changed. This will result that the result - // zone to return wrong offset after the transition. - // When we encounter such case, we do not inspect next next - // transition for another rule. - ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(), - dtr, year, AnnualTimeZoneRule::MAX_YEAR); - - if (tr.getTo()->getRawOffset() == initialRaw) { - // Get the next next transition - avail = getNextTransition(nextTransitionTime, FALSE, tr); - if (avail) { - // Check if the next next transition is either DST->STD or STD->DST - // and within roughly 1 year from the next transition - if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) - || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) - && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) { - - // Get local wall time for the next transition time - Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), - year, month, dom, dow, doy, mid); - weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); - // Generate another DOW rule - dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); - tr.getTo()->getName(name); - ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(), - dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR); - - // Make sure this rule can be applied to the specified date - avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d); - if (!avail || d > date - || initialRaw != tr.getTo()->getRawOffset() - || initialDst != tr.getTo()->getDSTSavings()) { - // We cannot use this rule as the second transition rule - delete ar2; - ar2 = NULL; - } - } - } - } - if (ar2 == NULL) { - // Try previous transition - avail = getPreviousTransition(date, TRUE, tr); - if (avail) { - // Check if the previous transition is either DST->STD or STD->DST. - // The actual transition time does not matter here. - if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) - || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) { - - // Generate another DOW rule - Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), - year, month, dom, dow, doy, mid); - weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); - dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); - tr.getTo()->getName(name); - - // second rule raw/dst offsets should match raw/dst offsets - // at the given time - ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst, - dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR); - - // Check if this rule start after the first rule after the specified date - avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d); - if (!avail || d <= nextTransitionTime) { - // We cannot use this rule as the second transition rule - delete ar2; - ar2 = NULL; - } - } - } - } - if (ar2 == NULL) { - // Cannot find a good pair of AnnualTimeZoneRule - delete ar1; - ar1 = NULL; - } else { - // The initial rule should represent the rule before the previous transition - ar1->getName(initialName); - initialRaw = ar1->getRawOffset(); - initialDst = ar1->getDSTSavings(); - } - } - } - else { - // Try the previous one - avail = getPreviousTransition(date, TRUE, tr); - if (avail) { - tr.getTo()->getName(initialName); - initialRaw = tr.getTo()->getRawOffset(); - initialDst = tr.getTo()->getDSTSavings(); - } else { - // No transitions in the past. Just use the current offsets - getOffset(date, FALSE, initialRaw, initialDst, status); - if (U_FAILURE(status)) { - return; - } - } - } - // Set the initial rule - initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst); - - // Set the standard and daylight saving rules - if (ar1 != NULL && ar2 != NULL) { - if (ar1->getDSTSavings() != 0) { - dst = ar1; - std = ar2; - } else { - std = ar1; - dst = ar2; - } - } -} - -void -BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, - UVector*& transitionRules, UErrorCode& status) const { - if (U_FAILURE(status)) { - return; - } - - const InitialTimeZoneRule *orgini; - const TimeZoneRule **orgtrs = NULL; - TimeZoneTransition tzt; - UBool avail; - UVector *orgRules = NULL; - int32_t ruleCount; - TimeZoneRule *r = NULL; - UBool *done = NULL; - InitialTimeZoneRule *res_initial = NULL; - UVector *filteredRules = NULL; - UnicodeString name; - int32_t i; - UDate time, t; - UDate *newTimes = NULL; - UDate firstStart; - UBool bFinalStd = FALSE, bFinalDst = FALSE; - - // Original transition rules - ruleCount = countTransitionRules(status); - if (U_FAILURE(status)) { - return; - } - orgRules = new UVector(ruleCount, status); - if (U_FAILURE(status)) { - return; - } - orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount); - if (orgtrs == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - goto error; - } - getTimeZoneRules(orgini, orgtrs, ruleCount, status); - if (U_FAILURE(status)) { - goto error; - } - for (i = 0; i < ruleCount; i++) { - orgRules->addElement(orgtrs[i]->clone(), status); - if (U_FAILURE(status)) { - goto error; - } - } - uprv_free(orgtrs); - orgtrs = NULL; - - avail = getPreviousTransition(start, TRUE, tzt); - if (!avail) { - // No need to filter out rules only applicable to time before the start - initial = orgini->clone(); - transitionRules = orgRules; - return; - } - - done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount); - if (done == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - goto error; - } - filteredRules = new UVector(status); - if (U_FAILURE(status)) { - goto error; - } - - // Create initial rule - tzt.getTo()->getName(name); - res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), - tzt.getTo()->getDSTSavings()); - - // Mark rules which does not need to be processed - for (i = 0; i < ruleCount; i++) { - r = (TimeZoneRule*)orgRules->elementAt(i); - avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time); - done[i] = !avail; - } - - time = start; - while (!bFinalStd || !bFinalDst) { - avail = getNextTransition(time, FALSE, tzt); - if (!avail) { - break; - } - UDate updatedTime = tzt.getTime(); - if (updatedTime == time) { - // Can get here if rules for start & end of daylight time have exactly - // the same time. - // TODO: fix getNextTransition() to prevent it? - status = U_INVALID_STATE_ERROR; - goto error; - } - time = updatedTime; - - const TimeZoneRule *toRule = tzt.getTo(); - for (i = 0; i < ruleCount; i++) { - r = (TimeZoneRule*)orgRules->elementAt(i); - if (*r == *toRule) { - break; - } - } - if (i >= ruleCount) { - // This case should never happen - status = U_INVALID_STATE_ERROR; - goto error; - } - if (done[i]) { - continue; - } - const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule); - const AnnualTimeZoneRule *ar; - if (tar != NULL) { - // Get the previous raw offset and DST savings before the very first start time - TimeZoneTransition tzt0; - t = start; - while (TRUE) { - avail = getNextTransition(t, FALSE, tzt0); - if (!avail) { - break; - } - if (*(tzt0.getTo()) == *tar) { - break; - } - t = tzt0.getTime(); - } - if (avail) { - // Check if the entire start times to be added - tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); - if (firstStart > start) { - // Just add the rule as is - filteredRules->addElement(tar->clone(), status); - if (U_FAILURE(status)) { - goto error; - } - } else { - // Colllect transitions after the start time - int32_t startTimes; - DateTimeRule::TimeRuleType timeType; - int32_t idx; - - startTimes = tar->countStartTimes(); - timeType = tar->getTimeType(); - for (idx = 0; idx < startTimes; idx++) { - tar->getStartTimeAt(idx, t); - if (timeType == DateTimeRule::STANDARD_TIME) { - t -= tzt.getFrom()->getRawOffset(); - } - if (timeType == DateTimeRule::WALL_TIME) { - t -= tzt.getFrom()->getDSTSavings(); - } - if (t > start) { - break; - } - } - int32_t asize = startTimes - idx; - if (asize > 0) { - newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize); - if (newTimes == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - goto error; - } - for (int32_t newidx = 0; newidx < asize; newidx++) { - tar->getStartTimeAt(idx + newidx, newTimes[newidx]); - if (U_FAILURE(status)) { - uprv_free(newTimes); - newTimes = NULL; - goto error; - } - } - tar->getName(name); - TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name, - tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType); - uprv_free(newTimes); - filteredRules->addElement(newTar, status); - if (U_FAILURE(status)) { - goto error; - } - } - } - } - } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) { - ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); - if (firstStart == tzt.getTime()) { - // Just add the rule as is - filteredRules->addElement(ar->clone(), status); - if (U_FAILURE(status)) { - goto error; - } - } else { - // Calculate the transition year - int32_t year, month, dom, dow, doy, mid; - Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid); - // Re-create the rule - ar->getName(name); - AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(), - *(ar->getRule()), year, ar->getEndYear()); - filteredRules->addElement(newAr, status); - if (U_FAILURE(status)) { - goto error; - } - } - // check if this is a final rule - if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) { - // After bot final standard and dst rules are processed, - // exit this while loop. - if (ar->getDSTSavings() == 0) { - bFinalStd = TRUE; - } else { - bFinalDst = TRUE; - } - } - } - done[i] = TRUE; - } - - // Set the results - if (orgRules != NULL) { - while (!orgRules->isEmpty()) { - r = (TimeZoneRule*)orgRules->orphanElementAt(0); - delete r; - } - delete orgRules; - } - if (done != NULL) { - uprv_free(done); - } - - initial = res_initial; - transitionRules = filteredRules; - return; - -error: - if (orgtrs != NULL) { - uprv_free(orgtrs); - } - if (orgRules != NULL) { - while (!orgRules->isEmpty()) { - r = (TimeZoneRule*)orgRules->orphanElementAt(0); - delete r; - } - delete orgRules; - } - if (done != NULL) { - if (filteredRules != NULL) { - while (!filteredRules->isEmpty()) { - r = (TimeZoneRule*)filteredRules->orphanElementAt(0); - delete r; - } - delete filteredRules; - } - delete res_initial; - uprv_free(done); - } - - initial = NULL; - transitionRules = NULL; -} - -void -BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/, - int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) const { - if (U_FAILURE(status)) { - return; - } - status = U_UNSUPPORTED_ERROR; -} - -U_NAMESPACE_END - -#endif /* #if !UCONFIG_NO_FORMATTING */ - -//eof +// License & terms of use: http://www.unicode.org/copyright.html +/* +******************************************************************************* +* Copyright (C) 2007-2013, International Business Machines Corporation and +* others. All Rights Reserved. +******************************************************************************* +*/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "unicode/basictz.h" +#include "gregoimp.h" +#include "uvector.h" +#include "cmemory.h" + +U_NAMESPACE_BEGIN + +#define MILLIS_PER_YEAR (365*24*60*60*1000.0) + +BasicTimeZone::BasicTimeZone() +: TimeZone() { +} + +BasicTimeZone::BasicTimeZone(const UnicodeString &id) +: TimeZone(id) { +} + +BasicTimeZone::BasicTimeZone(const BasicTimeZone& source) +: TimeZone(source) { +} + +BasicTimeZone::~BasicTimeZone() { +} + +UBool +BasicTimeZone::hasEquivalentTransitions(const BasicTimeZone& tz, UDate start, UDate end, + UBool ignoreDstAmount, UErrorCode& status) const { + if (U_FAILURE(status)) { + return FALSE; + } + if (hasSameRules(tz)) { + return TRUE; + } + // Check the offsets at the start time + int32_t raw1, raw2, dst1, dst2; + getOffset(start, FALSE, raw1, dst1, status); + if (U_FAILURE(status)) { + return FALSE; + } + tz.getOffset(start, FALSE, raw2, dst2, status); + if (U_FAILURE(status)) { + return FALSE; + } + if (ignoreDstAmount) { + if ((raw1 + dst1 != raw2 + dst2) + || (dst1 != 0 && dst2 == 0) + || (dst1 == 0 && dst2 != 0)) { + return FALSE; + } + } else { + if (raw1 != raw2 || dst1 != dst2) { + return FALSE; + } + } + // Check transitions in the range + UDate time = start; + TimeZoneTransition tr1, tr2; + while (TRUE) { + UBool avail1 = getNextTransition(time, FALSE, tr1); + UBool avail2 = tz.getNextTransition(time, FALSE, tr2); + + if (ignoreDstAmount) { + // Skip a transition which only differ the amount of DST savings + while (TRUE) { + if (avail1 + && tr1.getTime() <= end + && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings() + == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()) + && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) { + getNextTransition(tr1.getTime(), FALSE, tr1); + } else { + break; + } + } + while (TRUE) { + if (avail2 + && tr2.getTime() <= end + && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings() + == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()) + && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) { + tz.getNextTransition(tr2.getTime(), FALSE, tr2); + } else { + break; + } + } + } + + UBool inRange1 = (avail1 && tr1.getTime() <= end); + UBool inRange2 = (avail2 && tr2.getTime() <= end); + if (!inRange1 && !inRange2) { + // No more transition in the range + break; + } + if (!inRange1 || !inRange2) { + return FALSE; + } + if (tr1.getTime() != tr2.getTime()) { + return FALSE; + } + if (ignoreDstAmount) { + if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings() + != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings() + || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0) + || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) { + return FALSE; + } + } else { + if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() || + tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) { + return FALSE; + } + } + time = tr1.getTime(); + } + return TRUE; +} + +void +BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial, + AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) const { + initial = NULL; + std = NULL; + dst = NULL; + if (U_FAILURE(status)) { + return; + } + int32_t initialRaw, initialDst; + UnicodeString initialName; + + AnnualTimeZoneRule *ar1 = NULL; + AnnualTimeZoneRule *ar2 = NULL; + UnicodeString name; + + UBool avail; + TimeZoneTransition tr; + // Get the next transition + avail = getNextTransition(date, FALSE, tr); + if (avail) { + tr.getFrom()->getName(initialName); + initialRaw = tr.getFrom()->getRawOffset(); + initialDst = tr.getFrom()->getDSTSavings(); + + // Check if the next transition is either DST->STD or STD->DST and + // within roughly 1 year from the specified date + UDate nextTransitionTime = tr.getTime(); + if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) + || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) + && (date + MILLIS_PER_YEAR > nextTransitionTime)) { + + int32_t year, month, dom, dow, doy, mid; + UDate d; + + // Get local wall time for the next transition time + Grego::timeToFields(nextTransitionTime + initialRaw + initialDst, + year, month, dom, dow, doy, mid); + int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); + // Create DOW rule + DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); + tr.getTo()->getName(name); + + // Note: SimpleTimeZone does not support raw offset change. + // So we always use raw offset of the given time for the rule, + // even raw offset is changed. This will result that the result + // zone to return wrong offset after the transition. + // When we encounter such case, we do not inspect next next + // transition for another rule. + ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(), + dtr, year, AnnualTimeZoneRule::MAX_YEAR); + + if (tr.getTo()->getRawOffset() == initialRaw) { + // Get the next next transition + avail = getNextTransition(nextTransitionTime, FALSE, tr); + if (avail) { + // Check if the next next transition is either DST->STD or STD->DST + // and within roughly 1 year from the next transition + if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) + || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) + && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) { + + // Get local wall time for the next transition time + Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), + year, month, dom, dow, doy, mid); + weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); + // Generate another DOW rule + dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); + tr.getTo()->getName(name); + ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(), + dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR); + + // Make sure this rule can be applied to the specified date + avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d); + if (!avail || d > date + || initialRaw != tr.getTo()->getRawOffset() + || initialDst != tr.getTo()->getDSTSavings()) { + // We cannot use this rule as the second transition rule + delete ar2; + ar2 = NULL; + } + } + } + } + if (ar2 == NULL) { + // Try previous transition + avail = getPreviousTransition(date, TRUE, tr); + if (avail) { + // Check if the previous transition is either DST->STD or STD->DST. + // The actual transition time does not matter here. + if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0) + || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) { + + // Generate another DOW rule + Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(), + year, month, dom, dow, doy, mid); + weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); + dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); + tr.getTo()->getName(name); + + // second rule raw/dst offsets should match raw/dst offsets + // at the given time + ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst, + dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR); + + // Check if this rule start after the first rule after the specified date + avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d); + if (!avail || d <= nextTransitionTime) { + // We cannot use this rule as the second transition rule + delete ar2; + ar2 = NULL; + } + } + } + } + if (ar2 == NULL) { + // Cannot find a good pair of AnnualTimeZoneRule + delete ar1; + ar1 = NULL; + } else { + // The initial rule should represent the rule before the previous transition + ar1->getName(initialName); + initialRaw = ar1->getRawOffset(); + initialDst = ar1->getDSTSavings(); + } + } + } + else { + // Try the previous one + avail = getPreviousTransition(date, TRUE, tr); + if (avail) { + tr.getTo()->getName(initialName); + initialRaw = tr.getTo()->getRawOffset(); + initialDst = tr.getTo()->getDSTSavings(); + } else { + // No transitions in the past. Just use the current offsets + getOffset(date, FALSE, initialRaw, initialDst, status); + if (U_FAILURE(status)) { + return; + } + } + } + // Set the initial rule + initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst); + + // Set the standard and daylight saving rules + if (ar1 != NULL && ar2 != NULL) { + if (ar1->getDSTSavings() != 0) { + dst = ar1; + std = ar2; + } else { + std = ar1; + dst = ar2; + } + } +} + +void +BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, + UVector*& transitionRules, UErrorCode& status) const { + if (U_FAILURE(status)) { + return; + } + + const InitialTimeZoneRule *orgini; + const TimeZoneRule **orgtrs = NULL; + TimeZoneTransition tzt; + UBool avail; + UVector *orgRules = NULL; + int32_t ruleCount; + TimeZoneRule *r = NULL; + UBool *done = NULL; + InitialTimeZoneRule *res_initial = NULL; + UVector *filteredRules = NULL; + UnicodeString name; + int32_t i; + UDate time, t; + UDate *newTimes = NULL; + UDate firstStart; + UBool bFinalStd = FALSE, bFinalDst = FALSE; + + // Original transition rules + ruleCount = countTransitionRules(status); + if (U_FAILURE(status)) { + return; + } + orgRules = new UVector(ruleCount, status); + if (U_FAILURE(status)) { + return; + } + orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount); + if (orgtrs == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + goto error; + } + getTimeZoneRules(orgini, orgtrs, ruleCount, status); + if (U_FAILURE(status)) { + goto error; + } + for (i = 0; i < ruleCount; i++) { + orgRules->addElement(orgtrs[i]->clone(), status); + if (U_FAILURE(status)) { + goto error; + } + } + uprv_free(orgtrs); + orgtrs = NULL; + + avail = getPreviousTransition(start, TRUE, tzt); + if (!avail) { + // No need to filter out rules only applicable to time before the start + initial = orgini->clone(); + transitionRules = orgRules; + return; + } + + done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount); + if (done == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + goto error; + } + filteredRules = new UVector(status); + if (U_FAILURE(status)) { + goto error; + } + + // Create initial rule + tzt.getTo()->getName(name); + res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(), + tzt.getTo()->getDSTSavings()); + + // Mark rules which does not need to be processed + for (i = 0; i < ruleCount; i++) { + r = (TimeZoneRule*)orgRules->elementAt(i); + avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time); + done[i] = !avail; + } + + time = start; + while (!bFinalStd || !bFinalDst) { + avail = getNextTransition(time, FALSE, tzt); + if (!avail) { + break; + } + UDate updatedTime = tzt.getTime(); + if (updatedTime == time) { + // Can get here if rules for start & end of daylight time have exactly + // the same time. + // TODO: fix getNextTransition() to prevent it? + status = U_INVALID_STATE_ERROR; + goto error; + } + time = updatedTime; + + const TimeZoneRule *toRule = tzt.getTo(); + for (i = 0; i < ruleCount; i++) { + r = (TimeZoneRule*)orgRules->elementAt(i); + if (*r == *toRule) { + break; + } + } + if (i >= ruleCount) { + // This case should never happen + status = U_INVALID_STATE_ERROR; + goto error; + } + if (done[i]) { + continue; + } + const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule); + const AnnualTimeZoneRule *ar; + if (tar != NULL) { + // Get the previous raw offset and DST savings before the very first start time + TimeZoneTransition tzt0; + t = start; + while (TRUE) { + avail = getNextTransition(t, FALSE, tzt0); + if (!avail) { + break; + } + if (*(tzt0.getTo()) == *tar) { + break; + } + t = tzt0.getTime(); + } + if (avail) { + // Check if the entire start times to be added + tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); + if (firstStart > start) { + // Just add the rule as is + filteredRules->addElement(tar->clone(), status); + if (U_FAILURE(status)) { + goto error; + } + } else { + // Colllect transitions after the start time + int32_t startTimes; + DateTimeRule::TimeRuleType timeType; + int32_t idx; + + startTimes = tar->countStartTimes(); + timeType = tar->getTimeType(); + for (idx = 0; idx < startTimes; idx++) { + tar->getStartTimeAt(idx, t); + if (timeType == DateTimeRule::STANDARD_TIME) { + t -= tzt.getFrom()->getRawOffset(); + } + if (timeType == DateTimeRule::WALL_TIME) { + t -= tzt.getFrom()->getDSTSavings(); + } + if (t > start) { + break; + } + } + int32_t asize = startTimes - idx; + if (asize > 0) { + newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize); + if (newTimes == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + goto error; + } + for (int32_t newidx = 0; newidx < asize; newidx++) { + tar->getStartTimeAt(idx + newidx, newTimes[newidx]); + if (U_FAILURE(status)) { + uprv_free(newTimes); + newTimes = NULL; + goto error; + } + } + tar->getName(name); + TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name, + tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType); + uprv_free(newTimes); + filteredRules->addElement(newTar, status); + if (U_FAILURE(status)) { + goto error; + } + } + } + } + } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) { + ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); + if (firstStart == tzt.getTime()) { + // Just add the rule as is + filteredRules->addElement(ar->clone(), status); + if (U_FAILURE(status)) { + goto error; + } + } else { + // Calculate the transition year + int32_t year, month, dom, dow, doy, mid; + Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid); + // Re-create the rule + ar->getName(name); + AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(), + *(ar->getRule()), year, ar->getEndYear()); + filteredRules->addElement(newAr, status); + if (U_FAILURE(status)) { + goto error; + } + } + // check if this is a final rule + if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) { + // After bot final standard and dst rules are processed, + // exit this while loop. + if (ar->getDSTSavings() == 0) { + bFinalStd = TRUE; + } else { + bFinalDst = TRUE; + } + } + } + done[i] = TRUE; + } + + // Set the results + if (orgRules != NULL) { + while (!orgRules->isEmpty()) { + r = (TimeZoneRule*)orgRules->orphanElementAt(0); + delete r; + } + delete orgRules; + } + if (done != NULL) { + uprv_free(done); + } + + initial = res_initial; + transitionRules = filteredRules; + return; + +error: + if (orgtrs != NULL) { + uprv_free(orgtrs); + } + if (orgRules != NULL) { + while (!orgRules->isEmpty()) { + r = (TimeZoneRule*)orgRules->orphanElementAt(0); + delete r; + } + delete orgRules; + } + if (done != NULL) { + if (filteredRules != NULL) { + while (!filteredRules->isEmpty()) { + r = (TimeZoneRule*)filteredRules->orphanElementAt(0); + delete r; + } + delete filteredRules; + } + delete res_initial; + uprv_free(done); + } + + initial = NULL; + transitionRules = NULL; +} + +void +BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/, + int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) const { + if (U_FAILURE(status)) { + return; + } + status = U_UNSUPPORTED_ERROR; +} + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ + +//eof |