1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/olsontz.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1081 @@ 1.4 +/* 1.5 +********************************************************************** 1.6 +* Copyright (c) 2003-2013, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +********************************************************************** 1.9 +* Author: Alan Liu 1.10 +* Created: July 21 2003 1.11 +* Since: ICU 2.8 1.12 +********************************************************************** 1.13 +*/ 1.14 + 1.15 +#include "utypeinfo.h" // for 'typeid' to work 1.16 + 1.17 +#include "olsontz.h" 1.18 + 1.19 +#if !UCONFIG_NO_FORMATTING 1.20 + 1.21 +#include "unicode/ures.h" 1.22 +#include "unicode/simpletz.h" 1.23 +#include "unicode/gregocal.h" 1.24 +#include "gregoimp.h" 1.25 +#include "cmemory.h" 1.26 +#include "uassert.h" 1.27 +#include "uvector.h" 1.28 +#include <float.h> // DBL_MAX 1.29 +#include "uresimp.h" // struct UResourceBundle 1.30 +#include "zonemeta.h" 1.31 +#include "umutex.h" 1.32 + 1.33 +#ifdef U_DEBUG_TZ 1.34 +# include <stdio.h> 1.35 +# include "uresimp.h" // for debugging 1.36 + 1.37 +static void debug_tz_loc(const char *f, int32_t l) 1.38 +{ 1.39 + fprintf(stderr, "%s:%d: ", f, l); 1.40 +} 1.41 + 1.42 +static void debug_tz_msg(const char *pat, ...) 1.43 +{ 1.44 + va_list ap; 1.45 + va_start(ap, pat); 1.46 + vfprintf(stderr, pat, ap); 1.47 + fflush(stderr); 1.48 +} 1.49 +// must use double parens, i.e.: U_DEBUG_TZ_MSG(("four is: %d",4)); 1.50 +#define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;} 1.51 +#else 1.52 +#define U_DEBUG_TZ_MSG(x) 1.53 +#endif 1.54 + 1.55 +static UBool arrayEqual(const void *a1, const void *a2, int32_t size) { 1.56 + if (a1 == NULL && a2 == NULL) { 1.57 + return TRUE; 1.58 + } 1.59 + if ((a1 != NULL && a2 == NULL) || (a1 == NULL && a2 != NULL)) { 1.60 + return FALSE; 1.61 + } 1.62 + if (a1 == a2) { 1.63 + return TRUE; 1.64 + } 1.65 + 1.66 + return (uprv_memcmp(a1, a2, size) == 0); 1.67 +} 1.68 + 1.69 +U_NAMESPACE_BEGIN 1.70 + 1.71 +#define kTRANS "trans" 1.72 +#define kTRANSPRE32 "transPre32" 1.73 +#define kTRANSPOST32 "transPost32" 1.74 +#define kTYPEOFFSETS "typeOffsets" 1.75 +#define kTYPEMAP "typeMap" 1.76 +#define kLINKS "links" 1.77 +#define kFINALRULE "finalRule" 1.78 +#define kFINALRAW "finalRaw" 1.79 +#define kFINALYEAR "finalYear" 1.80 + 1.81 +#define SECONDS_PER_DAY (24*60*60) 1.82 + 1.83 +static const int32_t ZEROS[] = {0,0}; 1.84 + 1.85 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone) 1.86 + 1.87 +/** 1.88 + * Default constructor. Creates a time zone with an empty ID and 1.89 + * a fixed GMT offset of zero. 1.90 + */ 1.91 +/*OlsonTimeZone::OlsonTimeZone() : finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(FALSE) { 1.92 + clearTransitionRules(); 1.93 + constructEmpty(); 1.94 +}*/ 1.95 + 1.96 +/** 1.97 + * Construct a GMT+0 zone with no transitions. This is done when a 1.98 + * constructor fails so the resultant object is well-behaved. 1.99 + */ 1.100 +void OlsonTimeZone::constructEmpty() { 1.101 + canonicalID = NULL; 1.102 + 1.103 + transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0; 1.104 + transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL; 1.105 + 1.106 + typeMapData = NULL; 1.107 + 1.108 + typeCount = 1; 1.109 + typeOffsets = ZEROS; 1.110 + 1.111 + finalZone = NULL; 1.112 +} 1.113 + 1.114 +/** 1.115 + * Construct from a resource bundle 1.116 + * @param top the top-level zoneinfo resource bundle. This is used 1.117 + * to lookup the rule that `res' may refer to, if there is one. 1.118 + * @param res the resource bundle of the zone to be constructed 1.119 + * @param ec input-output error code 1.120 + */ 1.121 +OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, 1.122 + const UResourceBundle* res, 1.123 + const UnicodeString& tzid, 1.124 + UErrorCode& ec) : 1.125 + BasicTimeZone(tzid), finalZone(NULL) 1.126 +{ 1.127 + clearTransitionRules(); 1.128 + U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res))); 1.129 + if ((top == NULL || res == NULL) && U_SUCCESS(ec)) { 1.130 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.131 + } 1.132 + if (U_SUCCESS(ec)) { 1.133 + // TODO -- clean up -- Doesn't work if res points to an alias 1.134 + // // TODO remove nonconst casts below when ures_* API is fixed 1.135 + // setID(ures_getKey((UResourceBundle*) res)); // cast away const 1.136 + 1.137 + int32_t len; 1.138 + UResourceBundle r; 1.139 + ures_initStackObject(&r); 1.140 + 1.141 + // Pre-32bit second transitions 1.142 + ures_getByKey(res, kTRANSPRE32, &r, &ec); 1.143 + transitionTimesPre32 = ures_getIntVector(&r, &len, &ec); 1.144 + transitionCountPre32 = len >> 1; 1.145 + if (ec == U_MISSING_RESOURCE_ERROR) { 1.146 + // No pre-32bit transitions 1.147 + transitionTimesPre32 = NULL; 1.148 + transitionCountPre32 = 0; 1.149 + ec = U_ZERO_ERROR; 1.150 + } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) { 1.151 + ec = U_INVALID_FORMAT_ERROR; 1.152 + } 1.153 + 1.154 + // 32bit second transitions 1.155 + ures_getByKey(res, kTRANS, &r, &ec); 1.156 + transitionTimes32 = ures_getIntVector(&r, &len, &ec); 1.157 + transitionCount32 = len; 1.158 + if (ec == U_MISSING_RESOURCE_ERROR) { 1.159 + // No 32bit transitions 1.160 + transitionTimes32 = NULL; 1.161 + transitionCount32 = 0; 1.162 + ec = U_ZERO_ERROR; 1.163 + } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) { 1.164 + ec = U_INVALID_FORMAT_ERROR; 1.165 + } 1.166 + 1.167 + // Post-32bit second transitions 1.168 + ures_getByKey(res, kTRANSPOST32, &r, &ec); 1.169 + transitionTimesPost32 = ures_getIntVector(&r, &len, &ec); 1.170 + transitionCountPost32 = len >> 1; 1.171 + if (ec == U_MISSING_RESOURCE_ERROR) { 1.172 + // No pre-32bit transitions 1.173 + transitionTimesPost32 = NULL; 1.174 + transitionCountPost32 = 0; 1.175 + ec = U_ZERO_ERROR; 1.176 + } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) { 1.177 + ec = U_INVALID_FORMAT_ERROR; 1.178 + } 1.179 + 1.180 + // Type offsets list must be of even size, with size >= 2 1.181 + ures_getByKey(res, kTYPEOFFSETS, &r, &ec); 1.182 + typeOffsets = ures_getIntVector(&r, &len, &ec); 1.183 + if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) { 1.184 + ec = U_INVALID_FORMAT_ERROR; 1.185 + } 1.186 + typeCount = (int16_t) len >> 1; 1.187 + 1.188 + // Type map data must be of the same size as the transition count 1.189 + typeMapData = NULL; 1.190 + if (transitionCount() > 0) { 1.191 + ures_getByKey(res, kTYPEMAP, &r, &ec); 1.192 + typeMapData = ures_getBinary(&r, &len, &ec); 1.193 + if (ec == U_MISSING_RESOURCE_ERROR) { 1.194 + // no type mapping data 1.195 + ec = U_INVALID_FORMAT_ERROR; 1.196 + } else if (U_SUCCESS(ec) && len != transitionCount()) { 1.197 + ec = U_INVALID_FORMAT_ERROR; 1.198 + } 1.199 + } 1.200 + 1.201 + // Process final rule and data, if any 1.202 + const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec); 1.203 + ures_getByKey(res, kFINALRAW, &r, &ec); 1.204 + int32_t ruleRaw = ures_getInt(&r, &ec); 1.205 + ures_getByKey(res, kFINALYEAR, &r, &ec); 1.206 + int32_t ruleYear = ures_getInt(&r, &ec); 1.207 + if (U_SUCCESS(ec)) { 1.208 + UnicodeString ruleID(TRUE, ruleIdUStr, len); 1.209 + UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec); 1.210 + const int32_t *ruleData = ures_getIntVector(rule, &len, &ec); 1.211 + if (U_SUCCESS(ec) && len == 11) { 1.212 + UnicodeString emptyStr; 1.213 + finalZone = new SimpleTimeZone( 1.214 + ruleRaw * U_MILLIS_PER_SECOND, 1.215 + emptyStr, 1.216 + (int8_t)ruleData[0], (int8_t)ruleData[1], (int8_t)ruleData[2], 1.217 + ruleData[3] * U_MILLIS_PER_SECOND, 1.218 + (SimpleTimeZone::TimeMode) ruleData[4], 1.219 + (int8_t)ruleData[5], (int8_t)ruleData[6], (int8_t)ruleData[7], 1.220 + ruleData[8] * U_MILLIS_PER_SECOND, 1.221 + (SimpleTimeZone::TimeMode) ruleData[9], 1.222 + ruleData[10] * U_MILLIS_PER_SECOND, ec); 1.223 + if (finalZone == NULL) { 1.224 + ec = U_MEMORY_ALLOCATION_ERROR; 1.225 + } else { 1.226 + finalStartYear = ruleYear; 1.227 + 1.228 + // Note: Setting finalStartYear to the finalZone is problematic. When a date is around 1.229 + // year boundary, SimpleTimeZone may return false result when DST is observed at the 1.230 + // beginning of year. We could apply safe margin (day or two), but when one of recurrent 1.231 + // rules falls around year boundary, it could return false result. Without setting the 1.232 + // start year, finalZone works fine around the year boundary of the start year. 1.233 + 1.234 + // finalZone->setStartYear(finalStartYear); 1.235 + 1.236 + 1.237 + // Compute the millis for Jan 1, 0:00 GMT of the finalYear 1.238 + 1.239 + // Note: finalStartMillis is used for detecting either if 1.240 + // historic transition data or finalZone to be used. In an 1.241 + // extreme edge case - for example, two transitions fall into 1.242 + // small windows of time around the year boundary, this may 1.243 + // result incorrect offset computation. But I think it will 1.244 + // never happen practically. Yoshito - Feb 20, 2010 1.245 + finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY; 1.246 + } 1.247 + } else { 1.248 + ec = U_INVALID_FORMAT_ERROR; 1.249 + } 1.250 + ures_close(rule); 1.251 + } else if (ec == U_MISSING_RESOURCE_ERROR) { 1.252 + // No final zone 1.253 + ec = U_ZERO_ERROR; 1.254 + } 1.255 + ures_close(&r); 1.256 + 1.257 + // initialize canonical ID 1.258 + canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec); 1.259 + } 1.260 + 1.261 + if (U_FAILURE(ec)) { 1.262 + constructEmpty(); 1.263 + } 1.264 +} 1.265 + 1.266 +/** 1.267 + * Copy constructor 1.268 + */ 1.269 +OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) : 1.270 + BasicTimeZone(other), finalZone(0) { 1.271 + *this = other; 1.272 +} 1.273 + 1.274 +/** 1.275 + * Assignment operator 1.276 + */ 1.277 +OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) { 1.278 + canonicalID = other.canonicalID; 1.279 + 1.280 + transitionTimesPre32 = other.transitionTimesPre32; 1.281 + transitionTimes32 = other.transitionTimes32; 1.282 + transitionTimesPost32 = other.transitionTimesPost32; 1.283 + 1.284 + transitionCountPre32 = other.transitionCountPre32; 1.285 + transitionCount32 = other.transitionCount32; 1.286 + transitionCountPost32 = other.transitionCountPost32; 1.287 + 1.288 + typeCount = other.typeCount; 1.289 + typeOffsets = other.typeOffsets; 1.290 + typeMapData = other.typeMapData; 1.291 + 1.292 + delete finalZone; 1.293 + finalZone = (other.finalZone != 0) ? 1.294 + (SimpleTimeZone*) other.finalZone->clone() : 0; 1.295 + 1.296 + finalStartYear = other.finalStartYear; 1.297 + finalStartMillis = other.finalStartMillis; 1.298 + 1.299 + clearTransitionRules(); 1.300 + 1.301 + return *this; 1.302 +} 1.303 + 1.304 +/** 1.305 + * Destructor 1.306 + */ 1.307 +OlsonTimeZone::~OlsonTimeZone() { 1.308 + deleteTransitionRules(); 1.309 + delete finalZone; 1.310 +} 1.311 + 1.312 +/** 1.313 + * Returns true if the two TimeZone objects are equal. 1.314 + */ 1.315 +UBool OlsonTimeZone::operator==(const TimeZone& other) const { 1.316 + return ((this == &other) || 1.317 + (typeid(*this) == typeid(other) && 1.318 + TimeZone::operator==(other) && 1.319 + hasSameRules(other))); 1.320 +} 1.321 + 1.322 +/** 1.323 + * TimeZone API. 1.324 + */ 1.325 +TimeZone* OlsonTimeZone::clone() const { 1.326 + return new OlsonTimeZone(*this); 1.327 +} 1.328 + 1.329 +/** 1.330 + * TimeZone API. 1.331 + */ 1.332 +int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, 1.333 + int32_t dom, uint8_t dow, 1.334 + int32_t millis, UErrorCode& ec) const { 1.335 + if (month < UCAL_JANUARY || month > UCAL_DECEMBER) { 1.336 + if (U_SUCCESS(ec)) { 1.337 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.338 + } 1.339 + return 0; 1.340 + } else { 1.341 + return getOffset(era, year, month, dom, dow, millis, 1.342 + Grego::monthLength(year, month), 1.343 + ec); 1.344 + } 1.345 +} 1.346 + 1.347 +/** 1.348 + * TimeZone API. 1.349 + */ 1.350 +int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, 1.351 + int32_t dom, uint8_t dow, 1.352 + int32_t millis, int32_t monthLength, 1.353 + UErrorCode& ec) const { 1.354 + if (U_FAILURE(ec)) { 1.355 + return 0; 1.356 + } 1.357 + 1.358 + if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC) 1.359 + || month < UCAL_JANUARY 1.360 + || month > UCAL_DECEMBER 1.361 + || dom < 1 1.362 + || dom > monthLength 1.363 + || dow < UCAL_SUNDAY 1.364 + || dow > UCAL_SATURDAY 1.365 + || millis < 0 1.366 + || millis >= U_MILLIS_PER_DAY 1.367 + || monthLength < 28 1.368 + || monthLength > 31) { 1.369 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.370 + return 0; 1.371 + } 1.372 + 1.373 + if (era == GregorianCalendar::BC) { 1.374 + year = -year; 1.375 + } 1.376 + 1.377 + if (finalZone != NULL && year >= finalStartYear) { 1.378 + return finalZone->getOffset(era, year, month, dom, dow, 1.379 + millis, monthLength, ec); 1.380 + } 1.381 + 1.382 + // Compute local epoch millis from input fields 1.383 + UDate date = (UDate)(Grego::fieldsToDay(year, month, dom) * U_MILLIS_PER_DAY + millis); 1.384 + int32_t rawoff, dstoff; 1.385 + getHistoricalOffset(date, TRUE, kDaylight, kStandard, rawoff, dstoff); 1.386 + return rawoff + dstoff; 1.387 +} 1.388 + 1.389 +/** 1.390 + * TimeZone API. 1.391 + */ 1.392 +void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff, 1.393 + int32_t& dstoff, UErrorCode& ec) const { 1.394 + if (U_FAILURE(ec)) { 1.395 + return; 1.396 + } 1.397 + if (finalZone != NULL && date >= finalStartMillis) { 1.398 + finalZone->getOffset(date, local, rawoff, dstoff, ec); 1.399 + } else { 1.400 + getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff); 1.401 + } 1.402 +} 1.403 + 1.404 +void 1.405 +OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, 1.406 + int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const { 1.407 + if (U_FAILURE(ec)) { 1.408 + return; 1.409 + } 1.410 + if (finalZone != NULL && date >= finalStartMillis) { 1.411 + finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec); 1.412 + } else { 1.413 + getHistoricalOffset(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff); 1.414 + } 1.415 +} 1.416 + 1.417 + 1.418 +/** 1.419 + * TimeZone API. 1.420 + */ 1.421 +void OlsonTimeZone::setRawOffset(int32_t /*offsetMillis*/) { 1.422 + // We don't support this operation, since OlsonTimeZones are 1.423 + // immutable (except for the ID, which is in the base class). 1.424 + 1.425 + // Nothing to do! 1.426 +} 1.427 + 1.428 +/** 1.429 + * TimeZone API. 1.430 + */ 1.431 +int32_t OlsonTimeZone::getRawOffset() const { 1.432 + UErrorCode ec = U_ZERO_ERROR; 1.433 + int32_t raw, dst; 1.434 + getOffset((double) uprv_getUTCtime() * U_MILLIS_PER_SECOND, 1.435 + FALSE, raw, dst, ec); 1.436 + return raw; 1.437 +} 1.438 + 1.439 +#if defined U_DEBUG_TZ 1.440 +void printTime(double ms) { 1.441 + int32_t year, month, dom, dow; 1.442 + double millis=0; 1.443 + double days = ClockMath::floorDivide(((double)ms), (double)U_MILLIS_PER_DAY, millis); 1.444 + 1.445 + Grego::dayToFields(days, year, month, dom, dow); 1.446 + U_DEBUG_TZ_MSG((" getHistoricalOffset: time %.1f (%04d.%02d.%02d+%.1fh)\n", ms, 1.447 + year, month+1, dom, (millis/kOneHour))); 1.448 + } 1.449 +#endif 1.450 + 1.451 +int64_t 1.452 +OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const { 1.453 + U_ASSERT(transIdx >= 0 && transIdx < transitionCount()); 1.454 + 1.455 + if (transIdx < transitionCountPre32) { 1.456 + return (((int64_t)((uint32_t)transitionTimesPre32[transIdx << 1])) << 32) 1.457 + | ((int64_t)((uint32_t)transitionTimesPre32[(transIdx << 1) + 1])); 1.458 + } 1.459 + 1.460 + transIdx -= transitionCountPre32; 1.461 + if (transIdx < transitionCount32) { 1.462 + return (int64_t)transitionTimes32[transIdx]; 1.463 + } 1.464 + 1.465 + transIdx -= transitionCount32; 1.466 + return (((int64_t)((uint32_t)transitionTimesPost32[transIdx << 1])) << 32) 1.467 + | ((int64_t)((uint32_t)transitionTimesPost32[(transIdx << 1) + 1])); 1.468 +} 1.469 + 1.470 +// Maximum absolute offset in seconds (86400 seconds = 1 day) 1.471 +// getHistoricalOffset uses this constant as safety margin of 1.472 +// quick zone transition checking. 1.473 +#define MAX_OFFSET_SECONDS 86400 1.474 + 1.475 +void 1.476 +OlsonTimeZone::getHistoricalOffset(UDate date, UBool local, 1.477 + int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt, 1.478 + int32_t& rawoff, int32_t& dstoff) const { 1.479 + U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst)\n", 1.480 + date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt)); 1.481 +#if defined U_DEBUG_TZ 1.482 + printTime(date*1000.0); 1.483 +#endif 1.484 + int16_t transCount = transitionCount(); 1.485 + 1.486 + if (transCount > 0) { 1.487 + double sec = uprv_floor(date / U_MILLIS_PER_SECOND); 1.488 + if (!local && sec < transitionTimeInSeconds(0)) { 1.489 + // Before the first transition time 1.490 + rawoff = initialRawOffset() * U_MILLIS_PER_SECOND; 1.491 + dstoff = initialDstOffset() * U_MILLIS_PER_SECOND; 1.492 + } else { 1.493 + // Linear search from the end is the fastest approach, since 1.494 + // most lookups will happen at/near the end. 1.495 + int16_t transIdx; 1.496 + for (transIdx = transCount - 1; transIdx >= 0; transIdx--) { 1.497 + int64_t transition = transitionTimeInSeconds(transIdx); 1.498 + 1.499 + if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) { 1.500 + int32_t offsetBefore = zoneOffsetAt(transIdx - 1); 1.501 + UBool dstBefore = dstOffsetAt(transIdx - 1) != 0; 1.502 + 1.503 + int32_t offsetAfter = zoneOffsetAt(transIdx); 1.504 + UBool dstAfter = dstOffsetAt(transIdx) != 0; 1.505 + 1.506 + UBool dstToStd = dstBefore && !dstAfter; 1.507 + UBool stdToDst = !dstBefore && dstAfter; 1.508 + 1.509 + if (offsetAfter - offsetBefore >= 0) { 1.510 + // Positive transition, which makes a non-existing local time range 1.511 + if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd) 1.512 + || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { 1.513 + transition += offsetBefore; 1.514 + } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst) 1.515 + || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { 1.516 + transition += offsetAfter; 1.517 + } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) { 1.518 + transition += offsetBefore; 1.519 + } else { 1.520 + // Interprets the time with rule before the transition, 1.521 + // default for non-existing time range 1.522 + transition += offsetAfter; 1.523 + } 1.524 + } else { 1.525 + // Negative transition, which makes a duplicated local time range 1.526 + if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd) 1.527 + || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) { 1.528 + transition += offsetAfter; 1.529 + } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst) 1.530 + || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) { 1.531 + transition += offsetBefore; 1.532 + } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) { 1.533 + transition += offsetBefore; 1.534 + } else { 1.535 + // Interprets the time with rule after the transition, 1.536 + // default for duplicated local time range 1.537 + transition += offsetAfter; 1.538 + } 1.539 + } 1.540 + } 1.541 + if (sec >= transition) { 1.542 + break; 1.543 + } 1.544 + } 1.545 + // transIdx could be -1 when local=true 1.546 + rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND; 1.547 + dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND; 1.548 + } 1.549 + } else { 1.550 + // No transitions, single pair of offsets only 1.551 + rawoff = initialRawOffset() * U_MILLIS_PER_SECOND; 1.552 + dstoff = initialDstOffset() * U_MILLIS_PER_SECOND; 1.553 + } 1.554 + U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n", 1.555 + date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff)); 1.556 +} 1.557 + 1.558 +/** 1.559 + * TimeZone API. 1.560 + */ 1.561 +UBool OlsonTimeZone::useDaylightTime() const { 1.562 + // If DST was observed in 1942 (for example) but has never been 1.563 + // observed from 1943 to the present, most clients will expect 1.564 + // this method to return FALSE. This method determines whether 1.565 + // DST is in use in the current year (at any point in the year) 1.566 + // and returns TRUE if so. 1.567 + 1.568 + UDate current = uprv_getUTCtime(); 1.569 + if (finalZone != NULL && current >= finalStartMillis) { 1.570 + return finalZone->useDaylightTime(); 1.571 + } 1.572 + 1.573 + int32_t year, month, dom, dow, doy, mid; 1.574 + Grego::timeToFields(current, year, month, dom, dow, doy, mid); 1.575 + 1.576 + // Find start of this year, and start of next year 1.577 + double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY; 1.578 + double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY; 1.579 + 1.580 + // Return TRUE if DST is observed at any time during the current 1.581 + // year. 1.582 + for (int16_t i = 0; i < transitionCount(); ++i) { 1.583 + double transition = (double)transitionTimeInSeconds(i); 1.584 + if (transition >= limit) { 1.585 + break; 1.586 + } 1.587 + if ((transition >= start && dstOffsetAt(i) != 0) 1.588 + || (transition > start && dstOffsetAt(i - 1) != 0)) { 1.589 + return TRUE; 1.590 + } 1.591 + } 1.592 + return FALSE; 1.593 +} 1.594 +int32_t 1.595 +OlsonTimeZone::getDSTSavings() const{ 1.596 + if (finalZone != NULL){ 1.597 + return finalZone->getDSTSavings(); 1.598 + } 1.599 + return TimeZone::getDSTSavings(); 1.600 +} 1.601 +/** 1.602 + * TimeZone API. 1.603 + */ 1.604 +UBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const { 1.605 + int32_t raw, dst; 1.606 + getOffset(date, FALSE, raw, dst, ec); 1.607 + return dst != 0; 1.608 +} 1.609 + 1.610 +UBool 1.611 +OlsonTimeZone::hasSameRules(const TimeZone &other) const { 1.612 + if (this == &other) { 1.613 + return TRUE; 1.614 + } 1.615 + const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other); 1.616 + if (z == NULL) { 1.617 + return FALSE; 1.618 + } 1.619 + 1.620 + // [sic] pointer comparison: typeMapData points into 1.621 + // memory-mapped or DLL space, so if two zones have the same 1.622 + // pointer, they are equal. 1.623 + if (typeMapData == z->typeMapData) { 1.624 + return TRUE; 1.625 + } 1.626 + 1.627 + // If the pointers are not equal, the zones may still 1.628 + // be equal if their rules and transitions are equal 1.629 + if ((finalZone == NULL && z->finalZone != NULL) 1.630 + || (finalZone != NULL && z->finalZone == NULL) 1.631 + || (finalZone != NULL && z->finalZone != NULL && *finalZone != *z->finalZone)) { 1.632 + return FALSE; 1.633 + } 1.634 + 1.635 + if (finalZone != NULL) { 1.636 + if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) { 1.637 + return FALSE; 1.638 + } 1.639 + } 1.640 + if (typeCount != z->typeCount 1.641 + || transitionCountPre32 != z->transitionCountPre32 1.642 + || transitionCount32 != z->transitionCount32 1.643 + || transitionCountPost32 != z->transitionCountPost32) { 1.644 + return FALSE; 1.645 + } 1.646 + 1.647 + return 1.648 + arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1) 1.649 + && arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32) 1.650 + && arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1) 1.651 + && arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1) 1.652 + && arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount()); 1.653 +} 1.654 + 1.655 +void 1.656 +OlsonTimeZone::clearTransitionRules(void) { 1.657 + initialRule = NULL; 1.658 + firstTZTransition = NULL; 1.659 + firstFinalTZTransition = NULL; 1.660 + historicRules = NULL; 1.661 + historicRuleCount = 0; 1.662 + finalZoneWithStartYear = NULL; 1.663 + firstTZTransitionIdx = 0; 1.664 + transitionRulesInitOnce.reset(); 1.665 +} 1.666 + 1.667 +void 1.668 +OlsonTimeZone::deleteTransitionRules(void) { 1.669 + if (initialRule != NULL) { 1.670 + delete initialRule; 1.671 + } 1.672 + if (firstTZTransition != NULL) { 1.673 + delete firstTZTransition; 1.674 + } 1.675 + if (firstFinalTZTransition != NULL) { 1.676 + delete firstFinalTZTransition; 1.677 + } 1.678 + if (finalZoneWithStartYear != NULL) { 1.679 + delete finalZoneWithStartYear; 1.680 + } 1.681 + if (historicRules != NULL) { 1.682 + for (int i = 0; i < historicRuleCount; i++) { 1.683 + if (historicRules[i] != NULL) { 1.684 + delete historicRules[i]; 1.685 + } 1.686 + } 1.687 + uprv_free(historicRules); 1.688 + } 1.689 + clearTransitionRules(); 1.690 +} 1.691 + 1.692 +/* 1.693 + * Lazy transition rules initializer 1.694 + */ 1.695 + 1.696 +static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) { 1.697 + This->initTransitionRules(status); 1.698 +} 1.699 + 1.700 +void 1.701 +OlsonTimeZone::checkTransitionRules(UErrorCode& status) const { 1.702 + OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this); 1.703 + umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status); 1.704 +} 1.705 + 1.706 +void 1.707 +OlsonTimeZone::initTransitionRules(UErrorCode& status) { 1.708 + if(U_FAILURE(status)) { 1.709 + return; 1.710 + } 1.711 + deleteTransitionRules(); 1.712 + UnicodeString tzid; 1.713 + getID(tzid); 1.714 + 1.715 + UnicodeString stdName = tzid + UNICODE_STRING_SIMPLE("(STD)"); 1.716 + UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)"); 1.717 + 1.718 + int32_t raw, dst; 1.719 + 1.720 + // Create initial rule 1.721 + raw = initialRawOffset() * U_MILLIS_PER_SECOND; 1.722 + dst = initialDstOffset() * U_MILLIS_PER_SECOND; 1.723 + initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst); 1.724 + // Check to make sure initialRule was created 1.725 + if (initialRule == NULL) { 1.726 + status = U_MEMORY_ALLOCATION_ERROR; 1.727 + deleteTransitionRules(); 1.728 + return; 1.729 + } 1.730 + 1.731 + int32_t transCount = transitionCount(); 1.732 + if (transCount > 0) { 1.733 + int16_t transitionIdx, typeIdx; 1.734 + 1.735 + // We probably no longer need to check the first "real" transition 1.736 + // here, because the new tzcode remove such transitions already. 1.737 + // For now, keeping this code for just in case. Feb 19, 2010 Yoshito 1.738 + firstTZTransitionIdx = 0; 1.739 + for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) { 1.740 + if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type 1.741 + break; 1.742 + } 1.743 + firstTZTransitionIdx++; 1.744 + } 1.745 + if (transitionIdx == transCount) { 1.746 + // Actually no transitions... 1.747 + } else { 1.748 + // Build historic rule array 1.749 + UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transCount); /* large enough to store all transition times */ 1.750 + if (times == NULL) { 1.751 + status = U_MEMORY_ALLOCATION_ERROR; 1.752 + deleteTransitionRules(); 1.753 + return; 1.754 + } 1.755 + for (typeIdx = 0; typeIdx < typeCount; typeIdx++) { 1.756 + // Gather all start times for each pair of offsets 1.757 + int32_t nTimes = 0; 1.758 + for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) { 1.759 + if (typeIdx == (int16_t)typeMapData[transitionIdx]) { 1.760 + UDate tt = (UDate)transitionTime(transitionIdx); 1.761 + if (finalZone == NULL || tt <= finalStartMillis) { 1.762 + // Exclude transitions after finalMillis 1.763 + times[nTimes++] = tt; 1.764 + } 1.765 + } 1.766 + } 1.767 + if (nTimes > 0) { 1.768 + // Create a TimeArrayTimeZoneRule 1.769 + raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND; 1.770 + dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND; 1.771 + if (historicRules == NULL) { 1.772 + historicRuleCount = typeCount; 1.773 + historicRules = (TimeArrayTimeZoneRule**)uprv_malloc(sizeof(TimeArrayTimeZoneRule*)*historicRuleCount); 1.774 + if (historicRules == NULL) { 1.775 + status = U_MEMORY_ALLOCATION_ERROR; 1.776 + deleteTransitionRules(); 1.777 + uprv_free(times); 1.778 + return; 1.779 + } 1.780 + for (int i = 0; i < historicRuleCount; i++) { 1.781 + // Initialize TimeArrayTimeZoneRule pointers as NULL 1.782 + historicRules[i] = NULL; 1.783 + } 1.784 + } 1.785 + historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName), 1.786 + raw, dst, times, nTimes, DateTimeRule::UTC_TIME); 1.787 + // Check for memory allocation error 1.788 + if (historicRules[typeIdx] == NULL) { 1.789 + status = U_MEMORY_ALLOCATION_ERROR; 1.790 + deleteTransitionRules(); 1.791 + return; 1.792 + } 1.793 + } 1.794 + } 1.795 + uprv_free(times); 1.796 + 1.797 + // Create initial transition 1.798 + typeIdx = (int16_t)typeMapData[firstTZTransitionIdx]; 1.799 + firstTZTransition = new TimeZoneTransition((UDate)transitionTime(firstTZTransitionIdx), 1.800 + *initialRule, *historicRules[typeIdx]); 1.801 + // Check to make sure firstTZTransition was created. 1.802 + if (firstTZTransition == NULL) { 1.803 + status = U_MEMORY_ALLOCATION_ERROR; 1.804 + deleteTransitionRules(); 1.805 + return; 1.806 + } 1.807 + } 1.808 + } 1.809 + if (finalZone != NULL) { 1.810 + // Get the first occurence of final rule starts 1.811 + UDate startTime = (UDate)finalStartMillis; 1.812 + TimeZoneRule *firstFinalRule = NULL; 1.813 + 1.814 + if (finalZone->useDaylightTime()) { 1.815 + /* 1.816 + * Note: When an OlsonTimeZone is constructed, we should set the final year 1.817 + * as the start year of finalZone. However, the bounday condition used for 1.818 + * getting offset from finalZone has some problems. 1.819 + * For now, we do not set the valid start year when the construction time 1.820 + * and create a clone and set the start year when extracting rules. 1.821 + */ 1.822 + finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone(); 1.823 + // Check to make sure finalZone was actually cloned. 1.824 + if (finalZoneWithStartYear == NULL) { 1.825 + status = U_MEMORY_ALLOCATION_ERROR; 1.826 + deleteTransitionRules(); 1.827 + return; 1.828 + } 1.829 + finalZoneWithStartYear->setStartYear(finalStartYear); 1.830 + 1.831 + TimeZoneTransition tzt; 1.832 + finalZoneWithStartYear->getNextTransition(startTime, false, tzt); 1.833 + firstFinalRule = tzt.getTo()->clone(); 1.834 + // Check to make sure firstFinalRule received proper clone. 1.835 + if (firstFinalRule == NULL) { 1.836 + status = U_MEMORY_ALLOCATION_ERROR; 1.837 + deleteTransitionRules(); 1.838 + return; 1.839 + } 1.840 + startTime = tzt.getTime(); 1.841 + } else { 1.842 + // final rule with no transitions 1.843 + finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone(); 1.844 + // Check to make sure finalZone was actually cloned. 1.845 + if (finalZoneWithStartYear == NULL) { 1.846 + status = U_MEMORY_ALLOCATION_ERROR; 1.847 + deleteTransitionRules(); 1.848 + return; 1.849 + } 1.850 + finalZone->getID(tzid); 1.851 + firstFinalRule = new TimeArrayTimeZoneRule(tzid, 1.852 + finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME); 1.853 + // Check firstFinalRule was properly created. 1.854 + if (firstFinalRule == NULL) { 1.855 + status = U_MEMORY_ALLOCATION_ERROR; 1.856 + deleteTransitionRules(); 1.857 + return; 1.858 + } 1.859 + } 1.860 + TimeZoneRule *prevRule = NULL; 1.861 + if (transCount > 0) { 1.862 + prevRule = historicRules[typeMapData[transCount - 1]]; 1.863 + } 1.864 + if (prevRule == NULL) { 1.865 + // No historic transitions, but only finalZone available 1.866 + prevRule = initialRule; 1.867 + } 1.868 + firstFinalTZTransition = new TimeZoneTransition(); 1.869 + // Check to make sure firstFinalTZTransition was created before dereferencing 1.870 + if (firstFinalTZTransition == NULL) { 1.871 + status = U_MEMORY_ALLOCATION_ERROR; 1.872 + deleteTransitionRules(); 1.873 + return; 1.874 + } 1.875 + firstFinalTZTransition->setTime(startTime); 1.876 + firstFinalTZTransition->adoptFrom(prevRule->clone()); 1.877 + firstFinalTZTransition->adoptTo(firstFinalRule); 1.878 + } 1.879 +} 1.880 + 1.881 +UBool 1.882 +OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const { 1.883 + UErrorCode status = U_ZERO_ERROR; 1.884 + checkTransitionRules(status); 1.885 + if (U_FAILURE(status)) { 1.886 + return FALSE; 1.887 + } 1.888 + 1.889 + if (finalZone != NULL) { 1.890 + if (inclusive && base == firstFinalTZTransition->getTime()) { 1.891 + result = *firstFinalTZTransition; 1.892 + return TRUE; 1.893 + } else if (base >= firstFinalTZTransition->getTime()) { 1.894 + if (finalZone->useDaylightTime()) { 1.895 + //return finalZone->getNextTransition(base, inclusive, result); 1.896 + return finalZoneWithStartYear->getNextTransition(base, inclusive, result); 1.897 + } else { 1.898 + // No more transitions 1.899 + return FALSE; 1.900 + } 1.901 + } 1.902 + } 1.903 + if (historicRules != NULL) { 1.904 + // Find a historical transition 1.905 + int16_t transCount = transitionCount(); 1.906 + int16_t ttidx = transCount - 1; 1.907 + for (; ttidx >= firstTZTransitionIdx; ttidx--) { 1.908 + UDate t = (UDate)transitionTime(ttidx); 1.909 + if (base > t || (!inclusive && base == t)) { 1.910 + break; 1.911 + } 1.912 + } 1.913 + if (ttidx == transCount - 1) { 1.914 + if (firstFinalTZTransition != NULL) { 1.915 + result = *firstFinalTZTransition; 1.916 + return TRUE; 1.917 + } else { 1.918 + return FALSE; 1.919 + } 1.920 + } else if (ttidx < firstTZTransitionIdx) { 1.921 + result = *firstTZTransition; 1.922 + return TRUE; 1.923 + } else { 1.924 + // Create a TimeZoneTransition 1.925 + TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]]; 1.926 + TimeZoneRule *from = historicRules[typeMapData[ttidx]]; 1.927 + UDate startTime = (UDate)transitionTime(ttidx+1); 1.928 + 1.929 + // The transitions loaded from zoneinfo.res may contain non-transition data 1.930 + UnicodeString fromName, toName; 1.931 + from->getName(fromName); 1.932 + to->getName(toName); 1.933 + if (fromName == toName && from->getRawOffset() == to->getRawOffset() 1.934 + && from->getDSTSavings() == to->getDSTSavings()) { 1.935 + return getNextTransition(startTime, false, result); 1.936 + } 1.937 + result.setTime(startTime); 1.938 + result.adoptFrom(from->clone()); 1.939 + result.adoptTo(to->clone()); 1.940 + return TRUE; 1.941 + } 1.942 + } 1.943 + return FALSE; 1.944 +} 1.945 + 1.946 +UBool 1.947 +OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const { 1.948 + UErrorCode status = U_ZERO_ERROR; 1.949 + checkTransitionRules(status); 1.950 + if (U_FAILURE(status)) { 1.951 + return FALSE; 1.952 + } 1.953 + 1.954 + if (finalZone != NULL) { 1.955 + if (inclusive && base == firstFinalTZTransition->getTime()) { 1.956 + result = *firstFinalTZTransition; 1.957 + return TRUE; 1.958 + } else if (base > firstFinalTZTransition->getTime()) { 1.959 + if (finalZone->useDaylightTime()) { 1.960 + //return finalZone->getPreviousTransition(base, inclusive, result); 1.961 + return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result); 1.962 + } else { 1.963 + result = *firstFinalTZTransition; 1.964 + return TRUE; 1.965 + } 1.966 + } 1.967 + } 1.968 + 1.969 + if (historicRules != NULL) { 1.970 + // Find a historical transition 1.971 + int16_t ttidx = transitionCount() - 1; 1.972 + for (; ttidx >= firstTZTransitionIdx; ttidx--) { 1.973 + UDate t = (UDate)transitionTime(ttidx); 1.974 + if (base > t || (inclusive && base == t)) { 1.975 + break; 1.976 + } 1.977 + } 1.978 + if (ttidx < firstTZTransitionIdx) { 1.979 + // No more transitions 1.980 + return FALSE; 1.981 + } else if (ttidx == firstTZTransitionIdx) { 1.982 + result = *firstTZTransition; 1.983 + return TRUE; 1.984 + } else { 1.985 + // Create a TimeZoneTransition 1.986 + TimeZoneRule *to = historicRules[typeMapData[ttidx]]; 1.987 + TimeZoneRule *from = historicRules[typeMapData[ttidx-1]]; 1.988 + UDate startTime = (UDate)transitionTime(ttidx); 1.989 + 1.990 + // The transitions loaded from zoneinfo.res may contain non-transition data 1.991 + UnicodeString fromName, toName; 1.992 + from->getName(fromName); 1.993 + to->getName(toName); 1.994 + if (fromName == toName && from->getRawOffset() == to->getRawOffset() 1.995 + && from->getDSTSavings() == to->getDSTSavings()) { 1.996 + return getPreviousTransition(startTime, false, result); 1.997 + } 1.998 + result.setTime(startTime); 1.999 + result.adoptFrom(from->clone()); 1.1000 + result.adoptTo(to->clone()); 1.1001 + return TRUE; 1.1002 + } 1.1003 + } 1.1004 + return FALSE; 1.1005 +} 1.1006 + 1.1007 +int32_t 1.1008 +OlsonTimeZone::countTransitionRules(UErrorCode& status) const { 1.1009 + if (U_FAILURE(status)) { 1.1010 + return 0; 1.1011 + } 1.1012 + checkTransitionRules(status); 1.1013 + if (U_FAILURE(status)) { 1.1014 + return 0; 1.1015 + } 1.1016 + 1.1017 + int32_t count = 0; 1.1018 + if (historicRules != NULL) { 1.1019 + // historicRules may contain null entries when original zoneinfo data 1.1020 + // includes non transition data. 1.1021 + for (int32_t i = 0; i < historicRuleCount; i++) { 1.1022 + if (historicRules[i] != NULL) { 1.1023 + count++; 1.1024 + } 1.1025 + } 1.1026 + } 1.1027 + if (finalZone != NULL) { 1.1028 + if (finalZone->useDaylightTime()) { 1.1029 + count += 2; 1.1030 + } else { 1.1031 + count++; 1.1032 + } 1.1033 + } 1.1034 + return count; 1.1035 +} 1.1036 + 1.1037 +void 1.1038 +OlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial, 1.1039 + const TimeZoneRule* trsrules[], 1.1040 + int32_t& trscount, 1.1041 + UErrorCode& status) const { 1.1042 + if (U_FAILURE(status)) { 1.1043 + return; 1.1044 + } 1.1045 + checkTransitionRules(status); 1.1046 + if (U_FAILURE(status)) { 1.1047 + return; 1.1048 + } 1.1049 + 1.1050 + // Initial rule 1.1051 + initial = initialRule; 1.1052 + 1.1053 + // Transition rules 1.1054 + int32_t cnt = 0; 1.1055 + if (historicRules != NULL && trscount > cnt) { 1.1056 + // historicRules may contain null entries when original zoneinfo data 1.1057 + // includes non transition data. 1.1058 + for (int32_t i = 0; i < historicRuleCount; i++) { 1.1059 + if (historicRules[i] != NULL) { 1.1060 + trsrules[cnt++] = historicRules[i]; 1.1061 + if (cnt >= trscount) { 1.1062 + break; 1.1063 + } 1.1064 + } 1.1065 + } 1.1066 + } 1.1067 + if (finalZoneWithStartYear != NULL && trscount > cnt) { 1.1068 + const InitialTimeZoneRule *tmpini; 1.1069 + int32_t tmpcnt = trscount - cnt; 1.1070 + finalZoneWithStartYear->getTimeZoneRules(tmpini, &trsrules[cnt], tmpcnt, status); 1.1071 + if (U_FAILURE(status)) { 1.1072 + return; 1.1073 + } 1.1074 + cnt += tmpcnt; 1.1075 + } 1.1076 + // Set the result length 1.1077 + trscount = cnt; 1.1078 +} 1.1079 + 1.1080 +U_NAMESPACE_END 1.1081 + 1.1082 +#endif // !UCONFIG_NO_FORMATTING 1.1083 + 1.1084 +//eof