1b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru**********************************************************************
38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius* Copyright (c) 2003-2013, International Business Machines
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Corporation and others.  All Rights Reserved.
5b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru**********************************************************************
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Author: Alan Liu
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Created: July 21 2003
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Since: ICU 2.8
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru**********************************************************************
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "utypeinfo.h"  // for 'typeid' to work
1327f654740f2a26ad62a5c155af9199af9e69b889claireho
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "olsontz.h"
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/ures.h"
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/simpletz.h"
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/gregocal.h"
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "gregoimp.h"
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cmemory.h"
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uassert.h"
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uvector.h"
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <float.h> // DBL_MAX
2650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "uresimp.h" // struct UResourceBundle
27b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "zonemeta.h"
288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius#include "umutex.h"
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#ifdef U_DEBUG_TZ
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru# include <stdio.h>
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru# include "uresimp.h" // for debugging
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void debug_tz_loc(const char *f, int32_t l)
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  fprintf(stderr, "%s:%d: ", f, l);
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void debug_tz_msg(const char *pat, ...)
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  va_list ap;
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  va_start(ap, pat);
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  vfprintf(stderr, pat, ap);
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  fflush(stderr);
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru// must use double parens, i.e.:  U_DEBUG_TZ_MSG(("four is: %d",4));
47b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;}
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#else
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define U_DEBUG_TZ_MSG(x)
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
51b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
5250294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehostatic UBool arrayEqual(const void *a1, const void *a2, int32_t size) {
5350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (a1 == NULL && a2 == NULL) {
5450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return TRUE;
5550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
5627f654740f2a26ad62a5c155af9199af9e69b889claireho    if ((a1 != NULL && a2 == NULL) || (a1 == NULL && a2 != NULL)) {
5750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return FALSE;
5850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
5950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (a1 == a2) {
6050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return TRUE;
6150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
6250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
6350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return (uprv_memcmp(a1, a2, size) == 0);
6450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
6550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_BEGIN
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
6850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kTRANS          "trans"
6950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kTRANSPRE32     "transPre32"
7050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kTRANSPOST32    "transPost32"
7150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kTYPEOFFSETS    "typeOffsets"
7250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kTYPEMAP        "typeMap"
7350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kLINKS          "links"
7450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kFINALRULE      "finalRule"
7550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kFINALRAW       "finalRaw"
7650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define kFINALYEAR      "finalYear"
7750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define SECONDS_PER_DAY (24*60*60)
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const int32_t ZEROS[] = {0,0};
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Default constructor.  Creates a time zone with an empty ID and
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * a fixed GMT offset of zero.
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*OlsonTimeZone::OlsonTimeZone() : finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(FALSE) {
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    clearTransitionRules();
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    constructEmpty();
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}*/
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Construct a GMT+0 zone with no transitions.  This is done when a
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * constructor fails so the resultant object is well-behaved.
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid OlsonTimeZone::constructEmpty() {
98b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    canonicalID = NULL;
99b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
10050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
10150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
10250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
10350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    typeMapData = NULL;
10450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    typeCount = 1;
10650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    typeOffsets = ZEROS;
10750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
10850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    finalZone = NULL;
109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Construct from a resource bundle
113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param top the top-level zoneinfo resource bundle.  This is used
114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to lookup the rule that `res' may refer to, if there is one.
115b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param res the resource bundle of the zone to be constructed
116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param ec input-output error code
117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             const UResourceBundle* res,
120b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                             const UnicodeString& tzid,
121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                             UErrorCode& ec) :
12259d709d503bab6e2b61931737e662dd293b40578ccornelius  BasicTimeZone(tzid), finalZone(NULL)
123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
124b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    clearTransitionRules();
125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if ((top == NULL || res == NULL) && U_SUCCESS(ec)) {
127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ec = U_ILLEGAL_ARGUMENT_ERROR;
128b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_SUCCESS(ec)) {
130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // TODO -- clean up -- Doesn't work if res points to an alias
131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        //        // TODO remove nonconst casts below when ures_* API is fixed
132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        //        setID(ures_getKey((UResourceBundle*) res)); // cast away const
133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
13450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int32_t len;
13550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        UResourceBundle r;
13650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_initStackObject(&r);
13750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
13850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // Pre-32bit second transitions
13950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(res, kTRANSPRE32, &r, &ec);
14050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
14150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        transitionCountPre32 = len >> 1;
14250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (ec == U_MISSING_RESOURCE_ERROR) {
14350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // No pre-32bit transitions
14450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            transitionTimesPre32 = NULL;
14550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            transitionCountPre32 = 0;
14650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ec = U_ZERO_ERROR;
14750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ec = U_INVALID_FORMAT_ERROR;
149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
150b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
15150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // 32bit second transitions
15250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(res, kTRANS, &r, &ec);
15350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        transitionTimes32 = ures_getIntVector(&r, &len, &ec);
15450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        transitionCount32 = len;
15550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (ec == U_MISSING_RESOURCE_ERROR) {
15650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // No 32bit transitions
15750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            transitionTimes32 = NULL;
15850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            transitionCount32 = 0;
15950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ec = U_ZERO_ERROR;
16050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) {
161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ec = U_INVALID_FORMAT_ERROR;
162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
16350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
16450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // Post-32bit second transitions
16550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(res, kTRANSPOST32, &r, &ec);
16650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
16750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        transitionCountPost32 = len >> 1;
16850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (ec == U_MISSING_RESOURCE_ERROR) {
16950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // No pre-32bit transitions
17050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            transitionTimesPost32 = NULL;
17150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            transitionCountPost32 = 0;
17250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ec = U_ZERO_ERROR;
17350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ec = U_INVALID_FORMAT_ERROR;
175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
17750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // Type offsets list must be of even size, with size >= 2
17850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(res, kTYPEOFFSETS, &r, &ec);
17950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeOffsets = ures_getIntVector(&r, &len, &ec);
18050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ec = U_INVALID_FORMAT_ERROR;
182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
18350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeCount = (int16_t) len >> 1;
18450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
18550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // Type map data must be of the same size as the transition count
18650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeMapData =  NULL;
18750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (transitionCount() > 0) {
18850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ures_getByKey(res, kTYPEMAP, &r, &ec);
18950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            typeMapData = ures_getBinary(&r, &len, &ec);
19050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (ec == U_MISSING_RESOURCE_ERROR) {
19150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                // no type mapping data
19250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                ec = U_INVALID_FORMAT_ERROR;
19350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else if (U_SUCCESS(ec) && len != transitionCount()) {
19450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                ec = U_INVALID_FORMAT_ERROR;
19550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Process final rule and data, if any
19950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
20050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(res, kFINALRAW, &r, &ec);
20150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int32_t ruleRaw = ures_getInt(&r, &ec);
20250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(res, kFINALYEAR, &r, &ec);
20350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int32_t ruleYear = ures_getInt(&r, &ec);
20450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(ec)) {
20550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UnicodeString ruleID(TRUE, ruleIdUStr, len);
20650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec);
20750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            const int32_t *ruleData = ures_getIntVector(rule, &len, &ec);
20850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (U_SUCCESS(ec) && len == 11) {
20950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                UnicodeString emptyStr;
21050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                finalZone = new SimpleTimeZone(
21150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ruleRaw * U_MILLIS_PER_SECOND,
21250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    emptyStr,
21350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    (int8_t)ruleData[0], (int8_t)ruleData[1], (int8_t)ruleData[2],
21450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ruleData[3] * U_MILLIS_PER_SECOND,
21550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    (SimpleTimeZone::TimeMode) ruleData[4],
21650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    (int8_t)ruleData[5], (int8_t)ruleData[6], (int8_t)ruleData[7],
21750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ruleData[8] * U_MILLIS_PER_SECOND,
21850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    (SimpleTimeZone::TimeMode) ruleData[9],
21950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ruleData[10] * U_MILLIS_PER_SECOND, ec);
22050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (finalZone == NULL) {
22150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ec = U_MEMORY_ALLOCATION_ERROR;
222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
22350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    finalStartYear = ruleYear;
22450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
22550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // Note: Setting finalStartYear to the finalZone is problematic.  When a date is around
22650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // year boundary, SimpleTimeZone may return false result when DST is observed at the
22750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // beginning of year.  We could apply safe margin (day or two), but when one of recurrent
22850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // rules falls around year boundary, it could return false result.  Without setting the
22950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // start year, finalZone works fine around the year boundary of the start year.
23050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
23150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // finalZone->setStartYear(finalStartYear);
23250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
23350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
23450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // Compute the millis for Jan 1, 0:00 GMT of the finalYear
23550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
23650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // Note: finalStartMillis is used for detecting either if
23750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // historic transition data or finalZone to be used.  In an
23850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // extreme edge case - for example, two transitions fall into
23950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // small windows of time around the year boundary, this may
24050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // result incorrect offset computation.  But I think it will
24150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    // never happen practically.  Yoshito - Feb 20, 2010
24250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY;
243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
24450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
24550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                ec = U_INVALID_FORMAT_ERROR;
246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
24750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ures_close(rule);
24850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else if (ec == U_MISSING_RESOURCE_ERROR) {
24950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // No final zone
25050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            ec = U_ZERO_ERROR;
251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
25250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_close(&r);
253b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
254b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        // initialize canonical ID
255b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        canonicalID = ZoneMeta::getCanonicalCLDRID(tzid, ec);
256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(ec)) {
259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        constructEmpty();
260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Copy constructor
265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    BasicTimeZone(other), finalZone(0) {
268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    *this = other;
269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Assignment operator
273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
275b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    canonicalID = other.canonicalID;
276b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
27750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionTimesPre32 = other.transitionTimesPre32;
27850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionTimes32 = other.transitionTimes32;
27950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionTimesPost32 = other.transitionTimesPost32;
28050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
28150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionCountPre32 = other.transitionCountPre32;
28250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionCount32 = other.transitionCount32;
28350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transitionCountPost32 = other.transitionCountPost32;
28450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    typeCount = other.typeCount;
286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    typeOffsets = other.typeOffsets;
28750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    typeMapData = other.typeMapData;
28850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete finalZone;
290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    finalZone = (other.finalZone != 0) ?
291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        (SimpleTimeZone*) other.finalZone->clone() : 0;
29250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
29350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    finalStartYear = other.finalStartYear;
29450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    finalStartMillis = other.finalStartMillis;
29550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    clearTransitionRules();
29750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return *this;
299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Destructor
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::~OlsonTimeZone() {
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    deleteTransitionRules();
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    delete finalZone;
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Returns true if the two TimeZone objects are equal.
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool OlsonTimeZone::operator==(const TimeZone& other) const {
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return ((this == &other) ||
31427f654740f2a26ad62a5c155af9199af9e69b889claireho            (typeid(*this) == typeid(other) &&
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TimeZone::operator==(other) &&
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            hasSameRules(other)));
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruTimeZone* OlsonTimeZone::clone() const {
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return new OlsonTimeZone(*this);
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 int32_t dom, uint8_t dow,
331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 int32_t millis, UErrorCode& ec) const {
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (month < UCAL_JANUARY || month > UCAL_DECEMBER) {
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_SUCCESS(ec)) {
334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ec = U_ILLEGAL_ARGUMENT_ERROR;
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return getOffset(era, year, month, dom, dow, millis,
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                         Grego::monthLength(year, month),
340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                         ec);
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 int32_t dom, uint8_t dow,
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 int32_t millis, int32_t monthLength,
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                 UErrorCode& ec) const {
351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(ec)) {
352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if ((era != GregorianCalendar::AD && era != GregorianCalendar::BC)
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || month < UCAL_JANUARY
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || month > UCAL_DECEMBER
358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || dom < 1
359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || dom > monthLength
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || dow < UCAL_SUNDAY
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || dow > UCAL_SATURDAY
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || millis < 0
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || millis >= U_MILLIS_PER_DAY
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || monthLength < 28
365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        || monthLength > 31) {
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ec = U_ILLEGAL_ARGUMENT_ERROR;
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (era == GregorianCalendar::BC) {
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        year = -year;
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
37450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (finalZone != NULL && year >= finalStartYear) {
375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return finalZone->getOffset(era, year, month, dom, dow,
376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                    millis, monthLength, ec);
377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Compute local epoch millis from input fields
380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UDate date = (UDate)(Grego::fieldsToDay(year, month, dom) * U_MILLIS_PER_DAY + millis);
381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t rawoff, dstoff;
382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getHistoricalOffset(date, TRUE, kDaylight, kStandard, rawoff, dstoff);
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return rawoff + dstoff;
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                              int32_t& dstoff, UErrorCode& ec) const {
391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(ec)) {
392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
39450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (finalZone != NULL && date >= finalStartMillis) {
395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        finalZone->getOffset(date, local, rawoff, dstoff, ec);
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff);
398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
4038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                                  int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const {
404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(ec)) {
405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
40750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (finalZone != NULL && date >= finalStartMillis) {
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec);
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        getHistoricalOffset(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff);
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid OlsonTimeZone::setRawOffset(int32_t /*offsetMillis*/) {
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // We don't support this operation, since OlsonTimeZones are
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // immutable (except for the ID, which is in the base class).
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Nothing to do!
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t OlsonTimeZone::getRawOffset() const {
429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode ec = U_ZERO_ERROR;
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw, dst;
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffset((double) uprv_getUTCtime() * U_MILLIS_PER_SECOND,
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              FALSE, raw, dst, ec);
433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return raw;
434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined U_DEBUG_TZ
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid printTime(double ms) {
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t year, month, dom, dow;
439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            double millis=0;
440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            double days = ClockMath::floorDivide(((double)ms), (double)U_MILLIS_PER_DAY, millis);
441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            Grego::dayToFields(days, year, month, dom, dow);
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            U_DEBUG_TZ_MSG(("   getHistoricalOffset:  time %.1f (%04d.%02d.%02d+%.1fh)\n", ms,
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            year, month+1, dom, (millis/kOneHour)));
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
44850294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoint64_t
44950294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoOlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const {
45050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    U_ASSERT(transIdx >= 0 && transIdx < transitionCount());
45150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
45250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (transIdx < transitionCountPre32) {
45350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return (((int64_t)((uint32_t)transitionTimesPre32[transIdx << 1])) << 32)
45450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            | ((int64_t)((uint32_t)transitionTimesPre32[(transIdx << 1) + 1]));
45550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
45650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
45750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transIdx -= transitionCountPre32;
45850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (transIdx < transitionCount32) {
45950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return (int64_t)transitionTimes32[transIdx];
46050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
46150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
46250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    transIdx -= transitionCount32;
46350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return (((int64_t)((uint32_t)transitionTimesPost32[transIdx << 1])) << 32)
46450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        | ((int64_t)((uint32_t)transitionTimesPost32[(transIdx << 1) + 1]));
46550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho}
46650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
46759d709d503bab6e2b61931737e662dd293b40578ccornelius// Maximum absolute offset in seconds (86400 seconds = 1 day)
46859d709d503bab6e2b61931737e662dd293b40578ccornelius// getHistoricalOffset uses this constant as safety margin of
46959d709d503bab6e2b61931737e662dd293b40578ccornelius// quick zone transition checking.
47059d709d503bab6e2b61931737e662dd293b40578ccornelius#define MAX_OFFSET_SECONDS 86400
47159d709d503bab6e2b61931737e662dd293b40578ccornelius
472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                   int32_t& rawoff, int32_t& dstoff) const {
476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst)\n",
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt));
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined U_DEBUG_TZ
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        printTime(date*1000.0);
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
48150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int16_t transCount = transitionCount();
48250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
48350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (transCount > 0) {
484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
48550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (!local && sec < transitionTimeInSeconds(0)) {
48650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // Before the first transition time
48750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
48850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
48950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        } else {
49050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // Linear search from the end is the fastest approach, since
49150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // most lookups will happen at/near the end.
49250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            int16_t transIdx;
49350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
49450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                int64_t transition = transitionTimeInSeconds(transIdx);
49550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
49659d709d503bab6e2b61931737e662dd293b40578ccornelius                if (local && (sec >= (transition - MAX_OFFSET_SECONDS))) {
49750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    int32_t offsetBefore = zoneOffsetAt(transIdx - 1);
49850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    UBool dstBefore = dstOffsetAt(transIdx - 1) != 0;
49950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
50050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    int32_t offsetAfter = zoneOffsetAt(transIdx);
50150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    UBool dstAfter = dstOffsetAt(transIdx) != 0;
50250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
50350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    UBool dstToStd = dstBefore && !dstAfter;
50450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    UBool stdToDst = !dstBefore && dstAfter;
50550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
50650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (offsetAfter - offsetBefore >= 0) {
50750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // Positive transition, which makes a non-existing local time range
50850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
50950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
51050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetBefore;
51150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        } else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
51250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                || ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
51350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetAfter;
51450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        } else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
51550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetBefore;
51650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        } else {
51750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            // Interprets the time with rule before the transition,
51850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            // default for non-existing time range
51950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetAfter;
52050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        }
521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    } else {
52250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        // Negative transition, which makes a duplicated local time range
52350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
52450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
52550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetAfter;
52650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        } else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
52750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                                || ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
52850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetBefore;
52950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        } else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
53050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetBefore;
53150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        } else {
53250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            // Interprets the time with rule after the transition,
53350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            // default for duplicated local time range
53450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                            transition += offsetAfter;
53550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        }
536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
53850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (sec >= transition) {
53950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    break;
54050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
54250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // transIdx could be -1 when local=true
54350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
54450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // No transitions, single pair of offsets only
54850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
54950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n",
552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff));
553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool OlsonTimeZone::useDaylightTime() const {
559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // If DST was observed in 1942 (for example) but has never been
560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // observed from 1943 to the present, most clients will expect
561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // this method to return FALSE.  This method determines whether
562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // DST is in use in the current year (at any point in the year)
563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // and returns TRUE if so.
564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
56550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UDate current = uprv_getUTCtime();
56650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (finalZone != NULL && current >= finalStartMillis) {
56750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return finalZone->useDaylightTime();
568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
569b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
57050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t year, month, dom, dow, doy, mid;
57150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    Grego::timeToFields(current, year, month, dom, dow, doy, mid);
57250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Find start of this year, and start of next year
57450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
57550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Return TRUE if DST is observed at any time during the current
578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // year.
57950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    for (int16_t i = 0; i < transitionCount(); ++i) {
5808393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius        double transition = (double)transitionTimeInSeconds(i);
58150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (transition >= limit) {
582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
58450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if ((transition >= start && dstOffsetAt(i) != 0)
58550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                || (transition > start && dstOffsetAt(i - 1) != 0)) {
586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::getDSTSavings() const{
59350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (finalZone != NULL){
594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return finalZone->getDSTSavings();
595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return TimeZone::getDSTSavings();
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TimeZone API.
600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool OlsonTimeZone::inDaylightTime(UDate date, UErrorCode& ec) const {
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw, dst;
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getOffset(date, FALSE, raw, dst, ec);
604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return dst != 0;
605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
608b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::hasSameRules(const TimeZone &other) const {
609b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (this == &other) {
610b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
611b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
61227f654740f2a26ad62a5c155af9199af9e69b889claireho    const OlsonTimeZone* z = dynamic_cast<const OlsonTimeZone*>(&other);
61327f654740f2a26ad62a5c155af9199af9e69b889claireho    if (z == NULL) {
614b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
61750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // [sic] pointer comparison: typeMapData points into
618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // memory-mapped or DLL space, so if two zones have the same
619b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // pointer, they are equal.
62050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (typeMapData == z->typeMapData) {
621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return TRUE;
622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
62450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // If the pointers are not equal, the zones may still
62550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // be equal if their rules and transitions are equal
62627f654740f2a26ad62a5c155af9199af9e69b889claireho    if ((finalZone == NULL && z->finalZone != NULL)
62727f654740f2a26ad62a5c155af9199af9e69b889claireho        || (finalZone != NULL && z->finalZone == NULL)
62827f654740f2a26ad62a5c155af9199af9e69b889claireho        || (finalZone != NULL && z->finalZone != NULL && *finalZone != *z->finalZone)) {
62950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return FALSE;
63050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
63150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
63250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (finalZone != NULL) {
63350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) {
63450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            return FALSE;
63550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
63650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
63750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (typeCount != z->typeCount
63850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        || transitionCountPre32 != z->transitionCountPre32
63950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        || transitionCount32 != z->transitionCount32
64050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        || transitionCountPost32 != z->transitionCountPost32) {
64150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return FALSE;
64250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
64350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return
64550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1)
64650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        && arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32)
64750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        && arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1)
64850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        && arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1)
64950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        && arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount());
650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::clearTransitionRules(void) {
654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initialRule = NULL;
655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    firstTZTransition = NULL;
656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    firstFinalTZTransition = NULL;
657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    historicRules = NULL;
658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    historicRuleCount = 0;
659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    finalZoneWithStartYear = NULL;
660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    firstTZTransitionIdx = 0;
66159d709d503bab6e2b61931737e662dd293b40578ccornelius    transitionRulesInitOnce.reset();
662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::deleteTransitionRules(void) {
666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (initialRule != NULL) {
667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete initialRule;
668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (firstTZTransition != NULL) {
670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete firstTZTransition;
671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (firstFinalTZTransition != NULL) {
673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete firstFinalTZTransition;
674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (finalZoneWithStartYear != NULL) {
676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        delete finalZoneWithStartYear;
677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (historicRules != NULL) {
679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (int i = 0; i < historicRuleCount; i++) {
680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (historicRules[i] != NULL) {
681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                delete historicRules[i];
682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(historicRules);
685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    clearTransitionRules();
687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
6898393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*
6908393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius * Lazy transition rules initializer
6918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius */
6928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
69359d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) {
69459d709d503bab6e2b61931737e662dd293b40578ccornelius    This->initTransitionRules(status);
69559d709d503bab6e2b61931737e662dd293b40578ccornelius}
69659d709d503bab6e2b61931737e662dd293b40578ccornelius
6978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusvoid
6988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusOlsonTimeZone::checkTransitionRules(UErrorCode& status) const {
69959d709d503bab6e2b61931737e662dd293b40578ccornelius    OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(this);
70059d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status);
7018393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius}
7028393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::initTransitionRules(UErrorCode& status) {
705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(U_FAILURE(status)) {
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    deleteTransitionRules();
709b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString tzid;
710b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    getID(tzid);
711b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
712b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString stdName = tzid + UNICODE_STRING_SIMPLE("(STD)");
713b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)");
714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t raw, dst;
716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
71750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // Create initial rule
71850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    raw = initialRawOffset() * U_MILLIS_PER_SECOND;
71950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    dst = initialDstOffset() * U_MILLIS_PER_SECOND;
72050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
72150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    // Check to make sure initialRule was created
72250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (initialRule == NULL) {
72350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        status = U_MEMORY_ALLOCATION_ERROR;
72450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        deleteTransitionRules();
72550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        return;
72650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    }
727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
72850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t transCount = transitionCount();
72950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (transCount > 0) {
73050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int16_t transitionIdx, typeIdx;
731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
73250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // We probably no longer need to check the first "real" transition
73350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // here, because the new tzcode remove such transitions already.
73450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        // For now, keeping this code for just in case. Feb 19, 2010 Yoshito
735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        firstTZTransitionIdx = 0;
73650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) {
73750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type
738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
74050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            firstTZTransitionIdx++;
741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
74250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (transitionIdx == transCount) {
743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Actually no transitions...
744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Build historic rule array
74650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transCount); /* large enough to store all transition times */
747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (times == NULL) {
748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                deleteTransitionRules();
750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return;
751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            for (typeIdx = 0; typeIdx < typeCount; typeIdx++) {
753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // Gather all start times for each pair of offsets
754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                int32_t nTimes = 0;
75550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) {
75650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (typeIdx == (int16_t)typeMapData[transitionIdx]) {
75750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        UDate tt = (UDate)transitionTime(transitionIdx);
75850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        if (finalZone == NULL || tt <= finalStartMillis) {
759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            // Exclude transitions after finalMillis
760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            times[nTimes++] = tt;
761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (nTimes > 0) {
765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    // Create a TimeArrayTimeZoneRule
76650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND;
76750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND;
768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if (historicRules == NULL) {
769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        historicRuleCount = typeCount;
770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        historicRules = (TimeArrayTimeZoneRule**)uprv_malloc(sizeof(TimeArrayTimeZoneRule*)*historicRuleCount);
771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if (historicRules == NULL) {
772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            status = U_MEMORY_ALLOCATION_ERROR;
773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            deleteTransitionRules();
774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            uprv_free(times);
775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            return;
776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        for (int i = 0; i < historicRuleCount; i++) {
778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            // Initialize TimeArrayTimeZoneRule pointers as NULL
779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            historicRules[i] = NULL;
780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    historicRules[typeIdx] = new TimeArrayTimeZoneRule((dst == 0 ? stdName : dstName),
783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        raw, dst, times, nTimes, DateTimeRule::UTC_TIME);
784c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    // Check for memory allocation error
785c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    if (historicRules[typeIdx] == NULL) {
786c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        status = U_MEMORY_ALLOCATION_ERROR;
787c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        deleteTransitionRules();
788c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        return;
789c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    }
790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            uprv_free(times);
793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Create initial transition
79550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            typeIdx = (int16_t)typeMapData[firstTZTransitionIdx];
79650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            firstTZTransition = new TimeZoneTransition((UDate)transitionTime(firstTZTransitionIdx),
797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    *initialRule, *historicRules[typeIdx]);
798c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            // Check to make sure firstTZTransition was created.
799c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if (firstTZTransition == NULL) {
800c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
801c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                deleteTransitionRules();
802c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                return;
803c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (finalZone != NULL) {
807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Get the first occurence of final rule starts
80850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        UDate startTime = (UDate)finalStartMillis;
809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        TimeZoneRule *firstFinalRule = NULL;
81050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (finalZone->useDaylightTime()) {
812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /*
813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             * Note: When an OlsonTimeZone is constructed, we should set the final year
814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             * as the start year of finalZone.  However, the bounday condition used for
81550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho             * getting offset from finalZone has some problems.
81650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho             * For now, we do not set the valid start year when the construction time
81750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho             * and create a clone and set the start year when extracting rules.
818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             */
819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
820c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            // Check to make sure finalZone was actually cloned.
821c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if (finalZoneWithStartYear == NULL) {
822c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
823c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                deleteTransitionRules();
824c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                return;
825c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
82650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            finalZoneWithStartYear->setStartYear(finalStartYear);
827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            TimeZoneTransition tzt;
829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            firstFinalRule  = tzt.getTo()->clone();
831c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            // Check to make sure firstFinalRule received proper clone.
832c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if (firstFinalRule == NULL) {
833c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
834c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                deleteTransitionRules();
835c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                return;
836c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            startTime = tzt.getTime();
838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
83950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // final rule with no transitions
840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
84150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            // Check to make sure finalZone was actually cloned.
842c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if (finalZoneWithStartYear == NULL) {
843c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
844c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                deleteTransitionRules();
845c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                return;
846c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            finalZone->getID(tzid);
848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            firstFinalRule = new TimeArrayTimeZoneRule(tzid,
849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                finalZone->getRawOffset(), 0, &startTime, 1, DateTimeRule::UTC_TIME);
850c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            // Check firstFinalRule was properly created.
851c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            if (firstFinalRule == NULL) {
852c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                status = U_MEMORY_ALLOCATION_ERROR;
853c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                deleteTransitionRules();
854c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                return;
855c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
856b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        TimeZoneRule *prevRule = NULL;
85850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (transCount > 0) {
85950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            prevRule = historicRules[typeMapData[transCount - 1]];
860b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
861b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (prevRule == NULL) {
862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // No historic transitions, but only finalZone available
863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            prevRule = initialRule;
864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        firstFinalTZTransition = new TimeZoneTransition();
866c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        // Check to make sure firstFinalTZTransition was created before dereferencing
867c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        if (firstFinalTZTransition == NULL) {
868c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            status = U_MEMORY_ALLOCATION_ERROR;
869c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            deleteTransitionRules();
870c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            return;
871c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        }
872b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        firstFinalTZTransition->setTime(startTime);
873b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        firstFinalTZTransition->adoptFrom(prevRule->clone());
874b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        firstFinalTZTransition->adoptTo(firstFinalRule);
875b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
876b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
877b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
8798393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusOlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
8818393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    checkTransitionRules(status);
882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
883b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
884b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
885b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
886b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (finalZone != NULL) {
887b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (inclusive && base == firstFinalTZTransition->getTime()) {
888b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *firstFinalTZTransition;
889b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
890b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (base >= firstFinalTZTransition->getTime()) {
891b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (finalZone->useDaylightTime()) {
892b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                //return finalZone->getNextTransition(base, inclusive, result);
893b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return finalZoneWithStartYear->getNextTransition(base, inclusive, result);
894b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                // No more transitions
896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return FALSE;
897b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
898b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
899b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
900b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (historicRules != NULL) {
901b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Find a historical transition
90250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int16_t transCount = transitionCount();
90350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int16_t ttidx = transCount - 1;
904b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (; ttidx >= firstTZTransitionIdx; ttidx--) {
90550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UDate t = (UDate)transitionTime(ttidx);
906b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (base > t || (!inclusive && base == t)) {
907b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
908b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
909b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
91050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (ttidx == transCount - 1)  {
911b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (firstFinalTZTransition != NULL) {
912b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                result = *firstFinalTZTransition;
913b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return TRUE;
914b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
915b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return FALSE;
916b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
917b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (ttidx < firstTZTransitionIdx) {
918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *firstTZTransition;
919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
920b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Create a TimeZoneTransition
92250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]];
92350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            TimeZoneRule *from = historicRules[typeMapData[ttidx]];
92450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UDate startTime = (UDate)transitionTime(ttidx+1);
925b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // The transitions loaded from zoneinfo.res may contain non-transition data
927b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UnicodeString fromName, toName;
928b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            from->getName(fromName);
929b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            to->getName(toName);
930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (fromName == toName && from->getRawOffset() == to->getRawOffset()
931b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    && from->getDSTSavings() == to->getDSTSavings()) {
932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return getNextTransition(startTime, false, result);
933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.setTime(startTime);
935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.adoptFrom(from->clone());
936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.adoptTo(to->clone());
937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
943b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruUBool
9448393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusOlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
9468393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    checkTransitionRules(status);
947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return FALSE;
949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (finalZone != NULL) {
952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (inclusive && base == firstFinalTZTransition->getTime()) {
953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *firstFinalTZTransition;
954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (base > firstFinalTZTransition->getTime()) {
956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (finalZone->useDaylightTime()) {
957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                //return finalZone->getPreviousTransition(base, inclusive, result);
958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return finalZoneWithStartYear->getPreviousTransition(base, inclusive, result);
959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                result = *firstFinalTZTransition;
961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return TRUE;
96250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (historicRules != NULL) {
967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // Find a historical transition
96850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        int16_t ttidx = transitionCount() - 1;
969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (; ttidx >= firstTZTransitionIdx; ttidx--) {
97050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UDate t = (UDate)transitionTime(ttidx);
971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (base > t || (inclusive && base == t)) {
972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
975b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (ttidx < firstTZTransitionIdx) {
976b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // No more transitions
977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return FALSE;
978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (ttidx == firstTZTransitionIdx) {
979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result = *firstTZTransition;
980b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
981b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
982b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // Create a TimeZoneTransition
98350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            TimeZoneRule *to = historicRules[typeMapData[ttidx]];
98450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            TimeZoneRule *from = historicRules[typeMapData[ttidx-1]];
98550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            UDate startTime = (UDate)transitionTime(ttidx);
986b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
987b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            // The transitions loaded from zoneinfo.res may contain non-transition data
988b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UnicodeString fromName, toName;
989b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            from->getName(fromName);
990b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            to->getName(toName);
991b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (fromName == toName && from->getRawOffset() == to->getRawOffset()
992b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    && from->getDSTSavings() == to->getDSTSavings()) {
993b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return getPreviousTransition(startTime, false, result);
994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
995b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.setTime(startTime);
996b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.adoptFrom(from->clone());
997b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            result.adoptTo(to->clone());
998b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return TRUE;
999b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1000b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1001b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return FALSE;
1002b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1003b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruint32_t
10058393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusOlsonTimeZone::countTransitionRules(UErrorCode& status) const {
1006b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
1007b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1008b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
10098393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    checkTransitionRules(status);
1010b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
1011b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1012b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1013b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1014b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t count = 0;
1015b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (historicRules != NULL) {
1016b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // historicRules may contain null entries when original zoneinfo data
1017b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // includes non transition data.
1018b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (int32_t i = 0; i < historicRuleCount; i++) {
1019b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (historicRules[i] != NULL) {
1020b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                count++;
1021b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1022b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1023b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1024b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (finalZone != NULL) {
1025b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (finalZone->useDaylightTime()) {
1026b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            count += 2;
1027b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
1028b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            count++;
1029b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return count;
1032b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1033b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruvoid
1035b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruOlsonTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
1036b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                const TimeZoneRule* trsrules[],
1037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                int32_t& trscount,
10388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                                UErrorCode& status) const {
1039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
1040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
1041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
10428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    checkTransitionRules(status);
1043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
1044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
1045b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1046b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1047b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Initial rule
1048b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    initial = initialRule;
1049b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1050b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Transition rules
1051b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t cnt = 0;
1052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (historicRules != NULL && trscount > cnt) {
1053b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // historicRules may contain null entries when original zoneinfo data
1054b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        // includes non transition data.
1055b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (int32_t i = 0; i < historicRuleCount; i++) {
1056b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (historicRules[i] != NULL) {
1057b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                trsrules[cnt++] = historicRules[i];
1058b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (cnt >= trscount) {
1059b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
1060b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1061b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1062b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1063b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (finalZoneWithStartYear != NULL && trscount > cnt) {
1065b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const InitialTimeZoneRule *tmpini;
1066b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t tmpcnt = trscount - cnt;
1067b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        finalZoneWithStartYear->getTimeZoneRules(tmpini, &trsrules[cnt], tmpcnt, status);
1068b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (U_FAILURE(status)) {
1069b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return;
1070b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1071b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        cnt += tmpcnt;
1072b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1073b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    // Set the result length
1074b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    trscount = cnt;
1075b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1076b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1077b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_NAMESPACE_END
1078b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1079b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif // !UCONFIG_NO_FORMATTING
1080b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1081b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru//eof
1082