• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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