1 /*
2 **********************************************************************
3 * Copyright (c) 2003-2012, 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 "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 #include "zonemeta.h"
28
29 #ifdef U_DEBUG_TZ
30 # include <stdio.h>
31 # include "uresimp.h" // for debugging
32
debug_tz_loc(const char * f,int32_t l)33 static void debug_tz_loc(const char *f, int32_t l)
34 {
35 fprintf(stderr, "%s:%d: ", f, l);
36 }
37
debug_tz_msg(const char * pat,...)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
arrayEqual(const void * a1,const void * a2,int32_t size)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
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)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 */
OlsonTimeZone(const UResourceBundle * top,const UResourceBundle * res,const UnicodeString & tzid,UErrorCode & ec)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 */
OlsonTimeZone(const OlsonTimeZone & other)265 OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
266 BasicTimeZone(other), finalZone(0) {
267 *this = other;
268 }
269
270 /**
271 * Assignment operator
272 */
operator =(const OlsonTimeZone & other)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 */
~OlsonTimeZone()303 OlsonTimeZone::~OlsonTimeZone() {
304 deleteTransitionRules();
305 delete finalZone;
306 }
307
308 /**
309 * Returns true if the two TimeZone objects are equal.
310 */
operator ==(const TimeZone & other) const311 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 */
clone() const321 TimeZone* OlsonTimeZone::clone() const {
322 return new OlsonTimeZone(*this);
323 }
324
325 /**
326 * TimeZone API.
327 */
getOffset(uint8_t era,int32_t year,int32_t month,int32_t dom,uint8_t dow,int32_t millis,UErrorCode & ec) const328 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 */
getOffset(uint8_t era,int32_t year,int32_t month,int32_t dom,uint8_t dow,int32_t millis,int32_t monthLength,UErrorCode & ec) const346 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 */
getOffset(UDate date,UBool local,int32_t & rawoff,int32_t & dstoff,UErrorCode & ec) const388 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
getOffsetFromLocal(UDate date,int32_t nonExistingTimeOpt,int32_t duplicatedTimeOpt,int32_t & rawoff,int32_t & dstoff,UErrorCode & ec)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 */
setRawOffset(int32_t)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 */
getRawOffset() const427 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
printTime(double ms)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
transitionTimeInSeconds(int16_t transIdx) const448 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
getHistoricalOffset(UDate date,UBool local,int32_t NonExistingTimeOpt,int32_t DuplicatedTimeOpt,int32_t & rawoff,int32_t & dstoff) const467 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 */
useDaylightTime() const552 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 = transitionTimeInSeconds(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
getDSTSavings() const586 OlsonTimeZone::getDSTSavings() const{
587 if (finalZone != NULL){
588 return finalZone->getDSTSavings();
589 }
590 return TimeZone::getDSTSavings();
591 }
592 /**
593 * TimeZone API.
594 */
inDaylightTime(UDate date,UErrorCode & ec) const595 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
hasSameRules(const TimeZone & other) const602 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
clearTransitionRules(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
deleteTransitionRules(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
initTransitionRules(UErrorCode & status)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
getNextTransition(UDate base,UBool inclusive,TimeZoneTransition & result)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
getPreviousTransition(UDate base,UBool inclusive,TimeZoneTransition & result)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
countTransitionRules(UErrorCode & status)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
getTimeZoneRules(const InitialTimeZoneRule * & initial,const TimeZoneRule * trsrules[],int32_t & trscount,UErrorCode & status)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