]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/basictz.cpp
ICU-461.12.tar.gz
[apple/icu.git] / icuSources / i18n / basictz.cpp
index fb36eefc65185d0e564dfd9c78280924317eb654..6b4889a216c888fee22f314307beca79295ecb60 100644 (file)
@@ -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<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;
@@ -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<const AnnualTimeZoneRule *>(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;
     }