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