+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
- * Copyright (C) 1997-2008, International Business Machines Corporation and *
- * others. All Rights Reserved. *
+ * Copyright (C) 1997-2013, International Business Machines Corporation and
+ * others. All Rights Reserved.
*******************************************************************************
*
* File SIMPLETZ.H
********************************************************************************
*/
+#include "utypeinfo.h" // for 'typeid' to work
+
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/smpdtfmt.h"
#include "gregoimp.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
decodeRules(status);
- if (savingsDST <= 0) {
+ if (savingsDST == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
}
SimpleTimeZone::operator==(const TimeZone& that) const
{
return ((this == &that) ||
- (getDynamicClassID() == that.getDynamicClassID() &&
+ (typeid(*this) == typeid(that) &&
TimeZone::operator==(that) &&
hasSameRules(that)));
}
void
SimpleTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
- int32_t& rawOffsetGMT, int32_t& savingsDST, UErrorCode& status) /*const*/ {
+ int32_t& rawOffsetGMT, int32_t& savingsDST, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
// Now we need some adjustment
if (savingsDST > 0) {
if ((nonExistingTimeOpt & kStdDstMask) == kStandard
- || (nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter) {
+ || ((nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter)) {
date -= getDSTSavings();
recalc = TRUE;
}
} else {
if ((duplicatedTimeOpt & kStdDstMask) == kDaylight
- || (duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer) {
+ || ((duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer)) {
date -= getDSTSavings();
recalc = TRUE;
}
void
SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
{
- if (millisSavedDuringDST <= 0) {
+ if (millisSavedDuringDST == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
else {
SimpleTimeZone::hasSameRules(const TimeZone& other) const
{
if (this == &other) return TRUE;
- if (other.getDynamicClassID() != SimpleTimeZone::getStaticClassID()) return FALSE;
+ if (typeid(*this) != typeid(other)) return FALSE;
SimpleTimeZone *that = (SimpleTimeZone*)&other;
return rawOffset == that->rawOffset &&
useDaylight == that->useDaylight &&
}
UBool
-SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
- if (startMonth == 0) {
+SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
+ if (!useDaylight) {
return FALSE;
}
UErrorCode status = U_ZERO_ERROR;
- initTransitionRules(status);
+ checkTransitionRules(status);
if (U_FAILURE(status)) {
return FALSE;
}
}
UBool
-SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
- if (startMonth == 0) {
+SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
+ if (!useDaylight) {
return FALSE;
}
UErrorCode status = U_ZERO_ERROR;
- initTransitionRules(status);
+ checkTransitionRules(status);
if (U_FAILURE(status)) {
return FALSE;
}
clearTransitionRules();
}
+/*
+ * Lazy transition rules initializer
+ *
+ * Note On the removal of UMTX_CHECK from checkTransitionRules():
+ *
+ * It would be faster to have a UInitOnce as part of a SimpleTimeZone object,
+ * which would avoid needing to lock a mutex to check the initialization state.
+ * But we can't easily because simpletz.h is a public header, and including
+ * a UInitOnce as a member of SimpleTimeZone would publicly expose internal ICU headers.
+ *
+ * Alternatively we could have a pointer to a UInitOnce in the SimpleTimeZone object,
+ * allocate it in the constructors. This would be a more intrusive change, but doable
+ * if performance turns out to be an issue.
+ */
+static UMutex gLock = U_MUTEX_INITIALIZER;
+
+void
+SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ umtx_lock(&gLock);
+ if (!transitionRulesInitialized) {
+ SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
+ ncThis->initTransitionRules(status);
+ }
+ umtx_unlock(&gLock);
+}
+
void
SimpleTimeZone::initTransitionRules(UErrorCode& status) {
if (U_FAILURE(status)) {
UnicodeString tzid;
getID(tzid);
- if (startMonth != 0) {
+ if (useDaylight) {
DateTimeRule* dtRule;
DateTimeRule::TimeRuleType timeRuleType;
UDate firstStdStart, firstDstStart;
}
// Check for Null pointer
if (dtRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
}
// For now, use ID + "(DST)" as the name
- dstRule = new AnnualTimeZoneRule(tzid+DST_STR, getRawOffset(), getDSTSavings(),
+ dstRule = new AnnualTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), getDSTSavings(),
dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
// Check for Null pointer
if (dstRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
}
// Calculate the first DST start time
// Check for Null pointer
if (dtRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
}
// For now, use ID + "(STD)" as the name
- stdRule = new AnnualTimeZoneRule(tzid+STD_STR, getRawOffset(), 0,
+ stdRule = new AnnualTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0,
dtRule, startYear, AnnualTimeZoneRule::MAX_YEAR);
//Check for Null pointer
if (stdRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
}
// Calculate the first STD start time
// Create a TimeZoneRule for initial time
if (firstStdStart < firstDstStart) {
- initialRule = new InitialTimeZoneRule(tzid+DST_STR, getRawOffset(), dstRule->getDSTSavings());
+ initialRule = new InitialTimeZoneRule(tzid+UnicodeString(DST_STR), getRawOffset(), dstRule->getDSTSavings());
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
firstTransition = new TimeZoneTransition(firstStdStart, *initialRule, *stdRule);
} else {
- initialRule = new InitialTimeZoneRule(tzid+STD_STR, getRawOffset(), 0);
+ initialRule = new InitialTimeZoneRule(tzid+UnicodeString(STD_STR), getRawOffset(), 0);
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
firstTransition = new TimeZoneTransition(firstDstStart, *initialRule, *dstRule);
}
- // Check for null pointers.
- if (initialRule == NULL || firstTransition == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
+ if (firstTransition == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
}
} else {
initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
// Check for null pointer.
if (initialRule == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- deleteTransitionRules();
- return;
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
}
}
- transitionRulesInitialized = true;
+ transitionRulesInitialized = TRUE;
}
int32_t
-SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) /*const*/ {
- return (startMonth == 0) ? 0 : 2;
+SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
+ return (useDaylight) ? 2 : 0;
}
void
SimpleTimeZone::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;
}