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