]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/olsontz.cpp
ICU-64260.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / olsontz.cpp
index b9b2e0507d8be2f556728807bfdda2b346f3bf6f..7f9fe4370b494963eff34d8a72fc54ccbd11704e 100644 (file)
@@ -1,6 +1,8 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 **********************************************************************
-* Copyright (c) 2003-2010, International Business Machines
+* Copyright (c) 2003-2013, International Business Machines
 * Corporation and others.  All Rights Reserved.
 **********************************************************************
 * Author: Alan Liu
@@ -9,7 +11,7 @@
 **********************************************************************
 */
 
-#include <typeinfo>  // for 'typeid' to work
+#include "utypeinfo.h"  // for 'typeid' to work
 
 #include "olsontz.h"
 
@@ -23,7 +25,9 @@
 #include "uassert.h"
 #include "uvector.h"
 #include <float.h> // DBL_MAX
-#include "uresimp.h" // struct UResourceBundle
+#include "uresimp.h"
+#include "zonemeta.h"
+#include "umutex.h"
 
 #ifdef U_DEBUG_TZ
 # include <stdio.h>
@@ -93,6 +97,8 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
  * constructor fails so the resultant object is well-behaved.
  */
 void OlsonTimeZone::constructEmpty() {
+    canonicalID = NULL;
+
     transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
     transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
 
@@ -113,8 +119,9 @@ void OlsonTimeZone::constructEmpty() {
  */
 OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
                              const UResourceBundle* res,
+                             const UnicodeString& tzid,
                              UErrorCode& ec) :
-  finalZone(NULL), transitionRulesInitialized(FALSE)
+  BasicTimeZone(tzid), finalZone(NULL)
 {
     clearTransitionRules();
     U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
@@ -127,13 +134,12 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
         //        setID(ures_getKey((UResourceBundle*) res)); // cast away const
 
         int32_t len;
-        UResourceBundle r;
-        ures_initStackObject(&r);
+        StackUResourceBundle r;
 
         // Pre-32bit second transitions
-        ures_getByKey(res, kTRANSPRE32, &r, &ec);
-        transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
-        transitionCountPre32 = len >> 1;
+        ures_getByKey(res, kTRANSPRE32, r.getAlias(), &ec);
+        transitionTimesPre32 = ures_getIntVector(r.getAlias(), &len, &ec);
+        transitionCountPre32 = static_cast<int16_t>(len >> 1);
         if (ec == U_MISSING_RESOURCE_ERROR) {
             // No pre-32bit transitions
             transitionTimesPre32 = NULL;
@@ -144,9 +150,9 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
         }
 
         // 32bit second transitions
-        ures_getByKey(res, kTRANS, &r, &ec);
-        transitionTimes32 = ures_getIntVector(&r, &len, &ec);
-        transitionCount32 = len;
+        ures_getByKey(res, kTRANS, r.getAlias(), &ec);
+        transitionTimes32 = ures_getIntVector(r.getAlias(), &len, &ec);
+        transitionCount32 = static_cast<int16_t>(len);
         if (ec == U_MISSING_RESOURCE_ERROR) {
             // No 32bit transitions
             transitionTimes32 = NULL;
@@ -157,9 +163,9 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
         }
 
         // Post-32bit second transitions
-        ures_getByKey(res, kTRANSPOST32, &r, &ec);
-        transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
-        transitionCountPost32 = len >> 1;
+        ures_getByKey(res, kTRANSPOST32, r.getAlias(), &ec);
+        transitionTimesPost32 = ures_getIntVector(r.getAlias(), &len, &ec);
+        transitionCountPost32 = static_cast<int16_t>(len >> 1);
         if (ec == U_MISSING_RESOURCE_ERROR) {
             // No pre-32bit transitions
             transitionTimesPost32 = NULL;
@@ -170,8 +176,8 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
         }
 
         // Type offsets list must be of even size, with size >= 2
-        ures_getByKey(res, kTYPEOFFSETS, &r, &ec);
-        typeOffsets = ures_getIntVector(&r, &len, &ec);
+        ures_getByKey(res, kTYPEOFFSETS, r.getAlias(), &ec);
+        typeOffsets = ures_getIntVector(r.getAlias(), &len, &ec);
         if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
             ec = U_INVALID_FORMAT_ERROR;
         }
@@ -180,8 +186,8 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
         // Type map data must be of the same size as the transition count
         typeMapData =  NULL;
         if (transitionCount() > 0) {
-            ures_getByKey(res, kTYPEMAP, &r, &ec);
-            typeMapData = ures_getBinary(&r, &len, &ec);
+            ures_getByKey(res, kTYPEMAP, r.getAlias(), &ec);
+            typeMapData = ures_getBinary(r.getAlias(), &len, &ec);
             if (ec == U_MISSING_RESOURCE_ERROR) {
                 // no type mapping data
                 ec = U_INVALID_FORMAT_ERROR;
@@ -192,10 +198,10 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
 
         // Process final rule and data, if any
         const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
-        ures_getByKey(res, kFINALRAW, &r, &ec);
-        int32_t ruleRaw = ures_getInt(&r, &ec);
-        ures_getByKey(res, kFINALYEAR, &r, &ec);
-        int32_t ruleYear = ures_getInt(&r, &ec);
+        ures_getByKey(res, kFINALRAW, r.getAlias(), &ec);
+        int32_t ruleRaw = ures_getInt(r.getAlias(), &ec);
+        ures_getByKey(res, kFINALYEAR, r.getAlias(), &ec);
+        int32_t ruleYear = ures_getInt(r.getAlias(), &ec);
         if (U_SUCCESS(ec)) {
             UnicodeString ruleID(TRUE, ruleIdUStr, len);
             UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec);
@@ -244,7 +250,9 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
             // No final zone
             ec = U_ZERO_ERROR;
         }
-        ures_close(&r);
+
+        // initialize canonical ID
+        canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
     }
 
     if (U_FAILURE(ec)) {
@@ -264,6 +272,8 @@ OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
  * Assignment operator
  */
 OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
+    canonicalID = other.canonicalID;
+
     transitionTimesPre32 = other.transitionTimesPre32;
     transitionTimes32 = other.transitionTimes32;
     transitionTimesPost32 = other.transitionTimesPost32;
@@ -390,7 +400,7 @@ void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
 
 void
 OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
-                                  int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/ {
+                                  int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const {
     if (U_FAILURE(ec)) {
         return;
     }
@@ -454,6 +464,11 @@ OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const {
         | ((int64_t)((uint32_t)transitionTimesPost32[(transIdx << 1) + 1]));
 }
 
+// Maximum absolute offset in seconds (86400 seconds = 1 day)
+// getHistoricalOffset uses this constant as safety margin of
+// quick zone transition checking.
+#define MAX_OFFSET_SECONDS 86400
+
 void
 OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
                                    int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
@@ -478,7 +493,7 @@ OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
             for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
                 int64_t transition = transitionTimeInSeconds(transIdx);
 
-                if (local) {
+                if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) {
                     int32_t offsetBefore = zoneOffsetAt(transIdx - 1);
                     UBool dstBefore = dstOffsetAt(transIdx - 1) != 0;
 
@@ -562,7 +577,7 @@ UBool OlsonTimeZone::useDaylightTime() const {
     // Return TRUE if DST is observed at any time during the current
     // year.
     for (int16_t i = 0; i < transitionCount(); ++i) {
-        double transition = transitionTime(i);
+        double transition = (double)transitionTimeInSeconds(i);
         if (transition >= limit) {
             break;
         }
@@ -643,7 +658,7 @@ OlsonTimeZone::clearTransitionRules(void) {
     historicRuleCount = 0;
     finalZoneWithStartYear = NULL;
     firstTZTransitionIdx = 0;
-    transitionRulesInitialized = FALSE;
+    transitionRulesInitOnce.reset();
 }
 
 void
@@ -671,14 +686,25 @@ OlsonTimeZone::deleteTransitionRules(void) {
     clearTransitionRules();
 }
 
+/*
+ * Lazy transition rules initializer
+ */
+
+static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) {
+    This->initTransitionRules(status);
+}
+    
+void
+OlsonTimeZone::checkTransitionRules(UErrorCode& status) const {
+    OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this);
+    umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status);
+}
+
 void
 OlsonTimeZone::initTransitionRules(UErrorCode& status) {
     if(U_FAILURE(status)) {
         return;
     }
-    if (transitionRulesInitialized) {
-        return;
-    }
     deleteTransitionRules();
     UnicodeString tzid;
     getID(tzid);
@@ -847,13 +873,12 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
         firstFinalTZTransition->adoptFrom(prevRule->clone());
         firstFinalTZTransition->adoptTo(firstFinalRule);
     }
-    transitionRulesInitialized = TRUE;
 }
 
 UBool
-OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     UErrorCode status = U_ZERO_ERROR;
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return FALSE;
     }
@@ -916,9 +941,9 @@ OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition
 }
 
 UBool
-OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     UErrorCode status = U_ZERO_ERROR;
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return FALSE;
     }
@@ -977,11 +1002,11 @@ OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransi
 }
 
 int32_t
-OlsonTimeZone::countTransitionRules(UErrorCode& status) /*const*/ {
+OlsonTimeZone::countTransitionRules(UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return 0;
     }
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return 0;
     }
@@ -1010,11 +1035,11 @@ void
 OlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
                                 const TimeZoneRule* trsrules[],
                                 int32_t& trscount,
-                                UErrorCode& status) /*const*/ {
+                                UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
-    initTransitionRules(status);
+    checkTransitionRules(status);
     if (U_FAILURE(status)) {
         return;
     }