olsontz.cpp (40025B)
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_FORMATTING 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(stderr, "%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); 45 vfprintf(stderr, pat, ap); 46 fflush(stderr); 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__,__LINE__);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) == 0); 66 } 67 68 U_NAMESPACE_BEGIN 69 70 #define kTRANS "trans" 71 #define kTRANSPRE32 "transPre32" 72 #define kTRANSPOST32 "transPost32" 73 #define kTYPEOFFSETS "typeOffsets" 74 #define kTYPEMAP "typeMap" 75 #define kLINKS "links" 76 #define kFINALRULE "finalRule" 77 #define kFINALRAW "finalRaw" 78 #define kFINALYEAR "finalYear" 79 80 #define SECONDS_PER_DAY (24*60*60) 81 82 static const int32_t ZEROS[] = {0,0}; 83 84 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone) 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_getByKey(res, kTRANSPRE32, r.getAlias(), &ec); 141 transitionTimesPre32 = ures_getIntVector(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_getByKey(res, kTRANS, r.getAlias(), &ec); 154 transitionTimes32 = ures_getIntVector(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_getByKey(res, kTRANSPOST32, r.getAlias(), &ec); 167 transitionTimesPost32 = ures_getIntVector(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_getByKey(res, kTYPEOFFSETS, r.getAlias(), &ec); 180 typeOffsets = ures_getIntVector(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_getByKey(res, kTYPEMAP, r.getAlias(), &ec); 190 typeMapData = ures_getBinary(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_getStringByKey(res, kFINALRULE, &len, &ec); 202 ures_getByKey(res, kFINALRAW, r.getAlias(), &ec); 203 int32_t ruleRaw = ures_getInt(r.getAlias(), &ec); 204 ures_getByKey(res, kFINALYEAR, r.getAlias(), &ec); 205 int32_t ruleYear = ures_getInt(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_getIntVector(rule, &len, &ec); 210 if (U_SUCCESS(ec) && len == 11) { 211 UnicodeString emptyStr; 212 finalZone = new SimpleTimeZone( 213 ruleRaw * U_MILLIS_PER_SECOND, 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, 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, 220 static_cast<SimpleTimeZone::TimeMode>(ruleData[9]), 221 ruleData[10] * U_MILLIS_PER_SECOND, 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; 245 } 246 } else { 247 ec = U_INVALID_FORMAT_ERROR; 248 } 249 ures_close(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 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 + 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_getUTCtime(), 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()); 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_SECONDS 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_floor(date / U_MILLIS_PER_SECOND); 486 if (!local && sec < transitionTimeInSeconds(0)) { 487 // Before the first transition time 488 rawoff = initialRawOffset() * U_MILLIS_PER_SECOND; 489 dstoff = initialDstOffset() * U_MILLIS_PER_SECOND; 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_SECONDS))) { 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; 545 dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND; 546 } 547 } else { 548 // No transitions, single pair of offsets only 549 rawoff = initialRawOffset() * U_MILLIS_PER_SECOND; 550 dstoff = initialDstOffset() * U_MILLIS_PER_SECOND; 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_getUTCtime(); 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)); 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; 578 double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY; 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_free(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)"); 708 UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)"); 709 710 int32_t raw, dst; 711 712 // Create initial rule 713 raw = initialRawOffset() * U_MILLIS_PER_SECOND; 714 dst = initialDstOffset() * U_MILLIS_PER_SECOND; 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_malloc(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; 762 dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND; 763 if (historicRules == nullptr) { 764 historicRuleCount = typeCount; 765 historicRules = static_cast<TimeArrayTimeZoneRule**>(uprv_malloc(sizeof(TimeArrayTimeZoneRule*) * historicRuleCount)); 766 if (historicRules == nullptr) { 767 status = U_MEMORY_ALLOCATION_ERROR; 768 deleteTransitionRules(); 769 uprv_free(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_free(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