| Index: icu46/source/i18n/basictz.cpp
|
| ===================================================================
|
| --- icu46/source/i18n/basictz.cpp (revision 0)
|
| +++ icu46/source/i18n/basictz.cpp (revision 0)
|
| @@ -0,0 +1,560 @@
|
| +/*
|
| +*******************************************************************************
|
| +* Copyright (C) 2007-2010, International Business Machines Corporation and
|
| +* others. All Rights Reserved.
|
| +*******************************************************************************
|
| +*/
|
| +
|
| +#include "unicode/utypes.h"
|
| +
|
| +#if !UCONFIG_NO_FORMATTING
|
| +
|
| +#include "unicode/basictz.h"
|
| +#include "gregoimp.h"
|
| +#include "uvector.h"
|
| +#include "cmemory.h"
|
| +
|
| +U_NAMESPACE_BEGIN
|
| +
|
| +#define MILLIS_PER_YEAR (365*24*60*60*1000.0)
|
| +
|
| +BasicTimeZone::BasicTimeZone()
|
| +: TimeZone() {
|
| +}
|
| +
|
| +BasicTimeZone::BasicTimeZone(const UnicodeString &id)
|
| +: TimeZone(id) {
|
| +}
|
| +
|
| +BasicTimeZone::BasicTimeZone(const BasicTimeZone& source)
|
| +: TimeZone(source) {
|
| +}
|
| +
|
| +BasicTimeZone::~BasicTimeZone() {
|
| +}
|
| +
|
| +UBool
|
| +BasicTimeZone::hasEquivalentTransitions(/*const*/ BasicTimeZone& tz, UDate start, UDate end,
|
| + UBool ignoreDstAmount, UErrorCode& status) /*const*/ {
|
| + if (U_FAILURE(status)) {
|
| + return FALSE;
|
| + }
|
| + if (hasSameRules(tz)) {
|
| + return TRUE;
|
| + }
|
| + // Check the offsets at the start time
|
| + int32_t raw1, raw2, dst1, dst2;
|
| + getOffset(start, FALSE, raw1, dst1, status);
|
| + if (U_FAILURE(status)) {
|
| + return FALSE;
|
| + }
|
| + tz.getOffset(start, FALSE, raw2, dst2, status);
|
| + if (U_FAILURE(status)) {
|
| + return FALSE;
|
| + }
|
| + if (ignoreDstAmount) {
|
| + if ((raw1 + dst1 != raw2 + dst2)
|
| + || (dst1 != 0 && dst2 == 0)
|
| + || (dst1 == 0 && dst2 != 0)) {
|
| + return FALSE;
|
| + }
|
| + } else {
|
| + if (raw1 != raw2 || dst1 != dst2) {
|
| + return FALSE;
|
| + }
|
| + }
|
| + // Check transitions in the range
|
| + UDate time = start;
|
| + TimeZoneTransition tr1, tr2;
|
| + while (TRUE) {
|
| + UBool avail1 = getNextTransition(time, FALSE, tr1);
|
| + UBool avail2 = tz.getNextTransition(time, FALSE, tr2);
|
| +
|
| + if (ignoreDstAmount) {
|
| + // Skip a transition which only differ the amount of DST savings
|
| + while (TRUE) {
|
| + if (avail1
|
| + && tr1.getTime() <= end
|
| + && (tr1.getFrom()->getRawOffset() + tr1.getFrom()->getDSTSavings()
|
| + == tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings())
|
| + && (tr1.getFrom()->getDSTSavings() != 0 && tr1.getTo()->getDSTSavings() != 0)) {
|
| + getNextTransition(tr1.getTime(), FALSE, tr1);
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| + while (TRUE) {
|
| + if (avail2
|
| + && tr2.getTime() <= end
|
| + && (tr2.getFrom()->getRawOffset() + tr2.getFrom()->getDSTSavings()
|
| + == tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings())
|
| + && (tr2.getFrom()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() != 0)) {
|
| + tz.getNextTransition(tr2.getTime(), FALSE, tr2);
|
| + } else {
|
| + break;
|
| + }
|
| + }
|
| + }
|
| +
|
| + UBool inRange1 = (avail1 && tr1.getTime() <= end);
|
| + UBool inRange2 = (avail2 && tr2.getTime() <= end);
|
| + if (!inRange1 && !inRange2) {
|
| + // No more transition in the range
|
| + break;
|
| + }
|
| + if (!inRange1 || !inRange2) {
|
| + return FALSE;
|
| + }
|
| + if (tr1.getTime() != tr2.getTime()) {
|
| + return FALSE;
|
| + }
|
| + if (ignoreDstAmount) {
|
| + if (tr1.getTo()->getRawOffset() + tr1.getTo()->getDSTSavings()
|
| + != tr2.getTo()->getRawOffset() + tr2.getTo()->getDSTSavings()
|
| + || (tr1.getTo()->getDSTSavings() != 0 && tr2.getTo()->getDSTSavings() == 0)
|
| + || (tr1.getTo()->getDSTSavings() == 0 && tr2.getTo()->getDSTSavings() != 0)) {
|
| + return FALSE;
|
| + }
|
| + } else {
|
| + if (tr1.getTo()->getRawOffset() != tr2.getTo()->getRawOffset() ||
|
| + tr1.getTo()->getDSTSavings() != tr2.getTo()->getDSTSavings()) {
|
| + return FALSE;
|
| + }
|
| + }
|
| + time = tr1.getTime();
|
| + }
|
| + return TRUE;
|
| +}
|
| +
|
| +void
|
| +BasicTimeZone::getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
|
| + AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) /*const*/ {
|
| + initial = NULL;
|
| + std = NULL;
|
| + dst = NULL;
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| + int32_t initialRaw, initialDst;
|
| + UnicodeString initialName;
|
| +
|
| + AnnualTimeZoneRule *ar1 = NULL;
|
| + AnnualTimeZoneRule *ar2 = NULL;
|
| + UnicodeString name;
|
| +
|
| + UBool avail;
|
| + TimeZoneTransition tr;
|
| + // Get the next transition
|
| + avail = getNextTransition(date, FALSE, tr);
|
| + if (avail) {
|
| + tr.getFrom()->getName(initialName);
|
| + initialRaw = tr.getFrom()->getRawOffset();
|
| + initialDst = tr.getFrom()->getDSTSavings();
|
| +
|
| + // Check if the next transition is either DST->STD or STD->DST and
|
| + // within roughly 1 year from the specified date
|
| + UDate nextTransitionTime = tr.getTime();
|
| + if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
|
| + || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
|
| + && (date + MILLIS_PER_YEAR > nextTransitionTime)) {
|
| +
|
| + int32_t year, month, dom, dow, doy, mid;
|
| + UDate d;
|
| +
|
| + // Get local wall time for the next transition time
|
| + Grego::timeToFields(nextTransitionTime + initialRaw + initialDst,
|
| + year, month, dom, dow, doy, mid);
|
| + int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
| + // Create DOW rule
|
| + DateTimeRule *dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
|
| + tr.getTo()->getName(name);
|
| +
|
| + // Note: SimpleTimeZone does not support raw offset change.
|
| + // So we always use raw offset of the given time for the rule,
|
| + // even raw offset is changed. This will result that the result
|
| + // zone to return wrong offset after the transition.
|
| + // When we encounter such case, we do not inspect next next
|
| + // transition for another rule.
|
| + ar1 = new AnnualTimeZoneRule(name, initialRaw, tr.getTo()->getDSTSavings(),
|
| + dtr, year, AnnualTimeZoneRule::MAX_YEAR);
|
| +
|
| + if (tr.getTo()->getRawOffset() == initialRaw) {
|
| + // Get the next next transition
|
| + avail = getNextTransition(nextTransitionTime, FALSE, tr);
|
| + if (avail) {
|
| + // Check if the next next transition is either DST->STD or STD->DST
|
| + // and within roughly 1 year from the next transition
|
| + if (((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
|
| + || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0))
|
| + && nextTransitionTime + MILLIS_PER_YEAR > tr.getTime()) {
|
| +
|
| + // Get local wall time for the next transition time
|
| + Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
|
| + year, month, dom, dow, doy, mid);
|
| + weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
| + // Generate another DOW rule
|
| + dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
|
| + tr.getTo()->getName(name);
|
| + ar2 = new AnnualTimeZoneRule(name, tr.getTo()->getRawOffset(), tr.getTo()->getDSTSavings(),
|
| + dtr, year - 1, AnnualTimeZoneRule::MAX_YEAR);
|
| +
|
| + // Make sure this rule can be applied to the specified date
|
| + avail = ar2->getPreviousStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), TRUE, d);
|
| + if (!avail || d > date
|
| + || initialRaw != tr.getTo()->getRawOffset()
|
| + || initialDst != tr.getTo()->getDSTSavings()) {
|
| + // We cannot use this rule as the second transition rule
|
| + delete ar2;
|
| + ar2 = NULL;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + if (ar2 == NULL) {
|
| + // Try previous transition
|
| + avail = getPreviousTransition(date, TRUE, tr);
|
| + if (avail) {
|
| + // Check if the previous transition is either DST->STD or STD->DST.
|
| + // The actual transition time does not matter here.
|
| + if ((tr.getFrom()->getDSTSavings() == 0 && tr.getTo()->getDSTSavings() != 0)
|
| + || (tr.getFrom()->getDSTSavings() != 0 && tr.getTo()->getDSTSavings() == 0)) {
|
| +
|
| + // Generate another DOW rule
|
| + Grego::timeToFields(tr.getTime() + tr.getFrom()->getRawOffset() + tr.getFrom()->getDSTSavings(),
|
| + year, month, dom, dow, doy, mid);
|
| + weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
|
| + dtr = new DateTimeRule(month, weekInMonth, dow, mid, DateTimeRule::WALL_TIME);
|
| + tr.getTo()->getName(name);
|
| +
|
| + // second rule raw/dst offsets should match raw/dst offsets
|
| + // at the given time
|
| + ar2 = new AnnualTimeZoneRule(name, initialRaw, initialDst,
|
| + dtr, ar1->getStartYear() - 1, AnnualTimeZoneRule::MAX_YEAR);
|
| +
|
| + // Check if this rule start after the first rule after the specified date
|
| + avail = ar2->getNextStart(date, tr.getFrom()->getRawOffset(), tr.getFrom()->getDSTSavings(), FALSE, d);
|
| + if (!avail || d <= nextTransitionTime) {
|
| + // We cannot use this rule as the second transition rule
|
| + delete ar2;
|
| + ar2 = NULL;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + if (ar2 == NULL) {
|
| + // Cannot find a good pair of AnnualTimeZoneRule
|
| + delete ar1;
|
| + ar1 = NULL;
|
| + } else {
|
| + // The initial rule should represent the rule before the previous transition
|
| + ar1->getName(initialName);
|
| + initialRaw = ar1->getRawOffset();
|
| + initialDst = ar1->getDSTSavings();
|
| + }
|
| + }
|
| + }
|
| + else {
|
| + // Try the previous one
|
| + avail = getPreviousTransition(date, TRUE, tr);
|
| + if (avail) {
|
| + tr.getTo()->getName(initialName);
|
| + initialRaw = tr.getTo()->getRawOffset();
|
| + initialDst = tr.getTo()->getDSTSavings();
|
| + } else {
|
| + // No transitions in the past. Just use the current offsets
|
| + getOffset(date, FALSE, initialRaw, initialDst, status);
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + // Set the initial rule
|
| + initial = new InitialTimeZoneRule(initialName, initialRaw, initialDst);
|
| +
|
| + // Set the standard and daylight saving rules
|
| + if (ar1 != NULL && ar2 != NULL) {
|
| + if (ar1->getDSTSavings() != 0) {
|
| + dst = ar1;
|
| + std = ar2;
|
| + } else {
|
| + std = ar1;
|
| + dst = ar2;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void
|
| +BasicTimeZone::getTimeZoneRulesAfter(UDate start, InitialTimeZoneRule*& initial,
|
| + UVector*& transitionRules, UErrorCode& status) /*const*/ {
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| +
|
| + const InitialTimeZoneRule *orgini;
|
| + const TimeZoneRule **orgtrs = NULL;
|
| + TimeZoneTransition tzt;
|
| + UBool avail;
|
| + UVector *orgRules = NULL;
|
| + int32_t ruleCount;
|
| + TimeZoneRule *r = NULL;
|
| + UBool *done = NULL;
|
| + InitialTimeZoneRule *res_initial = NULL;
|
| + UVector *filteredRules = NULL;
|
| + UnicodeString name;
|
| + int32_t i;
|
| + UDate time, t;
|
| + UDate *newTimes = NULL;
|
| + UDate firstStart;
|
| + UBool bFinalStd = FALSE, bFinalDst = FALSE;
|
| +
|
| + // Original transition rules
|
| + ruleCount = countTransitionRules(status);
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| + orgRules = new UVector(ruleCount, status);
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| + orgtrs = (const TimeZoneRule**)uprv_malloc(sizeof(TimeZoneRule*)*ruleCount);
|
| + if (orgtrs == NULL) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + goto error;
|
| + }
|
| + getTimeZoneRules(orgini, orgtrs, ruleCount, status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| + for (i = 0; i < ruleCount; i++) {
|
| + orgRules->addElement(orgtrs[i]->clone(), status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| + }
|
| + uprv_free(orgtrs);
|
| + orgtrs = NULL;
|
| +
|
| + avail = getPreviousTransition(start, TRUE, tzt);
|
| + if (!avail) {
|
| + // No need to filter out rules only applicable to time before the start
|
| + initial = orgini->clone();
|
| + transitionRules = orgRules;
|
| + return;
|
| + }
|
| +
|
| + done = (UBool*)uprv_malloc(sizeof(UBool)*ruleCount);
|
| + if (done == NULL) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + goto error;
|
| + }
|
| + filteredRules = new UVector(status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| +
|
| + // Create initial rule
|
| + tzt.getTo()->getName(name);
|
| + res_initial = new InitialTimeZoneRule(name, tzt.getTo()->getRawOffset(),
|
| + tzt.getTo()->getDSTSavings());
|
| +
|
| + // Mark rules which does not need to be processed
|
| + for (i = 0; i < ruleCount; i++) {
|
| + r = (TimeZoneRule*)orgRules->elementAt(i);
|
| + avail = r->getNextStart(start, res_initial->getRawOffset(), res_initial->getDSTSavings(), FALSE, time);
|
| + done[i] = !avail;
|
| + }
|
| +
|
| + time = start;
|
| + while (!bFinalStd || !bFinalDst) {
|
| + avail = getNextTransition(time, FALSE, tzt);
|
| + if (!avail) {
|
| + break;
|
| + }
|
| + UDate updatedTime = tzt.getTime();
|
| + if (updatedTime == time) {
|
| + // Can get here if rules for start & end of daylight time have exactly
|
| + // the same time.
|
| + // TODO: fix getNextTransition() to prevent it?
|
| + status = U_INVALID_STATE_ERROR;
|
| + goto error;
|
| + }
|
| + time = updatedTime;
|
| +
|
| + const TimeZoneRule *toRule = tzt.getTo();
|
| + for (i = 0; i < ruleCount; i++) {
|
| + r = (TimeZoneRule*)orgRules->elementAt(i);
|
| + if (*r == *toRule) {
|
| + break;
|
| + }
|
| + }
|
| + if (i >= ruleCount) {
|
| + // This case should never happen
|
| + status = U_INVALID_STATE_ERROR;
|
| + goto error;
|
| + }
|
| + if (done[i]) {
|
| + continue;
|
| + }
|
| + const TimeArrayTimeZoneRule *tar = dynamic_cast<const TimeArrayTimeZoneRule *>(toRule);
|
| + const AnnualTimeZoneRule *ar;
|
| + if (tar != NULL) {
|
| + // Get the previous raw offset and DST savings before the very first start time
|
| + TimeZoneTransition tzt0;
|
| + t = start;
|
| + while (TRUE) {
|
| + avail = getNextTransition(t, FALSE, tzt0);
|
| + if (!avail) {
|
| + break;
|
| + }
|
| + if (*(tzt0.getTo()) == *tar) {
|
| + break;
|
| + }
|
| + t = tzt0.getTime();
|
| + }
|
| + if (avail) {
|
| + // Check if the entire start times to be added
|
| + tar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
|
| + if (firstStart > start) {
|
| + // Just add the rule as is
|
| + filteredRules->addElement(tar->clone(), status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| + } else {
|
| + // Colllect transitions after the start time
|
| + int32_t startTimes;
|
| + DateTimeRule::TimeRuleType timeType;
|
| + int32_t idx;
|
| +
|
| + startTimes = tar->countStartTimes();
|
| + timeType = tar->getTimeType();
|
| + for (idx = 0; idx < startTimes; idx++) {
|
| + tar->getStartTimeAt(idx, t);
|
| + if (timeType == DateTimeRule::STANDARD_TIME) {
|
| + t -= tzt.getFrom()->getRawOffset();
|
| + }
|
| + if (timeType == DateTimeRule::WALL_TIME) {
|
| + t -= tzt.getFrom()->getDSTSavings();
|
| + }
|
| + if (t > start) {
|
| + break;
|
| + }
|
| + }
|
| + int32_t asize = startTimes - idx;
|
| + if (asize > 0) {
|
| + newTimes = (UDate*)uprv_malloc(sizeof(UDate) * asize);
|
| + if (newTimes == NULL) {
|
| + status = U_MEMORY_ALLOCATION_ERROR;
|
| + goto error;
|
| + }
|
| + for (int32_t newidx = 0; newidx < asize; newidx++) {
|
| + tar->getStartTimeAt(idx + newidx, newTimes[newidx]);
|
| + if (U_FAILURE(status)) {
|
| + uprv_free(newTimes);
|
| + newTimes = NULL;
|
| + goto error;
|
| + }
|
| + }
|
| + tar->getName(name);
|
| + TimeArrayTimeZoneRule *newTar = new TimeArrayTimeZoneRule(name,
|
| + tar->getRawOffset(), tar->getDSTSavings(), newTimes, asize, timeType);
|
| + uprv_free(newTimes);
|
| + filteredRules->addElement(newTar, status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + } else if ((ar = dynamic_cast<const AnnualTimeZoneRule *>(toRule)) != NULL) {
|
| + ar->getFirstStart(tzt.getFrom()->getRawOffset(), tzt.getFrom()->getDSTSavings(), firstStart);
|
| + if (firstStart == tzt.getTime()) {
|
| + // Just add the rule as is
|
| + filteredRules->addElement(ar->clone(), status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| + } else {
|
| + // Calculate the transition year
|
| + int32_t year, month, dom, dow, doy, mid;
|
| + Grego::timeToFields(tzt.getTime(), year, month, dom, dow, doy, mid);
|
| + // Re-create the rule
|
| + ar->getName(name);
|
| + AnnualTimeZoneRule *newAr = new AnnualTimeZoneRule(name, ar->getRawOffset(), ar->getDSTSavings(),
|
| + *(ar->getRule()), year, ar->getEndYear());
|
| + filteredRules->addElement(newAr, status);
|
| + if (U_FAILURE(status)) {
|
| + goto error;
|
| + }
|
| + }
|
| + // check if this is a final rule
|
| + if (ar->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
|
| + // After bot final standard and dst rules are processed,
|
| + // exit this while loop.
|
| + if (ar->getDSTSavings() == 0) {
|
| + bFinalStd = TRUE;
|
| + } else {
|
| + bFinalDst = TRUE;
|
| + }
|
| + }
|
| + }
|
| + done[i] = TRUE;
|
| + }
|
| +
|
| + // Set the results
|
| + if (orgRules != NULL) {
|
| + while (!orgRules->isEmpty()) {
|
| + r = (TimeZoneRule*)orgRules->orphanElementAt(0);
|
| + delete r;
|
| + }
|
| + delete orgRules;
|
| + }
|
| + if (done != NULL) {
|
| + uprv_free(done);
|
| + }
|
| +
|
| + initial = res_initial;
|
| + transitionRules = filteredRules;
|
| + return;
|
| +
|
| +error:
|
| + if (orgtrs != NULL) {
|
| + uprv_free(orgtrs);
|
| + }
|
| + if (orgRules != NULL) {
|
| + while (!orgRules->isEmpty()) {
|
| + r = (TimeZoneRule*)orgRules->orphanElementAt(0);
|
| + delete r;
|
| + }
|
| + delete orgRules;
|
| + }
|
| + if (done != NULL) {
|
| + if (filteredRules != NULL) {
|
| + while (!filteredRules->isEmpty()) {
|
| + r = (TimeZoneRule*)filteredRules->orphanElementAt(0);
|
| + delete r;
|
| + }
|
| + delete filteredRules;
|
| + }
|
| + delete res_initial;
|
| + uprv_free(done);
|
| + }
|
| +
|
| + initial = NULL;
|
| + transitionRules = NULL;
|
| +}
|
| +
|
| +void
|
| +BasicTimeZone::getOffsetFromLocal(UDate /*date*/, int32_t /*nonExistingTimeOpt*/, int32_t /*duplicatedTimeOpt*/,
|
| + int32_t& /*rawOffset*/, int32_t& /*dstOffset*/, UErrorCode& status) /*const*/ {
|
| + if (U_FAILURE(status)) {
|
| + return;
|
| + }
|
| + status = U_UNSUPPORTED_ERROR;
|
| +}
|
| +
|
| +U_NAMESPACE_END
|
| +
|
| +#endif /* #if !UCONFIG_NO_FORMATTING */
|
| +
|
| +//eof
|
|
|
| Property changes on: icu46/source/i18n/basictz.cpp
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|