+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
- * Copyright (C) 1997-2011, International Business Machines Corporation and
+ * Copyright (C) 1997-2013, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
********************************************************************************
*/
-#include <typeinfo> // for 'typeid' to work
+#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/utypes.h"
#include "unicode/gregocal.h"
#include "unicode/smpdtfmt.h"
+#include "cmemory.h"
#include "gregoimp.h"
+#include "umutex.h"
U_NAMESPACE_BEGIN
decodeRules(status);
- if (savingsDST <= 0) {
+ if (savingsDST == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
}
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;
}
void
SimpleTimeZone::setDSTSavings(int32_t millisSavedDuringDST, UErrorCode& status)
{
- if (millisSavedDuringDST <= 0) {
+ if (millisSavedDuringDST == 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
else {
}
UBool
-SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+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*/ {
+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.
+ */
+
+void
+SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ static UMutex *gLock = STATIC_NEW(UMutex);
+ 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)) {
}
// 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+UnicodeString(DST_STR), getRawOffset(), getDSTSavings(),
// 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+UnicodeString(STD_STR), getRawOffset(), 0,
//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+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+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*/ {
+SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
return (useDaylight) ? 2 : 0;
}
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;
}