+UBool
+SimpleTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
+ if (!useDaylight) {
+ return FALSE;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ checkTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ UDate firstTransitionTime = firstTransition->getTime();
+ if (base < firstTransitionTime || (inclusive && base == firstTransitionTime)) {
+ result = *firstTransition;
+ }
+ UDate stdDate, dstDate;
+ UBool stdAvail = stdRule->getNextStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
+ UBool dstAvail = dstRule->getNextStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
+ if (stdAvail && (!dstAvail || stdDate < dstDate)) {
+ result.setTime(stdDate);
+ result.setFrom((const TimeZoneRule&)*dstRule);
+ result.setTo((const TimeZoneRule&)*stdRule);
+ return TRUE;
+ }
+ if (dstAvail && (!stdAvail || dstDate < stdDate)) {
+ result.setTime(dstDate);
+ result.setFrom((const TimeZoneRule&)*stdRule);
+ result.setTo((const TimeZoneRule&)*dstRule);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+UBool
+SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
+ if (!useDaylight) {
+ return FALSE;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ checkTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+
+ UDate firstTransitionTime = firstTransition->getTime();
+ if (base < firstTransitionTime || (!inclusive && base == firstTransitionTime)) {
+ return FALSE;
+ }
+ UDate stdDate, dstDate;
+ UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
+ UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
+ if (stdAvail && (!dstAvail || stdDate > dstDate)) {
+ result.setTime(stdDate);
+ result.setFrom((const TimeZoneRule&)*dstRule);
+ result.setTo((const TimeZoneRule&)*stdRule);
+ return TRUE;
+ }
+ if (dstAvail && (!stdAvail || dstDate > stdDate)) {
+ result.setTime(dstDate);
+ result.setFrom((const TimeZoneRule&)*stdRule);
+ result.setTo((const TimeZoneRule&)*dstRule);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+SimpleTimeZone::clearTransitionRules(void) {
+ initialRule = NULL;
+ firstTransition = NULL;
+ stdRule = NULL;
+ dstRule = NULL;
+ transitionRulesInitialized = FALSE;
+}
+
+void
+SimpleTimeZone::deleteTransitionRules(void) {
+ if (initialRule != NULL) {
+ delete initialRule;
+ }
+ if (firstTransition != NULL) {
+ delete firstTransition;
+ }
+ if (stdRule != NULL) {
+ delete stdRule;
+ }
+ if (dstRule != NULL) {
+ delete dstRule;
+ }
+ 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)) {
+ return;
+ }
+ if (transitionRulesInitialized) {
+ return;
+ }
+ deleteTransitionRules();
+ UnicodeString tzid;
+ getID(tzid);
+
+ if (useDaylight) {
+ DateTimeRule* dtRule;
+ DateTimeRule::TimeRuleType timeRuleType;
+ UDate firstStdStart, firstDstStart;
+
+ // Create a TimeZoneRule for daylight saving time
+ timeRuleType = (startTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
+ ((startTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
+ switch (startMode) {
+ case DOM_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startTime, timeRuleType);
+ break;
+ case DOW_IN_MONTH_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, startTime, timeRuleType);
+ break;
+ case DOW_GE_DOM_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, true, startTime, timeRuleType);
+ break;
+ case DOW_LE_DOM_MODE:
+ dtRule = new DateTimeRule(startMonth, startDay, startDayOfWeek, false, startTime, timeRuleType);
+ break;
+ default:
+ status = U_INVALID_STATE_ERROR;
+ return;
+ }
+ // Check for Null pointer
+ if (dtRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ // For now, use ID + "(DST)" as the name
+ 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;
+ }
+
+ // Calculate the first DST start time
+ dstRule->getFirstStart(getRawOffset(), 0, firstDstStart);
+
+ // Create a TimeZoneRule for standard time
+ timeRuleType = (endTimeMode == STANDARD_TIME) ? DateTimeRule::STANDARD_TIME :
+ ((endTimeMode == UTC_TIME) ? DateTimeRule::UTC_TIME : DateTimeRule::WALL_TIME);
+ switch (endMode) {
+ case DOM_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endTime, timeRuleType);
+ break;
+ case DOW_IN_MONTH_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, endTime, timeRuleType);
+ break;
+ case DOW_GE_DOM_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, true, endTime, timeRuleType);
+ break;
+ case DOW_LE_DOM_MODE:
+ dtRule = new DateTimeRule(endMonth, endDay, endDayOfWeek, false, endTime, timeRuleType);
+ break;
+ }
+
+ // Check for Null pointer
+ if (dtRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ // For now, use ID + "(STD)" as the name
+ 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;
+ }
+
+ // Calculate the first STD start time
+ stdRule->getFirstStart(getRawOffset(), dstRule->getDSTSavings(), firstStdStart);
+
+ // 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);
+ }
+ if (firstTransition == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+
+ } else {
+ // Create a TimeZoneRule for initial time
+ initialRule = new InitialTimeZoneRule(tzid, getRawOffset(), 0);
+ // Check for null pointer.
+ if (initialRule == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ deleteTransitionRules();
+ return;
+ }
+ }
+
+ transitionRulesInitialized = TRUE;
+}
+
+int32_t
+SimpleTimeZone::countTransitionRules(UErrorCode& /*status*/) const {
+ return (useDaylight) ? 2 : 0;
+}
+
+void
+SimpleTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
+ const TimeZoneRule* trsrules[],
+ int32_t& trscount,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ checkTransitionRules(status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ initial = initialRule;
+ int32_t cnt = 0;
+ if (stdRule != NULL) {
+ if (cnt < trscount) {
+ trsrules[cnt++] = stdRule;
+ }
+ if (cnt < trscount) {
+ trsrules[cnt++] = dstRule;
+ }
+ }
+ trscount = cnt;
+}
+
+