Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / i18n / rbtz.cpp
index 530cf04..5f3addc 100644 (file)
@@ -1,11 +1,11 @@
 /*
 *******************************************************************************
-* Copyright (C) 2007-2010, International Business Machines Corporation and
+* Copyright (C) 2007-2013, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 */
 
-#include "unicode/utypeinfo.h"  // for 'typeid' to work
+#include "utypeinfo.h"  // for 'typeid' to work
 
 #include "unicode/utypes.h"
 
@@ -16,6 +16,7 @@
 #include "uvector.h"
 #include "gregoimp.h"
 #include "cmemory.h"
+#include "umutex.h"
 
 U_NAMESPACE_BEGIN
 
@@ -143,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)) {
@@ -387,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);
 }
 
@@ -428,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 {
@@ -523,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;
     }
@@ -542,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;
     }
@@ -561,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();
@@ -576,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;
     }
@@ -701,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