]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/rbtz.cpp
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / rbtz.cpp
index 848ab845e492ca1b7b638cd69be7cdc6dcc1c6b2..5f3addce313101a20e5f298a42b5489203cbd2e3 100644 (file)
@@ -1,10 +1,12 @@
 /*
 *******************************************************************************
-* Copyright (C) 2007-2008, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
+* Copyright (C) 2007-2013, International Business Machines Corporation and
+* others. All Rights Reserved.
 *******************************************************************************
 */
 
+#include "utypeinfo.h"  // for 'typeid' to work
+
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
@@ -14,6 +16,7 @@
 #include "uvector.h"
 #include "gregoimp.h"
 #include "cmemory.h"
+#include "umutex.h"
 
 U_NAMESPACE_BEGIN
 
@@ -88,7 +91,7 @@ RuleBasedTimeZone::operator==(const TimeZone& that) const {
     if (this == &that) {
         return TRUE;
     }
-    if (getDynamicClassID() != that.getDynamicClassID()
+    if (typeid(*this) != typeid(that)
         || BasicTimeZone::operator==(that) == FALSE) {
         return FALSE;
     }
@@ -113,8 +116,8 @@ RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
     if (U_FAILURE(status)) {
         return;
     }
-    if (rule->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()
-        && ((AnnualTimeZoneRule*)rule)->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+    AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule);
+    if (atzrule != NULL && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
         // A final rule
         if (fFinalRules == NULL) {
             fFinalRules = new UVector(status);
@@ -141,6 +144,21 @@ RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
     fUpToDate = FALSE;
 }
 
+static UMutex gLock = U_MUTEX_INITIALIZER;
+
+void
+RuleBasedTimeZone::completeConst(UErrorCode& status) const {
+    if (U_FAILURE(status)) {
+        return;
+    }
+    umtx_lock(&gLock);
+    if (!fUpToDate) {
+        RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
+        ncThis->complete(status);
+    }
+    umtx_unlock(&gLock);
+}
+
 void
 RuleBasedTimeZone::complete(UErrorCode& status) {
     if (U_FAILURE(status)) {
@@ -385,7 +403,7 @@ RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
 
 void
 RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
-                                      int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ {
+                                      int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) const {
     getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status);
 }
 
@@ -426,8 +444,10 @@ RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local,
             if (date > tend) {
                 if (fFinalRules != NULL) {
                     rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt);
-                } else {
-                    // no final rule, use the last rule
+                }
+                if (rule == NULL) {
+                    // no final rules or the given time is before the first transition
+                    // specified by the final rules -> use the last rule 
                     rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
                 }
             } else {
@@ -506,7 +526,7 @@ RuleBasedTimeZone::hasSameRules(const TimeZone& other) const {
     if (this == &other) {
         return TRUE;
     }
-    if (getDynamicClassID() != other.getDynamicClassID()) {
+    if (typeid(*this) != typeid(other)) {
         return FALSE;
     }
     const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other;
@@ -521,9 +541,9 @@ RuleBasedTimeZone::hasSameRules(const TimeZone& other) const {
 }
 
 UBool
-RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     UErrorCode status = U_ZERO_ERROR;
-    complete(status);
+    completeConst(status);
     if (U_FAILURE(status)) {
         return FALSE;
     }
@@ -540,9 +560,9 @@ RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransi
 }
 
 UBool
-RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     UErrorCode status = U_ZERO_ERROR;
-    complete(status);
+    completeConst(status);
     if (U_FAILURE(status)) {
         return FALSE;
     }
@@ -559,7 +579,7 @@ RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTr
 }
 
 int32_t
-RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
+RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
     int32_t count = 0;
     if (fHistoricRules != NULL) {
         count += fHistoricRules->size();
@@ -574,7 +594,7 @@ void
 RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
                                     const TimeZoneRule* trsrules[],
                                     int32_t& trscount,
-                                    UErrorCode& status) /*const*/ {
+                                    UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
@@ -699,12 +719,17 @@ RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local,
     }
     UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1);
 
-    if (avail0 && (!avail1 || start0 > start1)) {
-        return fr0;
-    } else if (avail1) {
-        return fr1;
+    if (!avail0 || !avail1) {
+        if (avail0) {
+            return fr0;
+        } else if (avail1) {
+            return fr1;
+        }
+        // Both rules take effect after the given time
+        return NULL;
     }
-    return NULL;
+
+    return (start0 > start1) ? fr0 : fr1;
 }
 
 UBool