| File: | root/firefox-clang/intl/icu/source/i18n/olsontz.cpp |
| Warning: | line 607, column 16 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // © 2016 and later: Unicode, Inc. and others. | |||
| 2 | // License & terms of use: http://www.unicode.org/copyright.html | |||
| 3 | /* | |||
| 4 | ********************************************************************** | |||
| 5 | * Copyright (c) 2003-2013, International Business Machines | |||
| 6 | * Corporation and others. All Rights Reserved. | |||
| 7 | ********************************************************************** | |||
| 8 | * Author: Alan Liu | |||
| 9 | * Created: July 21 2003 | |||
| 10 | * Since: ICU 2.8 | |||
| 11 | ********************************************************************** | |||
| 12 | */ | |||
| 13 | ||||
| 14 | #include "utypeinfo.h" // for 'typeid' to work | |||
| 15 | ||||
| 16 | #include "olsontz.h" | |||
| 17 | ||||
| 18 | #if !UCONFIG_NO_FORMATTING0 | |||
| 19 | ||||
| 20 | #include "unicode/ures.h" | |||
| 21 | #include "unicode/simpletz.h" | |||
| 22 | #include "unicode/gregocal.h" | |||
| 23 | #include "gregoimp.h" | |||
| 24 | #include "cmemory.h" | |||
| 25 | #include "uassert.h" | |||
| 26 | #include "uvector.h" | |||
| 27 | #include <float.h> // DBL_MAX | |||
| 28 | #include "uresimp.h" | |||
| 29 | #include "zonemeta.h" | |||
| 30 | #include "umutex.h" | |||
| 31 | ||||
| 32 | #ifdef U_DEBUG_TZ | |||
| 33 | # include <stdio.h> | |||
| 34 | # include "uresimp.h" // for debugging | |||
| 35 | ||||
| 36 | static void debug_tz_loc(const char *f, int32_t l) | |||
| 37 | { | |||
| 38 | fprintf(stderrstderr, "%s:%d: ", f, l); | |||
| 39 | } | |||
| 40 | ||||
| 41 | static void debug_tz_msg(const char *pat, ...) | |||
| 42 | { | |||
| 43 | va_list ap; | |||
| 44 | va_start(ap, pat)__builtin_va_start(ap, pat); | |||
| 45 | vfprintf(stderrstderr, pat, ap); | |||
| 46 | fflush(stderrstderr); | |||
| 47 | } | |||
| 48 | // must use double parens, i.e.: U_DEBUG_TZ_MSG(("four is: %d",4)); | |||
| 49 | #define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__"/root/firefox-clang/intl/icu/source/i18n/olsontz.cpp",__LINE__49);debug_tz_msg x;} | |||
| 50 | #else | |||
| 51 | #define U_DEBUG_TZ_MSG(x) | |||
| 52 | #endif | |||
| 53 | ||||
| 54 | static UBool arrayEqual(const void *a1, const void *a2, int32_t size) { | |||
| 55 | if (a1 == nullptr && a2 == nullptr) { | |||
| 56 | return true; | |||
| 57 | } | |||
| 58 | if ((a1 != nullptr && a2 == nullptr) || (a1 == nullptr && a2 != nullptr)) { | |||
| 59 | return false; | |||
| 60 | } | |||
| 61 | if (a1 == a2) { | |||
| 62 | return true; | |||
| 63 | } | |||
| 64 | ||||
| 65 | return (uprv_memcmp(a1, a2, size):: memcmp(a1, a2,size) == 0); | |||
| 66 | } | |||
| 67 | ||||
| 68 | U_NAMESPACE_BEGINnamespace icu_77 { | |||
| 69 | ||||
| 70 | #define kTRANS"trans" "trans" | |||
| 71 | #define kTRANSPRE32"transPre32" "transPre32" | |||
| 72 | #define kTRANSPOST32"transPost32" "transPost32" | |||
| 73 | #define kTYPEOFFSETS"typeOffsets" "typeOffsets" | |||
| 74 | #define kTYPEMAP"typeMap" "typeMap" | |||
| 75 | #define kLINKS"links" "links" | |||
| 76 | #define kFINALRULE"finalRule" "finalRule" | |||
| 77 | #define kFINALRAW"finalRaw" "finalRaw" | |||
| 78 | #define kFINALYEAR"finalYear" "finalYear" | |||
| 79 | ||||
| 80 | #define SECONDS_PER_DAY(24*60*60) (24*60*60) | |||
| 81 | ||||
| 82 | static const int32_t ZEROS[] = {0,0}; | |||
| 83 | ||||
| 84 | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)UClassID OlsonTimeZone::getStaticClassID() { static char classID = 0; return (UClassID)&classID; } UClassID OlsonTimeZone ::getDynamicClassID() const { return OlsonTimeZone::getStaticClassID (); } | |||
| 85 | ||||
| 86 | /** | |||
| 87 | * Default constructor. Creates a time zone with an empty ID and | |||
| 88 | * a fixed GMT offset of zero. | |||
| 89 | */ | |||
| 90 | /*OlsonTimeZone::OlsonTimeZone() : finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(false) { | |||
| 91 | clearTransitionRules(); | |||
| 92 | constructEmpty(); | |||
| 93 | }*/ | |||
| 94 | ||||
| 95 | /** | |||
| 96 | * Construct a GMT+0 zone with no transitions. This is done when a | |||
| 97 | * constructor fails so the resultant object is well-behaved. | |||
| 98 | */ | |||
| 99 | void OlsonTimeZone::constructEmpty() { | |||
| 100 | canonicalID = nullptr; | |||
| 101 | ||||
| 102 | transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0; | |||
| 103 | transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = nullptr; | |||
| 104 | ||||
| 105 | typeMapData = nullptr; | |||
| 106 | ||||
| 107 | typeCount = 1; | |||
| 108 | typeOffsets = ZEROS; | |||
| 109 | ||||
| 110 | finalZone = nullptr; | |||
| 111 | } | |||
| 112 | ||||
| 113 | /** | |||
| 114 | * Construct from a resource bundle | |||
| 115 | * @param top the top-level zoneinfo resource bundle. This is used | |||
| 116 | * to lookup the rule that `res' may refer to, if there is one. | |||
| 117 | * @param res the resource bundle of the zone to be constructed | |||
| 118 | * @param ec input-output error code | |||
| 119 | */ | |||
| 120 | OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, | |||
| 121 | const UResourceBundle* res, | |||
| 122 | const UnicodeString& tzid, | |||
| 123 | UErrorCode& ec) : | |||
| 124 | BasicTimeZone(tzid), finalZone(nullptr) | |||
| 125 | { | |||
| 126 | clearTransitionRules(); | |||
| 127 | U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res))); | |||
| 128 | if ((top == nullptr || res == nullptr) && U_SUCCESS(ec)) { | |||
| 129 | ec = U_ILLEGAL_ARGUMENT_ERROR; | |||
| 130 | } | |||
| 131 | if (U_SUCCESS(ec)) { | |||
| 132 | // TODO -- clean up -- Doesn't work if res points to an alias | |||
| 133 | // // TODO remove nonconst casts below when ures_* API is fixed | |||
| 134 | // setID(ures_getKey((UResourceBundle*) res)); // cast away const | |||
| 135 | ||||
| 136 | int32_t len; | |||
| 137 | StackUResourceBundle r; | |||
| 138 | ||||
| 139 | // Pre-32bit second transitions | |||
| 140 | ures_getByKeyures_getByKey_77(res, kTRANSPRE32"transPre32", r.getAlias(), &ec); | |||
| 141 | transitionTimesPre32 = ures_getIntVectorures_getIntVector_77(r.getAlias(), &len, &ec); | |||
| 142 | transitionCountPre32 = static_cast<int16_t>(len >> 1); | |||
| 143 | if (ec == U_MISSING_RESOURCE_ERROR) { | |||
| 144 | // No pre-32bit transitions | |||
| 145 | transitionTimesPre32 = nullptr; | |||
| 146 | transitionCountPre32 = 0; | |||
| 147 | ec = U_ZERO_ERROR; | |||
| 148 | } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) { | |||
| 149 | ec = U_INVALID_FORMAT_ERROR; | |||
| 150 | } | |||
| 151 | ||||
| 152 | // 32bit second transitions | |||
| 153 | ures_getByKeyures_getByKey_77(res, kTRANS"trans", r.getAlias(), &ec); | |||
| 154 | transitionTimes32 = ures_getIntVectorures_getIntVector_77(r.getAlias(), &len, &ec); | |||
| 155 | transitionCount32 = static_cast<int16_t>(len); | |||
| 156 | if (ec == U_MISSING_RESOURCE_ERROR) { | |||
| 157 | // No 32bit transitions | |||
| 158 | transitionTimes32 = nullptr; | |||
| 159 | transitionCount32 = 0; | |||
| 160 | ec = U_ZERO_ERROR; | |||
| 161 | } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) { | |||
| 162 | ec = U_INVALID_FORMAT_ERROR; | |||
| 163 | } | |||
| 164 | ||||
| 165 | // Post-32bit second transitions | |||
| 166 | ures_getByKeyures_getByKey_77(res, kTRANSPOST32"transPost32", r.getAlias(), &ec); | |||
| 167 | transitionTimesPost32 = ures_getIntVectorures_getIntVector_77(r.getAlias(), &len, &ec); | |||
| 168 | transitionCountPost32 = static_cast<int16_t>(len >> 1); | |||
| 169 | if (ec == U_MISSING_RESOURCE_ERROR) { | |||
| 170 | // No pre-32bit transitions | |||
| 171 | transitionTimesPost32 = nullptr; | |||
| 172 | transitionCountPost32 = 0; | |||
| 173 | ec = U_ZERO_ERROR; | |||
| 174 | } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) { | |||
| 175 | ec = U_INVALID_FORMAT_ERROR; | |||
| 176 | } | |||
| 177 | ||||
| 178 | // Type offsets list must be of even size, with size >= 2 | |||
| 179 | ures_getByKeyures_getByKey_77(res, kTYPEOFFSETS"typeOffsets", r.getAlias(), &ec); | |||
| 180 | typeOffsets = ures_getIntVectorures_getIntVector_77(r.getAlias(), &len, &ec); | |||
| 181 | if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) { | |||
| 182 | ec = U_INVALID_FORMAT_ERROR; | |||
| 183 | } | |||
| 184 | typeCount = static_cast<int16_t>(len) >> 1; | |||
| 185 | ||||
| 186 | // Type map data must be of the same size as the transition count | |||
| 187 | typeMapData = nullptr; | |||
| 188 | if (transitionCount() > 0) { | |||
| 189 | ures_getByKeyures_getByKey_77(res, kTYPEMAP"typeMap", r.getAlias(), &ec); | |||
| 190 | typeMapData = ures_getBinaryures_getBinary_77(r.getAlias(), &len, &ec); | |||
| 191 | if (ec == U_MISSING_RESOURCE_ERROR) { | |||
| 192 | // no type mapping data | |||
| 193 | ec = U_INVALID_FORMAT_ERROR; | |||
| 194 | } else if (U_SUCCESS(ec) && len != transitionCount()) { | |||
| 195 | ec = U_INVALID_FORMAT_ERROR; | |||
| 196 | } | |||
| 197 | } | |||
| 198 | ||||
| 199 | // Process final rule and data, if any | |||
| 200 | if (U_SUCCESS(ec)) { | |||
| 201 | const char16_t *ruleIdUStr = ures_getStringByKeyures_getStringByKey_77(res, kFINALRULE"finalRule", &len, &ec); | |||
| 202 | ures_getByKeyures_getByKey_77(res, kFINALRAW"finalRaw", r.getAlias(), &ec); | |||
| 203 | int32_t ruleRaw = ures_getIntures_getInt_77(r.getAlias(), &ec); | |||
| 204 | ures_getByKeyures_getByKey_77(res, kFINALYEAR"finalYear", r.getAlias(), &ec); | |||
| 205 | int32_t ruleYear = ures_getIntures_getInt_77(r.getAlias(), &ec); | |||
| 206 | if (U_SUCCESS(ec)) { | |||
| 207 | UnicodeString ruleID(true, ruleIdUStr, len); | |||
| 208 | UResourceBundle *rule = TimeZone::loadRule(top, ruleID, nullptr, ec); | |||
| 209 | const int32_t *ruleData = ures_getIntVectorures_getIntVector_77(rule, &len, &ec); | |||
| 210 | if (U_SUCCESS(ec) && len == 11) { | |||
| 211 | UnicodeString emptyStr; | |||
| 212 | finalZone = new SimpleTimeZone( | |||
| 213 | ruleRaw * U_MILLIS_PER_SECOND(1000), | |||
| 214 | emptyStr, | |||
| 215 | static_cast<int8_t>(ruleData[0]), static_cast<int8_t>(ruleData[1]), static_cast<int8_t>(ruleData[2]), | |||
| 216 | ruleData[3] * U_MILLIS_PER_SECOND(1000), | |||
| 217 | static_cast<SimpleTimeZone::TimeMode>(ruleData[4]), | |||
| 218 | static_cast<int8_t>(ruleData[5]), static_cast<int8_t>(ruleData[6]), static_cast<int8_t>(ruleData[7]), | |||
| 219 | ruleData[8] * U_MILLIS_PER_SECOND(1000), | |||
| 220 | static_cast<SimpleTimeZone::TimeMode>(ruleData[9]), | |||
| 221 | ruleData[10] * U_MILLIS_PER_SECOND(1000), ec); | |||
| 222 | if (finalZone == nullptr) { | |||
| 223 | ec = U_MEMORY_ALLOCATION_ERROR; | |||
| 224 | } else { | |||
| 225 | finalStartYear = ruleYear; | |||
| 226 | ||||
| 227 | // Note: Setting finalStartYear to the finalZone is problematic. When a date is around | |||
| 228 | // year boundary, SimpleTimeZone may return false result when DST is observed at the | |||
| 229 | // beginning of year. We could apply safe margin (day or two), but when one of recurrent | |||
| 230 | // rules falls around year boundary, it could return false result. Without setting the | |||
| 231 | // start year, finalZone works fine around the year boundary of the start year. | |||
| 232 | ||||
| 233 | // finalZone->setStartYear(finalStartYear); | |||
| 234 | ||||
| 235 | ||||
| 236 | // Compute the millis for Jan 1, 0:00 GMT of the finalYear | |||
| 237 | ||||
| 238 | // Note: finalStartMillis is used for detecting either if | |||
| 239 | // historic transition data or finalZone to be used. In an | |||
| 240 | // extreme edge case - for example, two transitions fall into | |||
| 241 | // small windows of time around the year boundary, this may | |||
| 242 | // result incorrect offset computation. But I think it will | |||
| 243 | // never happen practically. Yoshito - Feb 20, 2010 | |||
| 244 | finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY(86400000); | |||
| 245 | } | |||
| 246 | } else { | |||
| 247 | ec = U_INVALID_FORMAT_ERROR; | |||
| 248 | } | |||
| 249 | ures_closeures_close_77(rule); | |||
| 250 | } else if (ec == U_MISSING_RESOURCE_ERROR) { | |||
| 251 | // No final zone | |||
| 252 | ec = U_ZERO_ERROR; | |||
| 253 | } | |||
| 254 | } | |||
| 255 | ||||
| 256 | // initialize canonical ID | |||
| 257 | canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec); | |||
| 258 | } | |||
| 259 | ||||
| 260 | if (U_FAILURE(ec)) { | |||
| 261 | constructEmpty(); | |||
| 262 | } | |||
| 263 | } | |||
| 264 | ||||
| 265 | /** | |||
| 266 | * Copy constructor | |||
| 267 | */ | |||
| 268 | OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) : | |||
| 269 | BasicTimeZone(other), finalZone(nullptr) { | |||
| 270 | *this = other; | |||
| 271 | } | |||
| 272 | ||||
| 273 | /** | |||
| 274 | * Assignment operator | |||
| 275 | */ | |||
| 276 | OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) { | |||
| 277 | if (this == &other) { return *this; } // self-assignment: no-op | |||
| 278 | canonicalID = other.canonicalID; | |||
| 279 | ||||
| 280 | transitionTimesPre32 = other.transitionTimesPre32; | |||
| 281 | transitionTimes32 = other.transitionTimes32; | |||
| 282 | transitionTimesPost32 = other.transitionTimesPost32; | |||
| 283 | ||||
| 284 | transitionCountPre32 = other.transitionCountPre32; | |||
| 285 | transitionCount32 = other.transitionCount32; | |||
| 286 | transitionCountPost32 = other.transitionCountPost32; | |||
| 287 | ||||
| 288 | typeCount = other.typeCount; | |||
| 289 | typeOffsets = other.typeOffsets; | |||
| 290 | typeMapData = other.typeMapData; | |||
| 291 | ||||
| 292 | delete finalZone; | |||
| 293 | finalZone = other.finalZone != nullptr ? other.finalZone->clone() : nullptr; | |||
| 294 | ||||
| 295 | finalStartYear = other.finalStartYear; | |||
| 296 | finalStartMillis = other.finalStartMillis; | |||
| 297 | ||||
| 298 | clearTransitionRules(); | |||
| 299 | ||||
| 300 | return *this; | |||
| 301 | } | |||
| 302 | ||||
| 303 | /** | |||
| 304 | * Destructor | |||
| 305 | */ | |||
| 306 | OlsonTimeZone::~OlsonTimeZone() { | |||
| 307 | deleteTransitionRules(); | |||
| 308 | delete finalZone; | |||
| 309 | } | |||
| 310 | ||||
| 311 | /** | |||
| 312 | * Returns true if the two TimeZone objects are equal. | |||
| 313 | */ | |||
| 314 | bool OlsonTimeZone::operator==(const TimeZone& other) const { | |||
| 315 | return ((this == &other) || | |||
| 316 | (typeid(*this) == typeid(other) && | |||
| 317 | TimeZone::operator==(other) && | |||
| 318 | hasSameRules(other))); | |||
| 319 | } | |||
| 320 | ||||
| 321 | /** | |||
| 322 | * TimeZone API. | |||
| 323 | */ | |||
| 324 | OlsonTimeZone* OlsonTimeZone::clone() const { | |||
| 325 | return new OlsonTimeZone(*this); | |||
| 326 | } | |||
| 327 | ||||
| 328 | /** | |||
| 329 | * TimeZone API. | |||
| 330 | */ | |||
| 331 | int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, | |||
| 332 | int32_t dom, uint8_t dow, | |||
| 333 | int32_t millis, UErrorCode& ec) const { | |||
| 334 | if (month < UCAL_JANUARY || month > UCAL_DECEMBER) { | |||
| 335 | if (U_SUCCESS(ec)) { | |||
| 336 | ec = U_ILLEGAL_ARGUMENT_ERROR; | |||
| 337 | } | |||
| 338 | return 0; | |||
| 339 | } else { | |||
| 340 | return getOffset(era, year, month, dom, dow, millis, | |||
| 341 | Grego::monthLength(year, month), | |||
| 342 | ec); | |||
| 343 | } | |||
| 344 | } | |||
| 345 | ||||
| 346 | /** | |||
| 347 | * TimeZone API. | |||
| 348 | */ | |||
| 349 | int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, | |||
| 350 | int32_t dom, uint8_t dow, | |||
| 351 | int32_t millis, int32_t monthLength, | |||
| 352 | UErrorCode& ec) const { | |||
| 353 | if (U_FAILURE(ec)) { | |||
| 354 | return 0; | |||
| 355 | } | |||
| 356 | ||||
| 357 | if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC) | |||
| 358 | || month < UCAL_JANUARY | |||
| 359 | || month > UCAL_DECEMBER | |||
| 360 | || dom < 1 | |||
| 361 | || dom > monthLength | |||
| 362 | || dow < UCAL_SUNDAY | |||
| 363 | || dow > UCAL_SATURDAY | |||
| 364 | || millis < 0 | |||
| 365 | || millis >= U_MILLIS_PER_DAY(86400000) | |||
| 366 | || monthLength < 28 | |||
| 367 | || monthLength > 31) { | |||
| 368 | ec = U_ILLEGAL_ARGUMENT_ERROR; | |||
| 369 | return 0; | |||
| 370 | } | |||
| 371 | ||||
| 372 | if (era == GregorianCalendar::BC) { | |||
| 373 | year = -year; | |||
| 374 | } | |||
| 375 | ||||
| 376 | if (finalZone != nullptr && year >= finalStartYear) { | |||
| 377 | return finalZone->getOffset(era, year, month, dom, dow, | |||
| 378 | millis, monthLength, ec); | |||
| 379 | } | |||
| 380 | ||||
| 381 | // Compute local epoch millis from input fields | |||
| 382 | UDate date = static_cast<UDate>(Grego::fieldsToDay(year, month, dom) * U_MILLIS_PER_DAY(86400000) + millis); | |||
| 383 | int32_t rawoff, dstoff; | |||
| 384 | getHistoricalOffset(date, true, kDaylight, kStandard, rawoff, dstoff); | |||
| 385 | return rawoff + dstoff; | |||
| 386 | } | |||
| 387 | ||||
| 388 | /** | |||
| 389 | * TimeZone API. | |||
| 390 | */ | |||
| 391 | void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff, | |||
| 392 | int32_t& dstoff, UErrorCode& ec) const { | |||
| 393 | if (U_FAILURE(ec)) { | |||
| 394 | return; | |||
| 395 | } | |||
| 396 | if (finalZone != nullptr && date >= finalStartMillis) { | |||
| 397 | finalZone->getOffset(date, local, rawoff, dstoff, ec); | |||
| 398 | } else { | |||
| 399 | getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff); | |||
| 400 | } | |||
| 401 | } | |||
| 402 | ||||
| 403 | void OlsonTimeZone::getOffsetFromLocal(UDate date, UTimeZoneLocalOption nonExistingTimeOpt, | |||
| 404 | UTimeZoneLocalOption duplicatedTimeOpt, | |||
| 405 | int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const { | |||
| 406 | if (U_FAILURE(ec)) { | |||
| 407 | return; | |||
| 408 | } | |||
| 409 | if (finalZone != nullptr && date >= finalStartMillis) { | |||
| 410 | finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec); | |||
| 411 | } else { | |||
| 412 | getHistoricalOffset(date, true, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff); | |||
| 413 | } | |||
| 414 | } | |||
| 415 | ||||
| 416 | ||||
| 417 | /** | |||
| 418 | * TimeZone API. | |||
| 419 | */ | |||
| 420 | void OlsonTimeZone::setRawOffset(int32_t /*offsetMillis*/) { | |||
| 421 | // We don't support this operation, since OlsonTimeZones are | |||
| 422 | // immutable (except for the ID, which is in the base class). | |||
| 423 | ||||
| 424 | // Nothing to do! | |||
| 425 | } | |||
| 426 | ||||
| 427 | /** | |||
| 428 | * TimeZone API. | |||
| 429 | */ | |||
| 430 | int32_t OlsonTimeZone::getRawOffset() const { | |||
| 431 | UErrorCode ec = U_ZERO_ERROR; | |||
| 432 | int32_t raw, dst; | |||
| 433 | getOffset(uprv_getUTCtimeuprv_getUTCtime_77(), false, raw, dst, ec); | |||
| 434 | return raw; | |||
| 435 | } | |||
| 436 | ||||
| 437 | #if defined U_DEBUG_TZ | |||
| 438 | void printTime(double ms) { | |||
| 439 | int32_t year; | |||
| 440 | int8_t month, dom, dow; | |||
| 441 | int32_t millis=0; | |||
| 442 | UErrorCode status = U_ZERO_ERROR; | |||
| 443 | Grego::timeToFields(ms, year, month, dom, dow, millis, status); | |||
| 444 | U_DEBUG_TZ_MSG((" getHistoricalOffset: time %.1f (%04d.%02d.%02d+%.1fh)\n", ms, | |||
| 445 | year, month+1, dom, (millis/kOneHour))); | |||
| 446 | } | |||
| 447 | #endif | |||
| 448 | ||||
| 449 | int64_t | |||
| 450 | OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const { | |||
| 451 | U_ASSERT(transIdx >= 0 && transIdx < transitionCount())(static_cast <bool> (transIdx >= 0 && transIdx < transitionCount()) ? void (0) : __assert_fail ("transIdx >= 0 && transIdx < transitionCount()" , __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__ )); | |||
| 452 | ||||
| 453 | if (transIdx < transitionCountPre32) { | |||
| 454 | return (static_cast<int64_t>(static_cast<uint32_t>(transitionTimesPre32[transIdx << 1])) << 32) | |||
| 455 | | static_cast<int64_t>(static_cast<uint32_t>(transitionTimesPre32[(transIdx << 1) + 1])); | |||
| 456 | } | |||
| 457 | ||||
| 458 | transIdx -= transitionCountPre32; | |||
| 459 | if (transIdx < transitionCount32) { | |||
| 460 | return static_cast<int64_t>(transitionTimes32[transIdx]); | |||
| 461 | } | |||
| 462 | ||||
| 463 | transIdx -= transitionCount32; | |||
| 464 | return (static_cast<int64_t>(static_cast<uint32_t>(transitionTimesPost32[transIdx << 1])) << 32) | |||
| 465 | | static_cast<int64_t>(static_cast<uint32_t>(transitionTimesPost32[(transIdx << 1) + 1])); | |||
| 466 | } | |||
| 467 | ||||
| 468 | // Maximum absolute offset in seconds (86400 seconds = 1 day) | |||
| 469 | // getHistoricalOffset uses this constant as safety margin of | |||
| 470 | // quick zone transition checking. | |||
| 471 | #define MAX_OFFSET_SECONDS86400 86400 | |||
| 472 | ||||
| 473 | void | |||
| 474 | OlsonTimeZone::getHistoricalOffset(UDate date, UBool local, | |||
| 475 | int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt, | |||
| 476 | int32_t& rawoff, int32_t& dstoff) const { | |||
| 477 | U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst)\n", | |||
| 478 | date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt)); | |||
| 479 | #if defined U_DEBUG_TZ | |||
| 480 | printTime(date*1000.0); | |||
| 481 | #endif | |||
| 482 | int16_t transCount = transitionCount(); | |||
| 483 | ||||
| 484 | if (transCount > 0) { | |||
| 485 | double sec = uprv_flooruprv_floor_77(date / U_MILLIS_PER_SECOND(1000)); | |||
| 486 | if (!local && sec < transitionTimeInSeconds(0)) { | |||
| 487 | // Before the first transition time | |||
| 488 | rawoff = initialRawOffset() * U_MILLIS_PER_SECOND(1000); | |||
| 489 | dstoff = initialDstOffset() * U_MILLIS_PER_SECOND(1000); | |||
| 490 | } else { | |||
| 491 | // Linear search from the end is the fastest approach, since | |||
| 492 | // most lookups will happen at/near the end. | |||
| 493 | int16_t transIdx; | |||
| 494 | for (transIdx = transCount - 1; transIdx >= 0; transIdx--) { | |||
| 495 | int64_t transition = transitionTimeInSeconds(transIdx); | |||
| 496 | ||||
| 497 | if (local && (sec >= (transition - MAX_OFFSET_SECONDS86400))) { | |||
| 498 | int32_t offsetBefore = zoneOffsetAt(transIdx - 1); | |||
| 499 | UBool dstBefore = dstOffsetAt(transIdx - 1) != 0; | |||
| 500 | ||||
| 501 | int32_t offsetAfter = zoneOffsetAt(transIdx); | |||
| 502 | UBool dstAfter = dstOffsetAt(transIdx) != 0; | |||
| 503 | ||||
| 504 | UBool dstToStd = dstBefore && !dstAfter; | |||
| 505 | UBool stdToDst = !dstBefore && dstAfter; | |||
| 506 | ||||
| 507 | if (offsetAfter - offsetBefore >= 0) { | |||
| 508 | // Positive transition, which makes a non-existing local time range | |||
| 509 | if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd) | |||
| 510 | || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { | |||
| 511 | transition += offsetBefore; | |||
| 512 | } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst) | |||
| 513 | || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { | |||
| 514 | transition += offsetAfter; | |||
| 515 | } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) { | |||
| 516 | transition += offsetBefore; | |||
| 517 | } else { | |||
| 518 | // Interprets the time with rule before the transition, | |||
| 519 | // default for non-existing time range | |||
| 520 | transition += offsetAfter; | |||
| 521 | } | |||
| 522 | } else { | |||
| 523 | // Negative transition, which makes a duplicated local time range | |||
| 524 | if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd) | |||
| 525 | || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { | |||
| 526 | transition += offsetAfter; | |||
| 527 | } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst) | |||
| 528 | || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { | |||
| 529 | transition += offsetBefore; | |||
| 530 | } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) { | |||
| 531 | transition += offsetBefore; | |||
| 532 | } else { | |||
| 533 | // Interprets the time with rule after the transition, | |||
| 534 | // default for duplicated local time range | |||
| 535 | transition += offsetAfter; | |||
| 536 | } | |||
| 537 | } | |||
| 538 | } | |||
| 539 | if (sec >= transition) { | |||
| 540 | break; | |||
| 541 | } | |||
| 542 | } | |||
| 543 | // transIdx could be -1 when local=true | |||
| 544 | rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND(1000); | |||
| 545 | dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND(1000); | |||
| 546 | } | |||
| 547 | } else { | |||
| 548 | // No transitions, single pair of offsets only | |||
| 549 | rawoff = initialRawOffset() * U_MILLIS_PER_SECOND(1000); | |||
| 550 | dstoff = initialDstOffset() * U_MILLIS_PER_SECOND(1000); | |||
| 551 | } | |||
| 552 | U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n", | |||
| 553 | date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff)); | |||
| 554 | } | |||
| 555 | ||||
| 556 | /** | |||
| 557 | * TimeZone API. | |||
| 558 | */ | |||
| 559 | UBool OlsonTimeZone::useDaylightTime() const { | |||
| 560 | // If DST was observed in 1942 (for example) but has never been | |||
| 561 | // observed from 1943 to the present, most clients will expect | |||
| 562 | // this method to return false. This method determines whether | |||
| 563 | // DST is in use in the current year (at any point in the year) | |||
| 564 | // and returns true if so. | |||
| 565 | ||||
| 566 | UDate current = uprv_getUTCtimeuprv_getUTCtime_77(); | |||
| 567 | if (finalZone != nullptr && current >= finalStartMillis) { | |||
| 568 | return finalZone->useDaylightTime(); | |||
| 569 | } | |||
| 570 | ||||
| 571 | UErrorCode status = U_ZERO_ERROR; | |||
| 572 | int32_t year = Grego::timeToYear(current, status); | |||
| 573 | U_ASSERT(U_SUCCESS(status))(static_cast <bool> (U_SUCCESS(status)) ? void (0) : __assert_fail ("U_SUCCESS(status)", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__)); | |||
| 574 | if (U_FAILURE(status)) return false; // If error, just return false. | |||
| 575 | ||||
| 576 | // Find start of this year, and start of next year | |||
| 577 | double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY(24*60*60); | |||
| 578 | double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY(24*60*60); | |||
| 579 | ||||
| 580 | // Return true if DST is observed at any time during the current | |||
| 581 | // year. | |||
| 582 | for (int16_t i = 0; i < transitionCount(); ++i) { | |||
| 583 | double transition = static_cast<double>(transitionTimeInSeconds(i)); | |||
| 584 | if (transition >= limit) { | |||
| 585 | break; | |||
| 586 | } | |||
| 587 | if ((transition >= start && dstOffsetAt(i) != 0) | |||
| 588 | || (transition > start && dstOffsetAt(i - 1) != 0)) { | |||
| 589 | return true; | |||
| 590 | } | |||
| 591 | } | |||
| 592 | return false; | |||
| 593 | } | |||
| 594 | int32_t | |||
| 595 | OlsonTimeZone::getDSTSavings() const{ | |||
| 596 | if (finalZone != nullptr){ | |||
| 597 | return finalZone->getDSTSavings(); | |||
| 598 | } | |||
| 599 | return TimeZone::getDSTSavings(); | |||
| 600 | } | |||
| 601 | /** | |||
| 602 | * TimeZone API. | |||
| 603 | */ | |||
| 604 | UBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const { | |||
| 605 | int32_t raw, dst; | |||
| ||||
| 606 | getOffset(date, false, raw, dst, ec); | |||
| 607 | return dst != 0; | |||
| ||||
| 608 | } | |||
| 609 | ||||
| 610 | UBool | |||
| 611 | OlsonTimeZone::hasSameRules(const TimeZone &other) const { | |||
| 612 | if (this == &other) { | |||
| 613 | return true; | |||
| 614 | } | |||
| 615 | const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other); | |||
| 616 | if (z == nullptr) { | |||
| 617 | return false; | |||
| 618 | } | |||
| 619 | ||||
| 620 | // [sic] pointer comparison: typeMapData points into | |||
| 621 | // memory-mapped or DLL space, so if two zones have the same | |||
| 622 | // pointer, they are equal. | |||
| 623 | if (typeMapData == z->typeMapData) { | |||
| 624 | return true; | |||
| 625 | } | |||
| 626 | ||||
| 627 | // If the pointers are not equal, the zones may still | |||
| 628 | // be equal if their rules and transitions are equal | |||
| 629 | if ((finalZone == nullptr && z->finalZone != nullptr) | |||
| 630 | || (finalZone != nullptr && z->finalZone == nullptr) | |||
| 631 | || (finalZone != nullptr && z->finalZone != nullptr && *finalZone != *z->finalZone)) { | |||
| 632 | return false; | |||
| 633 | } | |||
| 634 | ||||
| 635 | if (finalZone != nullptr) { | |||
| 636 | if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) { | |||
| 637 | return false; | |||
| 638 | } | |||
| 639 | } | |||
| 640 | if (typeCount != z->typeCount | |||
| 641 | || transitionCountPre32 != z->transitionCountPre32 | |||
| 642 | || transitionCount32 != z->transitionCount32 | |||
| 643 | || transitionCountPost32 != z->transitionCountPost32) { | |||
| 644 | return false; | |||
| 645 | } | |||
| 646 | ||||
| 647 | return | |||
| 648 | arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1) | |||
| 649 | && arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32) | |||
| 650 | && arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1) | |||
| 651 | && arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1) | |||
| 652 | && arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount()); | |||
| 653 | } | |||
| 654 | ||||
| 655 | void | |||
| 656 | OlsonTimeZone::clearTransitionRules() { | |||
| 657 | initialRule = nullptr; | |||
| 658 | firstTZTransition = nullptr; | |||
| 659 | firstFinalTZTransition = nullptr; | |||
| 660 | historicRules = nullptr; | |||
| 661 | historicRuleCount = 0; | |||
| 662 | finalZoneWithStartYear = nullptr; | |||
| 663 | firstTZTransitionIdx = 0; | |||
| 664 | transitionRulesInitOnce.reset(); | |||
| 665 | } | |||
| 666 | ||||
| 667 | void | |||
| 668 | OlsonTimeZone::deleteTransitionRules() { | |||
| 669 | delete initialRule; | |||
| 670 | delete firstTZTransition; | |||
| 671 | delete firstFinalTZTransition; | |||
| 672 | delete finalZoneWithStartYear; | |||
| 673 | if (historicRules != nullptr) { | |||
| 674 | for (int i = 0; i < historicRuleCount; i++) { | |||
| 675 | if (historicRules[i] != nullptr) { | |||
| 676 | delete historicRules[i]; | |||
| 677 | } | |||
| 678 | } | |||
| 679 | uprv_freeuprv_free_77(historicRules); | |||
| 680 | } | |||
| 681 | clearTransitionRules(); | |||
| 682 | } | |||
| 683 | ||||
| 684 | /* | |||
| 685 | * Lazy transition rules initializer | |||
| 686 | */ | |||
| 687 | ||||
| 688 | static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) { | |||
| 689 | This->initTransitionRules(status); | |||
| 690 | } | |||
| 691 | ||||
| 692 | void | |||
| 693 | OlsonTimeZone::checkTransitionRules(UErrorCode& status) const { | |||
| 694 | OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this); | |||
| 695 | umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status); | |||
| 696 | } | |||
| 697 | ||||
| 698 | void | |||
| 699 | OlsonTimeZone::initTransitionRules(UErrorCode& status) { | |||
| 700 | if(U_FAILURE(status)) { | |||
| 701 | return; | |||
| 702 | } | |||
| 703 | deleteTransitionRules(); | |||
| 704 | UnicodeString tzid; | |||
| 705 | getID(tzid); | |||
| 706 | ||||
| 707 | UnicodeString stdName = tzid + UNICODE_STRING_SIMPLE("(STD)")icu::UnicodeString(true, u"(STD)", -1); | |||
| 708 | UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)")icu::UnicodeString(true, u"(DST)", -1); | |||
| 709 | ||||
| 710 | int32_t raw, dst; | |||
| 711 | ||||
| 712 | // Create initial rule | |||
| 713 | raw = initialRawOffset() * U_MILLIS_PER_SECOND(1000); | |||
| 714 | dst = initialDstOffset() * U_MILLIS_PER_SECOND(1000); | |||
| 715 | initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst); | |||
| 716 | // Check to make sure initialRule was created | |||
| 717 | if (initialRule == nullptr) { | |||
| 718 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 719 | deleteTransitionRules(); | |||
| 720 | return; | |||
| 721 | } | |||
| 722 | ||||
| 723 | int32_t transCount = transitionCount(); | |||
| 724 | if (transCount > 0) { | |||
| 725 | int16_t transitionIdx, typeIdx; | |||
| 726 | ||||
| 727 | // We probably no longer need to check the first "real" transition | |||
| 728 | // here, because the new tzcode remove such transitions already. | |||
| 729 | // For now, keeping this code for just in case. Feb 19, 2010 Yoshito | |||
| 730 | firstTZTransitionIdx = 0; | |||
| 731 | for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) { | |||
| 732 | if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type | |||
| 733 | break; | |||
| 734 | } | |||
| 735 | firstTZTransitionIdx++; | |||
| 736 | } | |||
| 737 | if (transitionIdx == transCount) { | |||
| 738 | // Actually no transitions... | |||
| 739 | } else { | |||
| 740 | // Build historic rule array | |||
| 741 | UDate* times = static_cast<UDate*>(uprv_mallocuprv_malloc_77(sizeof(UDate) * transCount)); /* large enough to store all transition times */ | |||
| 742 | if (times == nullptr) { | |||
| 743 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 744 | deleteTransitionRules(); | |||
| 745 | return; | |||
| 746 | } | |||
| 747 | for (typeIdx = 0; typeIdx < typeCount; typeIdx++) { | |||
| 748 | // Gather all start times for each pair of offsets | |||
| 749 | int32_t nTimes = 0; | |||
| 750 | for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) { | |||
| 751 | if (typeIdx == static_cast<int16_t>(typeMapData[transitionIdx])) { | |||
| 752 | UDate tt = static_cast<UDate>(transitionTime(transitionIdx)); | |||
| 753 | if (finalZone == nullptr || tt <= finalStartMillis) { | |||
| 754 | // Exclude transitions after finalMillis | |||
| 755 | times[nTimes++] = tt; | |||
| 756 | } | |||
| 757 | } | |||
| 758 | } | |||
| 759 | if (nTimes > 0) { | |||
| 760 | // Create a TimeArrayTimeZoneRule | |||
| 761 | raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND(1000); | |||
| 762 | dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND(1000); | |||
| 763 | if (historicRules == nullptr) { | |||
| 764 | historicRuleCount = typeCount; | |||
| 765 | historicRules = static_cast<TimeArrayTimeZoneRule**>(uprv_mallocuprv_malloc_77(sizeof(TimeArrayTimeZoneRule*) * historicRuleCount)); | |||
| 766 | if (historicRules == nullptr) { | |||
| 767 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 768 | deleteTransitionRules(); | |||
| 769 | uprv_freeuprv_free_77(times); | |||
| 770 | return; | |||
| 771 | } | |||
| 772 | for (int i = 0; i < historicRuleCount; i++) { | |||
| 773 | // Initialize TimeArrayTimeZoneRule pointers as nullptr | |||
| 774 | historicRules[i] = nullptr; | |||
| 775 | } | |||
| 776 | } | |||
| 777 | historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName), | |||
| 778 | raw, dst, times, nTimes, DateTimeRule::UTC_TIME); | |||
| 779 | // Check for memory allocation error | |||
| 780 | if (historicRules[typeIdx] == nullptr) { | |||
| 781 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 782 | deleteTransitionRules(); | |||
| 783 | return; | |||
| 784 | } | |||
| 785 | } | |||
| 786 | } | |||
| 787 | uprv_freeuprv_free_77(times); | |||
| 788 | ||||
| 789 | // Create initial transition | |||
| 790 | typeIdx = static_cast<int16_t>(typeMapData[firstTZTransitionIdx]); | |||
| 791 | firstTZTransition = new TimeZoneTransition(static_cast<UDate>(transitionTime(firstTZTransitionIdx)), | |||
| 792 | *initialRule, *historicRules[typeIdx]); | |||
| 793 | // Check to make sure firstTZTransition was created. | |||
| 794 | if (firstTZTransition == nullptr) { | |||
| 795 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 796 | deleteTransitionRules(); | |||
| 797 | return; | |||
| 798 | } | |||
| 799 | } | |||
| 800 | } | |||
| 801 | if (finalZone != nullptr) { | |||
| 802 | // Get the first occurrence of final rule starts | |||
| 803 | UDate startTime = static_cast<UDate>(finalStartMillis); | |||
| 804 | TimeZoneRule *firstFinalRule = nullptr; | |||
| 805 | ||||
| 806 | if (finalZone->useDaylightTime()) { | |||
| 807 | /* | |||
| 808 | * Note: When an OlsonTimeZone is constructed, we should set the final year | |||
| 809 | * as the start year of finalZone. However, the boundary condition used for | |||
| 810 | * getting offset from finalZone has some problems. | |||
| 811 | * For now, we do not set the valid start year when the construction time | |||
| 812 | * and create a clone and set the start year when extracting rules. | |||
| 813 | */ | |||
| 814 | finalZoneWithStartYear = finalZone->clone(); | |||
| 815 | // Check to make sure finalZone was actually cloned. | |||
| 816 | if (finalZoneWithStartYear == nullptr) { | |||
| 817 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 818 | deleteTransitionRules(); | |||
| 819 | return; | |||
| 820 | } | |||
| 821 | finalZoneWithStartYear->setStartYear(finalStartYear); | |||
| 822 | ||||
| 823 | TimeZoneTransition tzt; | |||
| 824 | finalZoneWithStartYear->getNextTransition(startTime, false, tzt); | |||
| 825 | firstFinalRule = tzt.getTo()->clone(); | |||
| 826 | // Check to make sure firstFinalRule received proper clone. | |||
| 827 | if (firstFinalRule == nullptr) { | |||
| 828 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 829 | deleteTransitionRules(); | |||
| 830 | return; | |||
| 831 | } | |||
| 832 | startTime = tzt.getTime(); | |||
| 833 | } else { | |||
| 834 | // final rule with no transitions | |||
| 835 | finalZoneWithStartYear = finalZone->clone(); | |||
| 836 | // Check to make sure finalZone was actually cloned. | |||
| 837 | if (finalZoneWithStartYear == nullptr) { | |||
| 838 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 839 | deleteTransitionRules(); | |||
| 840 | return; | |||
| 841 | } | |||
| 842 | finalZone->getID(tzid); | |||
| 843 | firstFinalRule = new TimeArrayTimeZoneRule(tzid, | |||
| 844 | finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME); | |||
| 845 | // Check firstFinalRule was properly created. | |||
| 846 | if (firstFinalRule == nullptr) { | |||
| 847 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 848 | deleteTransitionRules(); | |||
| 849 | return; | |||
| 850 | } | |||
| 851 | } | |||
| 852 | TimeZoneRule *prevRule = nullptr; | |||
| 853 | if (transCount > 0) { | |||
| 854 | prevRule = historicRules[typeMapData[transCount - 1]]; | |||
| 855 | } | |||
| 856 | if (prevRule == nullptr) { | |||
| 857 | // No historic transitions, but only finalZone available | |||
| 858 | prevRule = initialRule; | |||
| 859 | } | |||
| 860 | firstFinalTZTransition = new TimeZoneTransition(); | |||
| 861 | // Check to make sure firstFinalTZTransition was created before dereferencing | |||
| 862 | if (firstFinalTZTransition == nullptr) { | |||
| 863 | status = U_MEMORY_ALLOCATION_ERROR; | |||
| 864 | deleteTransitionRules(); | |||
| 865 | return; | |||
| 866 | } | |||
| 867 | firstFinalTZTransition->setTime(startTime); | |||
| 868 | firstFinalTZTransition->adoptFrom(prevRule->clone()); | |||
| 869 | firstFinalTZTransition->adoptTo(firstFinalRule); | |||
| 870 | } | |||
| 871 | } | |||
| 872 | ||||
| 873 | UBool | |||
| 874 | OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const { | |||
| 875 | UErrorCode status = U_ZERO_ERROR; | |||
| 876 | checkTransitionRules(status); | |||
| 877 | if (U_FAILURE(status)) { | |||
| 878 | return false; | |||
| 879 | } | |||
| 880 | ||||
| 881 | if (finalZone != nullptr) { | |||
| 882 | if (inclusive && base == firstFinalTZTransition->getTime()) { | |||
| 883 | result = *firstFinalTZTransition; | |||
| 884 | return true; | |||
| 885 | } else if (base >= firstFinalTZTransition->getTime()) { | |||
| 886 | if (finalZone->useDaylightTime()) { | |||
| 887 | //return finalZone->getNextTransition(base, inclusive, result); | |||
| 888 | return finalZoneWithStartYear->getNextTransition(base, inclusive, result); | |||
| 889 | } else { | |||
| 890 | // No more transitions | |||
| 891 | return false; | |||
| 892 | } | |||
| 893 | } | |||
| 894 | } | |||
| 895 | if (historicRules != nullptr) { | |||
| 896 | // Find a historical transition | |||
| 897 | int16_t transCount = transitionCount(); | |||
| 898 | int16_t ttidx = transCount - 1; | |||
| 899 | for (; ttidx >= firstTZTransitionIdx; ttidx--) { | |||
| 900 | UDate t = static_cast<UDate>(transitionTime(ttidx)); | |||
| 901 | if (base > t || (!inclusive && base == t)) { | |||
| 902 | break; | |||
| 903 | } | |||
| 904 | } | |||
| 905 | if (ttidx == transCount - 1) { | |||
| 906 | if (firstFinalTZTransition != nullptr) { | |||
| 907 | result = *firstFinalTZTransition; | |||
| 908 | return true; | |||
| 909 | } else { | |||
| 910 | return false; | |||
| 911 | } | |||
| 912 | } else if (ttidx < firstTZTransitionIdx) { | |||
| 913 | result = *firstTZTransition; | |||
| 914 | return true; | |||
| 915 | } else { | |||
| 916 | // Create a TimeZoneTransition | |||
| 917 | TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]]; | |||
| 918 | TimeZoneRule *from = historicRules[typeMapData[ttidx]]; | |||
| 919 | UDate startTime = static_cast<UDate>(transitionTime(ttidx + 1)); | |||
| 920 | ||||
| 921 | // The transitions loaded from zoneinfo.res may contain non-transition data | |||
| 922 | UnicodeString fromName, toName; | |||
| 923 | from->getName(fromName); | |||
| 924 | to->getName(toName); | |||
| 925 | if (fromName == toName && from->getRawOffset() == to->getRawOffset() | |||
| 926 | && from->getDSTSavings() == to->getDSTSavings()) { | |||
| 927 | return getNextTransition(startTime, false, result); | |||
| 928 | } | |||
| 929 | result.setTime(startTime); | |||
| 930 | result.adoptFrom(from->clone()); | |||
| 931 | result.adoptTo(to->clone()); | |||
| 932 | return true; | |||
| 933 | } | |||
| 934 | } | |||
| 935 | return false; | |||
| 936 | } | |||
| 937 | ||||
| 938 | UBool | |||
| 939 | OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const { | |||
| 940 | UErrorCode status = U_ZERO_ERROR; | |||
| 941 | checkTransitionRules(status); | |||
| 942 | if (U_FAILURE(status)) { | |||
| 943 | return false; | |||
| 944 | } | |||
| 945 | ||||
| 946 | if (finalZone != nullptr) { | |||
| 947 | if (inclusive && base == firstFinalTZTransition->getTime()) { | |||
| 948 | result = *firstFinalTZTransition; | |||
| 949 | return true; | |||
| 950 | } else if (base > firstFinalTZTransition->getTime()) { | |||
| 951 | if (finalZone->useDaylightTime()) { | |||
| 952 | //return finalZone->getPreviousTransition(base, inclusive, result); | |||
| 953 | return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result); | |||
| 954 | } else { | |||
| 955 | result = *firstFinalTZTransition; | |||
| 956 | return true; | |||
| 957 | } | |||
| 958 | } | |||
| 959 | } | |||
| 960 | ||||
| 961 | if (historicRules != nullptr) { | |||
| 962 | // Find a historical transition | |||
| 963 | int16_t ttidx = transitionCount() - 1; | |||
| 964 | for (; ttidx >= firstTZTransitionIdx; ttidx--) { | |||
| 965 | UDate t = static_cast<UDate>(transitionTime(ttidx)); | |||
| 966 | if (base > t || (inclusive && base == t)) { | |||
| 967 | break; | |||
| 968 | } | |||
| 969 | } | |||
| 970 | if (ttidx < firstTZTransitionIdx) { | |||
| 971 | // No more transitions | |||
| 972 | return false; | |||
| 973 | } else if (ttidx == firstTZTransitionIdx) { | |||
| 974 | result = *firstTZTransition; | |||
| 975 | return true; | |||
| 976 | } else { | |||
| 977 | // Create a TimeZoneTransition | |||
| 978 | TimeZoneRule *to = historicRules[typeMapData[ttidx]]; | |||
| 979 | TimeZoneRule *from = historicRules[typeMapData[ttidx-1]]; | |||
| 980 | UDate startTime = static_cast<UDate>(transitionTime(ttidx)); | |||
| 981 | ||||
| 982 | // The transitions loaded from zoneinfo.res may contain non-transition data | |||
| 983 | UnicodeString fromName, toName; | |||
| 984 | from->getName(fromName); | |||
| 985 | to->getName(toName); | |||
| 986 | if (fromName == toName && from->getRawOffset() == to->getRawOffset() | |||
| 987 | && from->getDSTSavings() == to->getDSTSavings()) { | |||
| 988 | return getPreviousTransition(startTime, false, result); | |||
| 989 | } | |||
| 990 | result.setTime(startTime); | |||
| 991 | result.adoptFrom(from->clone()); | |||
| 992 | result.adoptTo(to->clone()); | |||
| 993 | return true; | |||
| 994 | } | |||
| 995 | } | |||
| 996 | return false; | |||
| 997 | } | |||
| 998 | ||||
| 999 | int32_t | |||
| 1000 | OlsonTimeZone::countTransitionRules(UErrorCode& status) const { | |||
| 1001 | if (U_FAILURE(status)) { | |||
| 1002 | return 0; | |||
| 1003 | } | |||
| 1004 | checkTransitionRules(status); | |||
| 1005 | if (U_FAILURE(status)) { | |||
| 1006 | return 0; | |||
| 1007 | } | |||
| 1008 | ||||
| 1009 | int32_t count = 0; | |||
| 1010 | if (historicRules != nullptr) { | |||
| 1011 | // historicRules may contain null entries when original zoneinfo data | |||
| 1012 | // includes non transition data. | |||
| 1013 | for (int32_t i = 0; i < historicRuleCount; i++) { | |||
| 1014 | if (historicRules[i] != nullptr) { | |||
| 1015 | count++; | |||
| 1016 | } | |||
| 1017 | } | |||
| 1018 | } | |||
| 1019 | if (finalZone != nullptr) { | |||
| 1020 | if (finalZone->useDaylightTime()) { | |||
| 1021 | count += 2; | |||
| 1022 | } else { | |||
| 1023 | count++; | |||
| 1024 | } | |||
| 1025 | } | |||
| 1026 | return count; | |||
| 1027 | } | |||
| 1028 | ||||
| 1029 | void | |||
| 1030 | OlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial, | |||
| 1031 | const TimeZoneRule* trsrules[], | |||
| 1032 | int32_t& trscount, | |||
| 1033 | UErrorCode& status) const { | |||
| 1034 | if (U_FAILURE(status)) { | |||
| 1035 | return; | |||
| 1036 | } | |||
| 1037 | checkTransitionRules(status); | |||
| 1038 | if (U_FAILURE(status)) { | |||
| 1039 | return; | |||
| 1040 | } | |||
| 1041 | ||||
| 1042 | // Initial rule | |||
| 1043 | initial = initialRule; | |||
| 1044 | ||||
| 1045 | // Transition rules | |||
| 1046 | int32_t cnt = 0; | |||
| 1047 | if (historicRules != nullptr && trscount > cnt) { | |||
| 1048 | // historicRules may contain null entries when original zoneinfo data | |||
| 1049 | // includes non transition data. | |||
| 1050 | for (int32_t i = 0; i < historicRuleCount; i++) { | |||
| 1051 | if (historicRules[i] != nullptr) { | |||
| 1052 | trsrules[cnt++] = historicRules[i]; | |||
| 1053 | if (cnt >= trscount) { | |||
| 1054 | break; | |||
| 1055 | } | |||
| 1056 | } | |||
| 1057 | } | |||
| 1058 | } | |||
| 1059 | if (finalZoneWithStartYear != nullptr && trscount > cnt) { | |||
| 1060 | const InitialTimeZoneRule *tmpini; | |||
| 1061 | int32_t tmpcnt = trscount - cnt; | |||
| 1062 | finalZoneWithStartYear->getTimeZoneRules(tmpini, &trsrules[cnt], tmpcnt, status); | |||
| 1063 | if (U_FAILURE(status)) { | |||
| 1064 | return; | |||
| 1065 | } | |||
| 1066 | cnt += tmpcnt; | |||
| 1067 | } | |||
| 1068 | // Set the result length | |||
| 1069 | trscount = cnt; | |||
| 1070 | } | |||
| 1071 | ||||
| 1072 | U_NAMESPACE_END} | |||
| 1073 | ||||
| 1074 | #endif // !UCONFIG_NO_FORMATTING | |||
| 1075 | ||||
| 1076 | //eof |