1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/rbtz.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,957 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 2007-2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +*/ 1.10 + 1.11 +#include "utypeinfo.h" // for 'typeid' to work 1.12 + 1.13 +#include "unicode/utypes.h" 1.14 + 1.15 +#if !UCONFIG_NO_FORMATTING 1.16 + 1.17 +#include "unicode/rbtz.h" 1.18 +#include "unicode/gregocal.h" 1.19 +#include "uvector.h" 1.20 +#include "gregoimp.h" 1.21 +#include "cmemory.h" 1.22 +#include "umutex.h" 1.23 + 1.24 +U_NAMESPACE_BEGIN 1.25 + 1.26 +/** 1.27 + * A struct representing a time zone transition 1.28 + */ 1.29 +struct Transition { 1.30 + UDate time; 1.31 + TimeZoneRule* from; 1.32 + TimeZoneRule* to; 1.33 +}; 1.34 + 1.35 +static UBool compareRules(UVector* rules1, UVector* rules2) { 1.36 + if (rules1 == NULL && rules2 == NULL) { 1.37 + return TRUE; 1.38 + } else if (rules1 == NULL || rules2 == NULL) { 1.39 + return FALSE; 1.40 + } 1.41 + int32_t size = rules1->size(); 1.42 + if (size != rules2->size()) { 1.43 + return FALSE; 1.44 + } 1.45 + for (int32_t i = 0; i < size; i++) { 1.46 + TimeZoneRule *r1 = (TimeZoneRule*)rules1->elementAt(i); 1.47 + TimeZoneRule *r2 = (TimeZoneRule*)rules2->elementAt(i); 1.48 + if (*r1 != *r2) { 1.49 + return FALSE; 1.50 + } 1.51 + } 1.52 + return TRUE; 1.53 +} 1.54 + 1.55 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone) 1.56 + 1.57 +RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule) 1.58 +: BasicTimeZone(id), fInitialRule(initialRule), fHistoricRules(NULL), fFinalRules(NULL), 1.59 + fHistoricTransitions(NULL), fUpToDate(FALSE) { 1.60 +} 1.61 + 1.62 +RuleBasedTimeZone::RuleBasedTimeZone(const RuleBasedTimeZone& source) 1.63 +: BasicTimeZone(source), fInitialRule(source.fInitialRule->clone()), 1.64 + fHistoricTransitions(NULL), fUpToDate(FALSE) { 1.65 + fHistoricRules = copyRules(source.fHistoricRules); 1.66 + fFinalRules = copyRules(source.fFinalRules); 1.67 + if (source.fUpToDate) { 1.68 + UErrorCode status = U_ZERO_ERROR; 1.69 + complete(status); 1.70 + } 1.71 +} 1.72 + 1.73 +RuleBasedTimeZone::~RuleBasedTimeZone() { 1.74 + deleteTransitions(); 1.75 + deleteRules(); 1.76 +} 1.77 + 1.78 +RuleBasedTimeZone& 1.79 +RuleBasedTimeZone::operator=(const RuleBasedTimeZone& right) { 1.80 + if (*this != right) { 1.81 + BasicTimeZone::operator=(right); 1.82 + deleteRules(); 1.83 + fInitialRule = right.fInitialRule->clone(); 1.84 + fHistoricRules = copyRules(right.fHistoricRules); 1.85 + fFinalRules = copyRules(right.fFinalRules); 1.86 + deleteTransitions(); 1.87 + fUpToDate = FALSE; 1.88 + } 1.89 + return *this; 1.90 +} 1.91 + 1.92 +UBool 1.93 +RuleBasedTimeZone::operator==(const TimeZone& that) const { 1.94 + if (this == &that) { 1.95 + return TRUE; 1.96 + } 1.97 + if (typeid(*this) != typeid(that) 1.98 + || BasicTimeZone::operator==(that) == FALSE) { 1.99 + return FALSE; 1.100 + } 1.101 + RuleBasedTimeZone *rbtz = (RuleBasedTimeZone*)&that; 1.102 + if (*fInitialRule != *(rbtz->fInitialRule)) { 1.103 + return FALSE; 1.104 + } 1.105 + if (compareRules(fHistoricRules, rbtz->fHistoricRules) 1.106 + && compareRules(fFinalRules, rbtz->fFinalRules)) { 1.107 + return TRUE; 1.108 + } 1.109 + return FALSE; 1.110 +} 1.111 + 1.112 +UBool 1.113 +RuleBasedTimeZone::operator!=(const TimeZone& that) const { 1.114 + return !operator==(that); 1.115 +} 1.116 + 1.117 +void 1.118 +RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) { 1.119 + if (U_FAILURE(status)) { 1.120 + return; 1.121 + } 1.122 + AnnualTimeZoneRule* atzrule = dynamic_cast<AnnualTimeZoneRule*>(rule); 1.123 + if (atzrule != NULL && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) { 1.124 + // A final rule 1.125 + if (fFinalRules == NULL) { 1.126 + fFinalRules = new UVector(status); 1.127 + if (U_FAILURE(status)) { 1.128 + return; 1.129 + } 1.130 + } else if (fFinalRules->size() >= 2) { 1.131 + // Cannot handle more than two final rules 1.132 + status = U_INVALID_STATE_ERROR; 1.133 + return; 1.134 + } 1.135 + fFinalRules->addElement((void*)rule, status); 1.136 + } else { 1.137 + // Non-final rule 1.138 + if (fHistoricRules == NULL) { 1.139 + fHistoricRules = new UVector(status); 1.140 + if (U_FAILURE(status)) { 1.141 + return; 1.142 + } 1.143 + } 1.144 + fHistoricRules->addElement((void*)rule, status); 1.145 + } 1.146 + // Mark dirty, so transitions are recalculated at next complete() call 1.147 + fUpToDate = FALSE; 1.148 +} 1.149 + 1.150 +static UMutex gLock = U_MUTEX_INITIALIZER; 1.151 + 1.152 +void 1.153 +RuleBasedTimeZone::completeConst(UErrorCode& status) const { 1.154 + if (U_FAILURE(status)) { 1.155 + return; 1.156 + } 1.157 + umtx_lock(&gLock); 1.158 + if (!fUpToDate) { 1.159 + RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this); 1.160 + ncThis->complete(status); 1.161 + } 1.162 + umtx_unlock(&gLock); 1.163 +} 1.164 + 1.165 +void 1.166 +RuleBasedTimeZone::complete(UErrorCode& status) { 1.167 + if (U_FAILURE(status)) { 1.168 + return; 1.169 + } 1.170 + if (fUpToDate) { 1.171 + return; 1.172 + } 1.173 + // Make sure either no final rules or a pair of AnnualTimeZoneRules 1.174 + // are available. 1.175 + if (fFinalRules != NULL && fFinalRules->size() != 2) { 1.176 + status = U_INVALID_STATE_ERROR; 1.177 + return; 1.178 + } 1.179 + 1.180 + UBool *done = NULL; 1.181 + // Create a TimezoneTransition and add to the list 1.182 + if (fHistoricRules != NULL || fFinalRules != NULL) { 1.183 + TimeZoneRule *curRule = fInitialRule; 1.184 + UDate lastTransitionTime = MIN_MILLIS; 1.185 + 1.186 + // Build the transition array which represents historical time zone 1.187 + // transitions. 1.188 + if (fHistoricRules != NULL && fHistoricRules->size() > 0) { 1.189 + int32_t i; 1.190 + int32_t historicCount = fHistoricRules->size(); 1.191 + done = (UBool*)uprv_malloc(sizeof(UBool) * historicCount); 1.192 + if (done == NULL) { 1.193 + status = U_MEMORY_ALLOCATION_ERROR; 1.194 + goto cleanup; 1.195 + } 1.196 + for (i = 0; i < historicCount; i++) { 1.197 + done[i] = FALSE; 1.198 + } 1.199 + while (TRUE) { 1.200 + int32_t curStdOffset = curRule->getRawOffset(); 1.201 + int32_t curDstSavings = curRule->getDSTSavings(); 1.202 + UDate nextTransitionTime = MAX_MILLIS; 1.203 + TimeZoneRule *nextRule = NULL; 1.204 + TimeZoneRule *r = NULL; 1.205 + UBool avail; 1.206 + UDate tt; 1.207 + UnicodeString curName, name; 1.208 + curRule->getName(curName); 1.209 + 1.210 + for (i = 0; i < historicCount; i++) { 1.211 + if (done[i]) { 1.212 + continue; 1.213 + } 1.214 + r = (TimeZoneRule*)fHistoricRules->elementAt(i); 1.215 + avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt); 1.216 + if (!avail) { 1.217 + // No more transitions from this rule - skip this rule next time 1.218 + done[i] = TRUE; 1.219 + } else { 1.220 + r->getName(name); 1.221 + if (*r == *curRule || 1.222 + (name == curName && r->getRawOffset() == curRule->getRawOffset() 1.223 + && r->getDSTSavings() == curRule->getDSTSavings())) { 1.224 + continue; 1.225 + } 1.226 + if (tt < nextTransitionTime) { 1.227 + nextTransitionTime = tt; 1.228 + nextRule = r; 1.229 + } 1.230 + } 1.231 + } 1.232 + 1.233 + if (nextRule == NULL) { 1.234 + // Check if all historic rules are done 1.235 + UBool bDoneAll = TRUE; 1.236 + for (int32_t j = 0; j < historicCount; j++) { 1.237 + if (!done[j]) { 1.238 + bDoneAll = FALSE; 1.239 + break; 1.240 + } 1.241 + } 1.242 + if (bDoneAll) { 1.243 + break; 1.244 + } 1.245 + } 1.246 + 1.247 + if (fFinalRules != NULL) { 1.248 + // Check if one of final rules has earlier transition date 1.249 + for (i = 0; i < 2 /* fFinalRules->size() */; i++) { 1.250 + TimeZoneRule *fr = (TimeZoneRule*)fFinalRules->elementAt(i); 1.251 + if (*fr == *curRule) { 1.252 + continue; 1.253 + } 1.254 + r = (TimeZoneRule*)fFinalRules->elementAt(i); 1.255 + avail = r->getNextStart(lastTransitionTime, curStdOffset, curDstSavings, false, tt); 1.256 + if (avail) { 1.257 + if (tt < nextTransitionTime) { 1.258 + nextTransitionTime = tt; 1.259 + nextRule = r; 1.260 + } 1.261 + } 1.262 + } 1.263 + } 1.264 + 1.265 + if (nextRule == NULL) { 1.266 + // Nothing more 1.267 + break; 1.268 + } 1.269 + 1.270 + if (fHistoricTransitions == NULL) { 1.271 + fHistoricTransitions = new UVector(status); 1.272 + if (U_FAILURE(status)) { 1.273 + goto cleanup; 1.274 + } 1.275 + } 1.276 + Transition *trst = (Transition*)uprv_malloc(sizeof(Transition)); 1.277 + if (trst == NULL) { 1.278 + status = U_MEMORY_ALLOCATION_ERROR; 1.279 + goto cleanup; 1.280 + } 1.281 + trst->time = nextTransitionTime; 1.282 + trst->from = curRule; 1.283 + trst->to = nextRule; 1.284 + fHistoricTransitions->addElement(trst, status); 1.285 + if (U_FAILURE(status)) { 1.286 + goto cleanup; 1.287 + } 1.288 + lastTransitionTime = nextTransitionTime; 1.289 + curRule = nextRule; 1.290 + } 1.291 + } 1.292 + if (fFinalRules != NULL) { 1.293 + if (fHistoricTransitions == NULL) { 1.294 + fHistoricTransitions = new UVector(status); 1.295 + if (U_FAILURE(status)) { 1.296 + goto cleanup; 1.297 + } 1.298 + } 1.299 + // Append the first transition for each 1.300 + TimeZoneRule *rule0 = (TimeZoneRule*)fFinalRules->elementAt(0); 1.301 + TimeZoneRule *rule1 = (TimeZoneRule*)fFinalRules->elementAt(1); 1.302 + UDate tt0, tt1; 1.303 + UBool avail0 = rule0->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt0); 1.304 + UBool avail1 = rule1->getNextStart(lastTransitionTime, curRule->getRawOffset(), curRule->getDSTSavings(), false, tt1); 1.305 + if (!avail0 || !avail1) { 1.306 + // Should not happen, because both rules are permanent 1.307 + status = U_INVALID_STATE_ERROR; 1.308 + goto cleanup; 1.309 + } 1.310 + Transition *final0 = (Transition*)uprv_malloc(sizeof(Transition)); 1.311 + if (final0 == NULL) { 1.312 + status = U_MEMORY_ALLOCATION_ERROR; 1.313 + goto cleanup; 1.314 + } 1.315 + Transition *final1 = (Transition*)uprv_malloc(sizeof(Transition)); 1.316 + if (final1 == NULL) { 1.317 + uprv_free(final0); 1.318 + status = U_MEMORY_ALLOCATION_ERROR; 1.319 + goto cleanup; 1.320 + } 1.321 + if (tt0 < tt1) { 1.322 + final0->time = tt0; 1.323 + final0->from = curRule; 1.324 + final0->to = rule0; 1.325 + rule1->getNextStart(tt0, rule0->getRawOffset(), rule0->getDSTSavings(), false, final1->time); 1.326 + final1->from = rule0; 1.327 + final1->to = rule1; 1.328 + } else { 1.329 + final0->time = tt1; 1.330 + final0->from = curRule; 1.331 + final0->to = rule1; 1.332 + rule0->getNextStart(tt1, rule1->getRawOffset(), rule1->getDSTSavings(), false, final1->time); 1.333 + final1->from = rule1; 1.334 + final1->to = rule0; 1.335 + } 1.336 + fHistoricTransitions->addElement(final0, status); 1.337 + if (U_FAILURE(status)) { 1.338 + goto cleanup; 1.339 + } 1.340 + fHistoricTransitions->addElement(final1, status); 1.341 + if (U_FAILURE(status)) { 1.342 + goto cleanup; 1.343 + } 1.344 + } 1.345 + } 1.346 + fUpToDate = TRUE; 1.347 + if (done != NULL) { 1.348 + uprv_free(done); 1.349 + } 1.350 + return; 1.351 + 1.352 +cleanup: 1.353 + deleteTransitions(); 1.354 + if (done != NULL) { 1.355 + uprv_free(done); 1.356 + } 1.357 + fUpToDate = FALSE; 1.358 +} 1.359 + 1.360 +TimeZone* 1.361 +RuleBasedTimeZone::clone(void) const { 1.362 + return new RuleBasedTimeZone(*this); 1.363 +} 1.364 + 1.365 +int32_t 1.366 +RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, 1.367 + uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const { 1.368 + if (U_FAILURE(status)) { 1.369 + return 0; 1.370 + } 1.371 + if (month < UCAL_JANUARY || month > UCAL_DECEMBER) { 1.372 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.373 + return 0; 1.374 + } else { 1.375 + return getOffset(era, year, month, day, dayOfWeek, millis, 1.376 + Grego::monthLength(year, month), status); 1.377 + } 1.378 +} 1.379 + 1.380 +int32_t 1.381 +RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day, 1.382 + uint8_t /*dayOfWeek*/, int32_t millis, 1.383 + int32_t /*monthLength*/, UErrorCode& status) const { 1.384 + // dayOfWeek and monthLength are unused 1.385 + if (U_FAILURE(status)) { 1.386 + return 0; 1.387 + } 1.388 + if (era == GregorianCalendar::BC) { 1.389 + // Convert to extended year 1.390 + year = 1 - year; 1.391 + } 1.392 + int32_t rawOffset, dstOffset; 1.393 + UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis; 1.394 + getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status); 1.395 + if (U_FAILURE(status)) { 1.396 + return 0; 1.397 + } 1.398 + return (rawOffset + dstOffset); 1.399 +} 1.400 + 1.401 +void 1.402 +RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset, 1.403 + int32_t& dstOffset, UErrorCode& status) const { 1.404 + getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status); 1.405 +} 1.406 + 1.407 +void 1.408 +RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, 1.409 + int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) const { 1.410 + getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status); 1.411 +} 1.412 + 1.413 + 1.414 +/* 1.415 + * The internal getOffset implementation 1.416 + */ 1.417 +void 1.418 +RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local, 1.419 + int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt, 1.420 + int32_t& rawOffset, int32_t& dstOffset, 1.421 + UErrorCode& status) const { 1.422 + rawOffset = 0; 1.423 + dstOffset = 0; 1.424 + 1.425 + if (U_FAILURE(status)) { 1.426 + return; 1.427 + } 1.428 + if (!fUpToDate) { 1.429 + // Transitions are not yet resolved. We cannot do it here 1.430 + // because this method is const. Thus, do nothing and return 1.431 + // error status. 1.432 + status = U_INVALID_STATE_ERROR; 1.433 + return; 1.434 + } 1.435 + const TimeZoneRule *rule = NULL; 1.436 + if (fHistoricTransitions == NULL) { 1.437 + rule = fInitialRule; 1.438 + } else { 1.439 + UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0), 1.440 + local, NonExistingTimeOpt, DuplicatedTimeOpt); 1.441 + if (date < tstart) { 1.442 + rule = fInitialRule; 1.443 + } else { 1.444 + int32_t idx = fHistoricTransitions->size() - 1; 1.445 + UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx), 1.446 + local, NonExistingTimeOpt, DuplicatedTimeOpt); 1.447 + if (date > tend) { 1.448 + if (fFinalRules != NULL) { 1.449 + rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt); 1.450 + } 1.451 + if (rule == NULL) { 1.452 + // no final rules or the given time is before the first transition 1.453 + // specified by the final rules -> use the last rule 1.454 + rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to; 1.455 + } 1.456 + } else { 1.457 + // Find a historical transition 1.458 + while (idx >= 0) { 1.459 + if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx), 1.460 + local, NonExistingTimeOpt, DuplicatedTimeOpt)) { 1.461 + break; 1.462 + } 1.463 + idx--; 1.464 + } 1.465 + rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to; 1.466 + } 1.467 + } 1.468 + } 1.469 + if (rule != NULL) { 1.470 + rawOffset = rule->getRawOffset(); 1.471 + dstOffset = rule->getDSTSavings(); 1.472 + } 1.473 +} 1.474 + 1.475 +void 1.476 +RuleBasedTimeZone::setRawOffset(int32_t /*offsetMillis*/) { 1.477 + // We don't support this operation at this moment. 1.478 + // Nothing to do! 1.479 +} 1.480 + 1.481 +int32_t 1.482 +RuleBasedTimeZone::getRawOffset(void) const { 1.483 + // Note: This implementation returns standard GMT offset 1.484 + // as of current time. 1.485 + UErrorCode status = U_ZERO_ERROR; 1.486 + int32_t raw, dst; 1.487 + getOffset(uprv_getUTCtime() * U_MILLIS_PER_SECOND, 1.488 + FALSE, raw, dst, status); 1.489 + return raw; 1.490 +} 1.491 + 1.492 +UBool 1.493 +RuleBasedTimeZone::useDaylightTime(void) const { 1.494 + // Note: This implementation returns true when 1.495 + // daylight saving time is used as of now or 1.496 + // after the next transition. 1.497 + UErrorCode status = U_ZERO_ERROR; 1.498 + UDate now = uprv_getUTCtime() * U_MILLIS_PER_SECOND; 1.499 + int32_t raw, dst; 1.500 + getOffset(now, FALSE, raw, dst, status); 1.501 + if (dst != 0) { 1.502 + return TRUE; 1.503 + } 1.504 + // If DST is not used now, check if DST is used after the next transition 1.505 + UDate time; 1.506 + TimeZoneRule *from, *to; 1.507 + UBool avail = findNext(now, FALSE, time, from, to); 1.508 + if (avail && to->getDSTSavings() != 0) { 1.509 + return TRUE; 1.510 + } 1.511 + return FALSE; 1.512 +} 1.513 + 1.514 +UBool 1.515 +RuleBasedTimeZone::inDaylightTime(UDate date, UErrorCode& status) const { 1.516 + if (U_FAILURE(status)) { 1.517 + return FALSE; 1.518 + } 1.519 + int32_t raw, dst; 1.520 + getOffset(date, FALSE, raw, dst, status); 1.521 + if (dst != 0) { 1.522 + return TRUE; 1.523 + } 1.524 + return FALSE; 1.525 +} 1.526 + 1.527 +UBool 1.528 +RuleBasedTimeZone::hasSameRules(const TimeZone& other) const { 1.529 + if (this == &other) { 1.530 + return TRUE; 1.531 + } 1.532 + if (typeid(*this) != typeid(other)) { 1.533 + return FALSE; 1.534 + } 1.535 + const RuleBasedTimeZone& that = (const RuleBasedTimeZone&)other; 1.536 + if (*fInitialRule != *(that.fInitialRule)) { 1.537 + return FALSE; 1.538 + } 1.539 + if (compareRules(fHistoricRules, that.fHistoricRules) 1.540 + && compareRules(fFinalRules, that.fFinalRules)) { 1.541 + return TRUE; 1.542 + } 1.543 + return FALSE; 1.544 +} 1.545 + 1.546 +UBool 1.547 +RuleBasedTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const { 1.548 + UErrorCode status = U_ZERO_ERROR; 1.549 + completeConst(status); 1.550 + if (U_FAILURE(status)) { 1.551 + return FALSE; 1.552 + } 1.553 + UDate transitionTime; 1.554 + TimeZoneRule *fromRule, *toRule; 1.555 + UBool found = findNext(base, inclusive, transitionTime, fromRule, toRule); 1.556 + if (found) { 1.557 + result.setTime(transitionTime); 1.558 + result.setFrom((const TimeZoneRule&)*fromRule); 1.559 + result.setTo((const TimeZoneRule&)*toRule); 1.560 + return TRUE; 1.561 + } 1.562 + return FALSE; 1.563 +} 1.564 + 1.565 +UBool 1.566 +RuleBasedTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const { 1.567 + UErrorCode status = U_ZERO_ERROR; 1.568 + completeConst(status); 1.569 + if (U_FAILURE(status)) { 1.570 + return FALSE; 1.571 + } 1.572 + UDate transitionTime; 1.573 + TimeZoneRule *fromRule, *toRule; 1.574 + UBool found = findPrev(base, inclusive, transitionTime, fromRule, toRule); 1.575 + if (found) { 1.576 + result.setTime(transitionTime); 1.577 + result.setFrom((const TimeZoneRule&)*fromRule); 1.578 + result.setTo((const TimeZoneRule&)*toRule); 1.579 + return TRUE; 1.580 + } 1.581 + return FALSE; 1.582 +} 1.583 + 1.584 +int32_t 1.585 +RuleBasedTimeZone::countTransitionRules(UErrorCode& /*status*/) const { 1.586 + int32_t count = 0; 1.587 + if (fHistoricRules != NULL) { 1.588 + count += fHistoricRules->size(); 1.589 + } 1.590 + if (fFinalRules != NULL) { 1.591 + count += fFinalRules->size(); 1.592 + } 1.593 + return count; 1.594 +} 1.595 + 1.596 +void 1.597 +RuleBasedTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial, 1.598 + const TimeZoneRule* trsrules[], 1.599 + int32_t& trscount, 1.600 + UErrorCode& status) const { 1.601 + if (U_FAILURE(status)) { 1.602 + return; 1.603 + } 1.604 + // Initial rule 1.605 + initial = fInitialRule; 1.606 + 1.607 + // Transition rules 1.608 + int32_t cnt = 0; 1.609 + int32_t idx; 1.610 + if (fHistoricRules != NULL && cnt < trscount) { 1.611 + int32_t historicCount = fHistoricRules->size(); 1.612 + idx = 0; 1.613 + while (cnt < trscount && idx < historicCount) { 1.614 + trsrules[cnt++] = (const TimeZoneRule*)fHistoricRules->elementAt(idx++); 1.615 + } 1.616 + } 1.617 + if (fFinalRules != NULL && cnt < trscount) { 1.618 + int32_t finalCount = fFinalRules->size(); 1.619 + idx = 0; 1.620 + while (cnt < trscount && idx < finalCount) { 1.621 + trsrules[cnt++] = (const TimeZoneRule*)fFinalRules->elementAt(idx++); 1.622 + } 1.623 + } 1.624 + // Set the result length 1.625 + trscount = cnt; 1.626 +} 1.627 + 1.628 +void 1.629 +RuleBasedTimeZone::deleteRules(void) { 1.630 + delete fInitialRule; 1.631 + fInitialRule = NULL; 1.632 + if (fHistoricRules != NULL) { 1.633 + while (!fHistoricRules->isEmpty()) { 1.634 + delete (TimeZoneRule*)(fHistoricRules->orphanElementAt(0)); 1.635 + } 1.636 + delete fHistoricRules; 1.637 + fHistoricRules = NULL; 1.638 + } 1.639 + if (fFinalRules != NULL) { 1.640 + while (!fFinalRules->isEmpty()) { 1.641 + delete (AnnualTimeZoneRule*)(fFinalRules->orphanElementAt(0)); 1.642 + } 1.643 + delete fFinalRules; 1.644 + fFinalRules = NULL; 1.645 + } 1.646 +} 1.647 + 1.648 +void 1.649 +RuleBasedTimeZone::deleteTransitions(void) { 1.650 + if (fHistoricTransitions != NULL) { 1.651 + while (!fHistoricTransitions->isEmpty()) { 1.652 + Transition *trs = (Transition*)fHistoricTransitions->orphanElementAt(0); 1.653 + uprv_free(trs); 1.654 + } 1.655 + delete fHistoricTransitions; 1.656 + } 1.657 + fHistoricTransitions = NULL; 1.658 +} 1.659 + 1.660 +UVector* 1.661 +RuleBasedTimeZone::copyRules(UVector* source) { 1.662 + if (source == NULL) { 1.663 + return NULL; 1.664 + } 1.665 + UErrorCode ec = U_ZERO_ERROR; 1.666 + int32_t size = source->size(); 1.667 + UVector *rules = new UVector(size, ec); 1.668 + if (U_FAILURE(ec)) { 1.669 + return NULL; 1.670 + } 1.671 + int32_t i; 1.672 + for (i = 0; i < size; i++) { 1.673 + rules->addElement(((TimeZoneRule*)source->elementAt(i))->clone(), ec); 1.674 + if (U_FAILURE(ec)) { 1.675 + break; 1.676 + } 1.677 + } 1.678 + if (U_FAILURE(ec)) { 1.679 + // In case of error, clean up 1.680 + for (i = 0; i < rules->size(); i++) { 1.681 + TimeZoneRule *rule = (TimeZoneRule*)rules->orphanElementAt(i); 1.682 + delete rule; 1.683 + } 1.684 + delete rules; 1.685 + return NULL; 1.686 + } 1.687 + return rules; 1.688 +} 1.689 + 1.690 +TimeZoneRule* 1.691 +RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local, 1.692 + int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const { 1.693 + if (fFinalRules == NULL) { 1.694 + return NULL; 1.695 + } 1.696 + 1.697 + AnnualTimeZoneRule* fr0 = (AnnualTimeZoneRule*)fFinalRules->elementAt(0); 1.698 + AnnualTimeZoneRule* fr1 = (AnnualTimeZoneRule*)fFinalRules->elementAt(1); 1.699 + if (fr0 == NULL || fr1 == NULL) { 1.700 + return NULL; 1.701 + } 1.702 + 1.703 + UDate start0, start1; 1.704 + UDate base; 1.705 + int32_t localDelta; 1.706 + 1.707 + base = date; 1.708 + if (local) { 1.709 + localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(), 1.710 + fr0->getRawOffset(), fr0->getDSTSavings(), 1.711 + NonExistingTimeOpt, DuplicatedTimeOpt); 1.712 + base -= localDelta; 1.713 + } 1.714 + UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0); 1.715 + 1.716 + base = date; 1.717 + if (local) { 1.718 + localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(), 1.719 + fr1->getRawOffset(), fr1->getDSTSavings(), 1.720 + NonExistingTimeOpt, DuplicatedTimeOpt); 1.721 + base -= localDelta; 1.722 + } 1.723 + UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1); 1.724 + 1.725 + if (!avail0 || !avail1) { 1.726 + if (avail0) { 1.727 + return fr0; 1.728 + } else if (avail1) { 1.729 + return fr1; 1.730 + } 1.731 + // Both rules take effect after the given time 1.732 + return NULL; 1.733 + } 1.734 + 1.735 + return (start0 > start1) ? fr0 : fr1; 1.736 +} 1.737 + 1.738 +UBool 1.739 +RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime, 1.740 + TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const { 1.741 + if (fHistoricTransitions == NULL) { 1.742 + return FALSE; 1.743 + } 1.744 + UBool isFinal = FALSE; 1.745 + UBool found = FALSE; 1.746 + Transition result; 1.747 + Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0); 1.748 + UDate tt = tzt->time; 1.749 + if (tt > base || (inclusive && tt == base)) { 1.750 + result = *tzt; 1.751 + found = TRUE; 1.752 + } else { 1.753 + int32_t idx = fHistoricTransitions->size() - 1; 1.754 + tzt = (Transition*)fHistoricTransitions->elementAt(idx); 1.755 + tt = tzt->time; 1.756 + if (inclusive && tt == base) { 1.757 + result = *tzt; 1.758 + found = TRUE; 1.759 + } else if (tt <= base) { 1.760 + if (fFinalRules != NULL) { 1.761 + // Find a transion time with finalRules 1.762 + TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0); 1.763 + TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1); 1.764 + UDate start0, start1; 1.765 + UBool avail0 = r0->getNextStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0); 1.766 + UBool avail1 = r1->getNextStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1); 1.767 + // avail0/avail1 should be always TRUE 1.768 + if (!avail0 && !avail1) { 1.769 + return FALSE; 1.770 + } 1.771 + if (!avail1 || start0 < start1) { 1.772 + result.time = start0; 1.773 + result.from = r1; 1.774 + result.to = r0; 1.775 + } else { 1.776 + result.time = start1; 1.777 + result.from = r0; 1.778 + result.to = r1; 1.779 + } 1.780 + isFinal = TRUE; 1.781 + found = TRUE; 1.782 + } 1.783 + } else { 1.784 + // Find a transition within the historic transitions 1.785 + idx--; 1.786 + Transition *prev = tzt; 1.787 + while (idx > 0) { 1.788 + tzt = (Transition*)fHistoricTransitions->elementAt(idx); 1.789 + tt = tzt->time; 1.790 + if (tt < base || (!inclusive && tt == base)) { 1.791 + break; 1.792 + } 1.793 + idx--; 1.794 + prev = tzt; 1.795 + } 1.796 + result.time = prev->time; 1.797 + result.from = prev->from; 1.798 + result.to = prev->to; 1.799 + found = TRUE; 1.800 + } 1.801 + } 1.802 + if (found) { 1.803 + // For now, this implementation ignore transitions with only zone name changes. 1.804 + if (result.from->getRawOffset() == result.to->getRawOffset() 1.805 + && result.from->getDSTSavings() == result.to->getDSTSavings()) { 1.806 + if (isFinal) { 1.807 + return FALSE; 1.808 + } else { 1.809 + // No offset changes. Try next one if not final 1.810 + return findNext(result.time, FALSE /* always exclusive */, 1.811 + transitionTime, fromRule, toRule); 1.812 + } 1.813 + } 1.814 + transitionTime = result.time; 1.815 + fromRule = result.from; 1.816 + toRule = result.to; 1.817 + return TRUE; 1.818 + } 1.819 + return FALSE; 1.820 +} 1.821 + 1.822 +UBool 1.823 +RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime, 1.824 + TimeZoneRule*& fromRule, TimeZoneRule*& toRule) const { 1.825 + if (fHistoricTransitions == NULL) { 1.826 + return FALSE; 1.827 + } 1.828 + UBool found = FALSE; 1.829 + Transition result; 1.830 + Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0); 1.831 + UDate tt = tzt->time; 1.832 + if (inclusive && tt == base) { 1.833 + result = *tzt; 1.834 + found = TRUE; 1.835 + } else if (tt < base) { 1.836 + int32_t idx = fHistoricTransitions->size() - 1; 1.837 + tzt = (Transition*)fHistoricTransitions->elementAt(idx); 1.838 + tt = tzt->time; 1.839 + if (inclusive && tt == base) { 1.840 + result = *tzt; 1.841 + found = TRUE; 1.842 + } else if (tt < base) { 1.843 + if (fFinalRules != NULL) { 1.844 + // Find a transion time with finalRules 1.845 + TimeZoneRule *r0 = (TimeZoneRule*)fFinalRules->elementAt(0); 1.846 + TimeZoneRule *r1 = (TimeZoneRule*)fFinalRules->elementAt(1); 1.847 + UDate start0, start1; 1.848 + UBool avail0 = r0->getPreviousStart(base, r1->getRawOffset(), r1->getDSTSavings(), inclusive, start0); 1.849 + UBool avail1 = r1->getPreviousStart(base, r0->getRawOffset(), r0->getDSTSavings(), inclusive, start1); 1.850 + // avail0/avail1 should be always TRUE 1.851 + if (!avail0 && !avail1) { 1.852 + return FALSE; 1.853 + } 1.854 + if (!avail1 || start0 > start1) { 1.855 + result.time = start0; 1.856 + result.from = r1; 1.857 + result.to = r0; 1.858 + } else { 1.859 + result.time = start1; 1.860 + result.from = r0; 1.861 + result.to = r1; 1.862 + } 1.863 + } else { 1.864 + result = *tzt; 1.865 + } 1.866 + found = TRUE; 1.867 + } else { 1.868 + // Find a transition within the historic transitions 1.869 + idx--; 1.870 + while (idx >= 0) { 1.871 + tzt = (Transition*)fHistoricTransitions->elementAt(idx); 1.872 + tt = tzt->time; 1.873 + if (tt < base || (inclusive && tt == base)) { 1.874 + break; 1.875 + } 1.876 + idx--; 1.877 + } 1.878 + result = *tzt; 1.879 + found = TRUE; 1.880 + } 1.881 + } 1.882 + if (found) { 1.883 + // For now, this implementation ignore transitions with only zone name changes. 1.884 + if (result.from->getRawOffset() == result.to->getRawOffset() 1.885 + && result.from->getDSTSavings() == result.to->getDSTSavings()) { 1.886 + // No offset changes. Try next one if not final 1.887 + return findPrev(result.time, FALSE /* always exclusive */, 1.888 + transitionTime, fromRule, toRule); 1.889 + } 1.890 + transitionTime = result.time; 1.891 + fromRule = result.from; 1.892 + toRule = result.to; 1.893 + return TRUE; 1.894 + } 1.895 + return FALSE; 1.896 +} 1.897 + 1.898 +UDate 1.899 +RuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local, 1.900 + int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const { 1.901 + UDate time = transition->time; 1.902 + if (local) { 1.903 + time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(), 1.904 + transition->to->getRawOffset(), transition->to->getDSTSavings(), 1.905 + NonExistingTimeOpt, DuplicatedTimeOpt); 1.906 + } 1.907 + return time; 1.908 +} 1.909 + 1.910 +int32_t 1.911 +RuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter, 1.912 + int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const { 1.913 + int32_t delta = 0; 1.914 + 1.915 + int32_t offsetBefore = rawBefore + dstBefore; 1.916 + int32_t offsetAfter = rawAfter + dstAfter; 1.917 + 1.918 + UBool dstToStd = (dstBefore != 0) && (dstAfter == 0); 1.919 + UBool stdToDst = (dstBefore == 0) && (dstAfter != 0); 1.920 + 1.921 + if (offsetAfter - offsetBefore >= 0) { 1.922 + // Positive transition, which makes a non-existing local time range 1.923 + if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd) 1.924 + || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { 1.925 + delta = offsetBefore; 1.926 + } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst) 1.927 + || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { 1.928 + delta = offsetAfter; 1.929 + } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) { 1.930 + delta = offsetBefore; 1.931 + } else { 1.932 + // Interprets the time with rule before the transition, 1.933 + // default for non-existing time range 1.934 + delta = offsetAfter; 1.935 + } 1.936 + } else { 1.937 + // Negative transition, which makes a duplicated local time range 1.938 + if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd) 1.939 + || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { 1.940 + delta = offsetAfter; 1.941 + } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst) 1.942 + || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { 1.943 + delta = offsetBefore; 1.944 + } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) { 1.945 + delta = offsetBefore; 1.946 + } else { 1.947 + // Interprets the time with rule after the transition, 1.948 + // default for duplicated local time range 1.949 + delta = offsetAfter; 1.950 + } 1.951 + } 1.952 + return delta; 1.953 +} 1.954 + 1.955 +U_NAMESPACE_END 1.956 + 1.957 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.958 + 1.959 +//eof 1.960 +