X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/48b980fed3435926e0b3a8d72ecb58be703a1c7a..729e4ab9bc6618bc3d8a898e575df7f4019e29ca:/icuSources/i18n/basictz.cpp diff --git a/icuSources/i18n/basictz.cpp b/icuSources/i18n/basictz.cpp index fb36eefc..6b4889a2 100644 --- a/icuSources/i18n/basictz.cpp +++ b/icuSources/i18n/basictz.cpp @@ -1,7 +1,7 @@ /* ******************************************************************************* -* Copyright (C) 2007-2008, International Business Machines Corporation and * -* others. All Rights Reserved. * +* Copyright (C) 2007-2010, International Business Machines Corporation and +* others. All Rights Reserved. ******************************************************************************* */ @@ -72,17 +72,27 @@ BasicTimeZone::hasEquivalentTransitions(/*const*/ BasicTimeZone& tz, UDate start if (ignoreDstAmount) { // Skip a transition which only differ the amount of DST savings - if (avail1 - && (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); + 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; + } } - if (avail2 - && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings() - == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()) - && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) { - getNextTransition(tr2.getTime(), FALSE, tr2); + 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; + } } } @@ -101,8 +111,8 @@ BasicTimeZone::hasEquivalentTransitions(/*const*/ BasicTimeZone& tz, UDate start 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) { + || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0) + || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) { return FALSE; } } else { @@ -158,36 +168,45 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial, // Create DOW rule DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); tr.getTo()->getName(name); - ar1 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(), + + // 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); - // 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 (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; + } } } } @@ -206,7 +225,10 @@ BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial, weekInMonth = Grego::dayOfWeekInMonth(year, month, dom); dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME); tr.getTo()->getName(name); - ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(), + + // 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 @@ -348,7 +370,15 @@ BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, if (!avail) { break; } - time = tzt.getTime(); + 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++) { @@ -365,9 +395,9 @@ BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, if (done[i]) { continue; } - if (toRule->getDynamicClassID() == TimeArrayTimeZoneRule::getStaticClassID()) { - TimeArrayTimeZoneRule *tar = (TimeArrayTimeZoneRule*)toRule; - + const TimeArrayTimeZoneRule *tar = dynamic_cast(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; @@ -436,8 +466,7 @@ BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial, } } } - } else if (toRule->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) { - AnnualTimeZoneRule *ar = (AnnualTimeZoneRule*)toRule; + } else if ((ar = dynamic_cast(toRule)) != NULL) { ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart); if (firstStart == tzt.getTime()) { // Just add the rule as is @@ -500,6 +529,14 @@ error: 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); } @@ -508,8 +545,8 @@ error: } void -BasicTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, - int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ { +BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/, + int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) /*const*/ { if (U_FAILURE(status)) { return; }