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