+// © 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
**********************************************************************
*/
-#include <typeinfo> // for 'typeid' to work
+#include "utypeinfo.h" // for 'typeid' to work
#include "olsontz.h"
#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>
* constructor fails so the resultant object is well-behaved.
*/
void OlsonTimeZone::constructEmpty() {
+ canonicalID = NULL;
+
transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
*/
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)));
// 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;
}
// 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;
}
// 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;
}
// 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;
}
// 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;
// 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);
// No final zone
ec = U_ZERO_ERROR;
}
- ures_close(&r);
+
+ // initialize canonical ID
+ canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
}
if (U_FAILURE(ec)) {
* Assignment operator
*/
OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
+ canonicalID = other.canonicalID;
+
transitionTimesPre32 = other.transitionTimesPre32;
transitionTimes32 = other.transitionTimes32;
transitionTimesPost32 = other.transitionTimesPost32;
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;
}
| ((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,
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;
// 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;
}
historicRuleCount = 0;
finalZoneWithStartYear = NULL;
firstTZTransitionIdx = 0;
- transitionRulesInitialized = FALSE;
+ transitionRulesInitOnce.reset();
}
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);
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;
}
}
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;
}
}
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;
}
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;
}