1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*******************************************************************************
38393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius* Copyright (C) 2007-2013, International Business Machines Corporation and
427f654740f2a26ad62a5c155af9199af9e69b889claireho* others. All Rights Reserved.
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*******************************************************************************
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*/
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "utypeinfo.h"  // for 'typeid' to work
927f654740f2a26ad62a5c155af9199af9e69b889claireho
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/utypes.h"
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
12ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#if !UCONFIG_NO_FORMATTING
13ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
14ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/vtzone.h"
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/rbtz.h"
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/ucal.h"
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/ures.h"
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "cmemory.h"
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "uvector.h"
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "gregoimp.h"
2159d709d503bab6e2b61931737e662dd293b40578ccornelius#include "uassert.h"
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho// This is the deleter that will be use to remove TimeZoneRule
2685bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoU_CDECL_BEGIN
2785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hostatic void U_CALLCONV
2885bf2e2fbc60a9f938064abc8127d61da7d19882Claire HodeleteTimeZoneRule(void* obj) {
2985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    delete (TimeZoneRule*) obj;
3085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho}
3185bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoU_CDECL_END
3285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Smybol characters used by RFC2445 VTIMEZONE
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar COLON = 0x3A; /* : */
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar SEMICOLON = 0x3B; /* ; */
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar EQUALS_SIGN = 0x3D; /* = */
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar COMMA = 0x2C; /* , */
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar PLUS = 0x2B; /* + */
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar MINUS = 0x2D; /* - */
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// RFC2445 VTIMEZONE tokens
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_BEGIN_VTIMEZONE[] = {0x42, 0x45, 0x47, 0x49, 0x4E, 0x3A, 0x56, 0x54, 0x49, 0x4D, 0x45, 0x5A, 0x4F, 0x4E, 0x45, 0}; /* "BEGIN:VTIMEZONE" */
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_END_VTIMEZONE[] = {0x45, 0x4E, 0x44, 0x3A, 0x56, 0x54, 0x49, 0x4D, 0x45, 0x5A, 0x4F, 0x4E, 0x45, 0}; /* "END:VTIMEZONE" */
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_BEGIN[] = {0x42, 0x45, 0x47, 0x49, 0x4E, 0}; /* "BEGIN" */
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_END[] = {0x45, 0x4E, 0x44, 0}; /* "END" */
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_VTIMEZONE[] = {0x56, 0x54, 0x49, 0x4D, 0x45, 0x5A, 0x4F, 0x4E, 0x45, 0}; /* "VTIMEZONE" */
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_TZID[] = {0x54, 0x5A, 0x49, 0x44, 0}; /* "TZID" */
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_STANDARD[] = {0x53, 0x54, 0x41, 0x4E, 0x44, 0x41, 0x52, 0x44, 0}; /* "STANDARD" */
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_DAYLIGHT[] = {0x44, 0x41, 0x59, 0x4C, 0x49, 0x47, 0x48, 0x54, 0}; /* "DAYLIGHT" */
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_DTSTART[] = {0x44, 0x54, 0x53, 0x54, 0x41, 0x52, 0x54, 0}; /* "DTSTART" */
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_TZOFFSETFROM[] = {0x54, 0x5A, 0x4F, 0x46, 0x46, 0x53, 0x45, 0x54, 0x46, 0x52, 0x4F, 0x4D, 0}; /* "TZOFFSETFROM" */
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_TZOFFSETTO[] = {0x54, 0x5A, 0x4F, 0x46, 0x46, 0x53, 0x45, 0x54, 0x54, 0x4F, 0}; /* "TZOFFSETTO" */
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_RDATE[] = {0x52, 0x44, 0x41, 0x54, 0x45, 0}; /* "RDATE" */
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_RRULE[] = {0x52, 0x52, 0x55, 0x4C, 0x45, 0}; /* "RRULE" */
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_TZNAME[] = {0x54, 0x5A, 0x4E, 0x41, 0x4D, 0x45, 0}; /* "TZNAME" */
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_TZURL[] = {0x54, 0x5A, 0x55, 0x52, 0x4C, 0}; /* "TZURL" */
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_LASTMOD[] = {0x4C, 0x41, 0x53, 0x54, 0x2D, 0x4D, 0x4F, 0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0}; /* "LAST-MODIFIED" */
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_FREQ[] = {0x46, 0x52, 0x45, 0x51, 0}; /* "FREQ" */
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_UNTIL[] = {0x55, 0x4E, 0x54, 0x49, 0x4C, 0}; /* "UNTIL" */
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_YEARLY[] = {0x59, 0x45, 0x41, 0x52, 0x4C, 0x59, 0}; /* "YEARLY" */
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_BYMONTH[] = {0x42, 0x59, 0x4D, 0x4F, 0x4E, 0x54, 0x48, 0}; /* "BYMONTH" */
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_BYDAY[] = {0x42, 0x59, 0x44, 0x41, 0x59, 0}; /* "BYDAY" */
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_BYMONTHDAY[] = {0x42, 0x59, 0x4D, 0x4F, 0x4E, 0x54, 0x48, 0x44, 0x41, 0x59, 0}; /* "BYMONTHDAY" */
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_NEWLINE[] = {0x0D, 0x0A, 0}; /* CRLF */
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICAL_DOW_NAMES[7][3] = {
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x53, 0x55, 0}, /* "SU" */
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x4D, 0x4F, 0}, /* "MO" */
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x54, 0x55, 0}, /* "TU" */
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x57, 0x45, 0}, /* "WE" */
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x54, 0x48, 0}, /* "TH" */
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x46, 0x52, 0}, /* "FR" */
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    {0x53, 0x41, 0}  /* "SA" */};
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Month length for non-leap year
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const int32_t MONTHLENGTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// ICU custom property
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICU_TZINFO_PROP[] = {0x58, 0x2D, 0x54, 0x5A, 0x49, 0x4E, 0x46, 0x4F, 0x3A, 0}; /* "X-TZINFO:" */
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICU_TZINFO_PARTIAL[] = {0x2F, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6C, 0x40, 0}; /* "/Partial@" */
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar ICU_TZINFO_SIMPLE[] = {0x2F, 0x53, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x40, 0}; /* "/Simple@" */
84ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
85ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
86ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
87ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Simple fixed digit ASCII number to integer converter
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int32_t parseAsciiDigits(const UnicodeString& str, int32_t start, int32_t length, UErrorCode& status) {
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
91ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
92ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
93ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (length <= 0 || str.length() < start || (start + length) > str.length()) {
94ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t sign = 1;
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (str.charAt(start) == PLUS) {
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        start++;
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        length--;
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (str.charAt(start) == MINUS) {
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        sign = -1;
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        start++;
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        length--;
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t num = 0;
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (int32_t i = 0; i < length; i++) {
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t digit = str.charAt(start + i) - 0x0030;
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (digit < 0 || digit > 9) {
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            status = U_INVALID_FORMAT_ERROR;
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return 0;
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        num = 10 * num + digit;
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return sign * num;
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UnicodeString& appendAsciiDigits(int32_t number, uint8_t length, UnicodeString& str) {
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool negative = FALSE;
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t digits[10]; // max int32_t is 10 decimal digits
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t i;
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (number < 0) {
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        negative = TRUE;
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        number *= -1;
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    length = length > 10 ? 10 : length;
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (length == 0) {
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // variable length
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        i = 0;
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        do {
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            digits[i++] = number % 10;
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            number /= 10;
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } while (number != 0);
136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        length = i;
137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // fixed digits
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (i = 0; i < length; i++) {
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru           digits[i] = number % 10;
141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru           number /= 10;
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (negative) {
145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        str.append(MINUS);
146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (i = length - 1; i >= 0; i--) {
148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        str.append((UChar)(digits[i] + 0x0030));
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return str;
151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UnicodeString& appendMillis(UDate date, UnicodeString& str) {
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool negative = FALSE;
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t digits[20]; // max int64_t is 20 decimal digits
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t i;
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int64_t number;
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (date < MIN_MILLIS) {
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        number = (int64_t)MIN_MILLIS;
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (date > MAX_MILLIS) {
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        number = (int64_t)MAX_MILLIS;
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        number = (int64_t)date;
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (number < 0) {
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        negative = TRUE;
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        number *= -1;
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    i = 0;
171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    do {
172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        digits[i++] = (int32_t)(number % 10);
173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        number /= 10;
174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } while (number != 0);
175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (negative) {
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        str.append(MINUS);
178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    i--;
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (i >= 0) {
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        str.append((UChar)(digits[i--] + 0x0030));
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return str;
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Convert date/time to RFC2445 Date-Time form #1 DATE WITH LOCAL TIME
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UnicodeString& getDateTimeString(UDate time, UnicodeString& str) {
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t year, month, dom, dow, doy, mid;
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    Grego::timeToFields(time, year, month, dom, dow, doy, mid);
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    str.remove();
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(year, 4, str);
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(month + 1, 2, str);
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(dom, 2, str);
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    str.append((UChar)0x0054 /*'T'*/);
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t t = mid;
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t hour = t / U_MILLIS_PER_HOUR;
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    t %= U_MILLIS_PER_HOUR;
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t min = t / U_MILLIS_PER_MINUTE;
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    t %= U_MILLIS_PER_MINUTE;
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t sec = t / U_MILLIS_PER_SECOND;
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(hour, 2, str);
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(min, 2, str);
208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(sec, 2, str);
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return str;
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Convert date/time to RFC2445 Date-Time form #2 DATE WITH UTC TIME
214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UnicodeString& getUTCDateTimeString(UDate time, UnicodeString& str) {
216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    getDateTimeString(time, str);
217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    str.append((UChar)0x005A /*'Z'*/);
218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return str;
219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Parse RFC2445 Date-Time form #1 DATE WITH LOCAL TIME and
223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * #2 DATE WITH UTC TIME
224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UDate parseDateTimeString(const UnicodeString& str, int32_t offset, UErrorCode& status) {
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0.0;
228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool isUTC = FALSE;
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool isValid = FALSE;
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    do {
234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int length = str.length();
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (length != 15 && length != 16) {
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // FORM#1 15 characters, such as "20060317T142115"
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // FORM#2 16 characters, such as "20060317T142115Z"
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (str.charAt(8) != 0x0054) {
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // charcter "T" must be used for separating date and time
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (length == 16) {
245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (str.charAt(15) != 0x005A) {
246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // invalid format
247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            isUTC = TRUE;
250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        year = parseAsciiDigits(str, 0, 4, status);
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        month = parseAsciiDigits(str, 4, 2, status) - 1;  // 0-based
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        day = parseAsciiDigits(str, 6, 2, status);
255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        hour = parseAsciiDigits(str, 9, 2, status);
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        min = parseAsciiDigits(str, 11, 2, status);
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        sec = parseAsciiDigits(str, 13, 2, status);
258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // check valid range
264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t maxDayOfMonth = Grego::monthLength(year, month);
265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (year < 0 || month < 0 || month > 11 || day < 1 || day > maxDayOfMonth ||
266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                hour < 0 || hour >= 24 || min < 0 || min >= 60 || sec < 0 || sec >= 60) {
267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        isValid = TRUE;
271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } while(false);
272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!isValid) {
274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0.0;
276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Calculate the time
278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate time = Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY;
279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    time += (hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE + sec * U_MILLIS_PER_SECOND);
280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!isUTC) {
281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        time -= offset;
282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return time;
284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Convert RFC2445 utc-offset string to milliseconds
288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic int32_t offsetStrToMillis(const UnicodeString& str, UErrorCode& status) {
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool isValid = FALSE;
295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t sign = 0, hour = 0, min = 0, sec = 0;
296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    do {
298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int length = str.length();
299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (length != 5 && length != 7) {
300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // utf-offset must be 5 or 7 characters
301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // sign
304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UChar s = str.charAt(0);
305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (s == PLUS) {
306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            sign = 1;
307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (s == MINUS) {
308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            sign = -1;
309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // utf-offset must start with "+" or "-"
311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        hour = parseAsciiDigits(str, 1, 2, status);
314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        min = parseAsciiDigits(str, 3, 2, status);
315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (length == 7) {
316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            sec = parseAsciiDigits(str, 5, 2, status);
317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        isValid = true;
322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } while(false);
323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!isValid) {
325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return 0;
327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t millis = sign * ((hour * 60 + min) * 60 + sec) * 1000;
329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return millis;
330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Convert milliseconds to RFC2445 utc-offset string
334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void millisToOffset(int32_t millis, UnicodeString& str) {
336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    str.remove();
337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (millis >= 0) {
338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        str.append(PLUS);
339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        str.append(MINUS);
341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        millis = -millis;
342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t hour, min, sec;
344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t t = millis / 1000;
345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    sec = t % 60;
347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    t = (t - sec) / 60;
348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    min = t % 60;
349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    hour = t / 60;
350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(hour, 2, str);
352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(min, 2, str);
353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(sec, 2, str);
354ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
355ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
356ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
357ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Create a default TZNAME from TZID
358ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
35985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hostatic void getDefaultTZName(const UnicodeString tzid, UBool isDST, UnicodeString& zonename) {
36085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    zonename = tzid;
361ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (isDST) {
36285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        zonename += UNICODE_STRING_SIMPLE("(DST)");
363ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
36485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        zonename += UNICODE_STRING_SIMPLE("(STD)");
365ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
366ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
367ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
368ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
369ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Parse individual RRULE
370ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
371ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * On return -
372ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
373ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * month    calculated by BYMONTH-1, or -1 when not found
374ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * dow      day of week in BYDAY, or 0 when not found
375ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * wim      day of week ordinal number in BYDAY, or 0 when not found
376ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * dom      an array of day of month
377ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * domCount number of availble days in dom (domCount is specifying the size of dom on input)
378ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * until    time defined by UNTIL attribute or MIN_MILLIS if not available
379ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
380ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic void parseRRULE(const UnicodeString& rrule, int32_t& month, int32_t& dow, int32_t& wim,
381ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                       int32_t* dom, int32_t& domCount, UDate& until, UErrorCode& status) {
382ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
383ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
384ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
385ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t numDom = 0;
386ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
387ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    month = -1;
388ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    dow = 0;
389ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    wim = 0;
390ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    until = MIN_MILLIS;
391ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
392ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool yearly = FALSE;
393ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    //UBool parseError = FALSE;
394ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
395ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t prop_start = 0;
396ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t prop_end;
397ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString prop, attr, value;
398ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool nextProp = TRUE;
399ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
400ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (nextProp) {
401ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        prop_end = rrule.indexOf(SEMICOLON, prop_start);
402ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (prop_end == -1) {
403ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            prop.setTo(rrule, prop_start);
404ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            nextProp = FALSE;
405ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
406ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            prop.setTo(rrule, prop_start, prop_end - prop_start);
407ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            prop_start = prop_end + 1;
408ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
409ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t eql = prop.indexOf(EQUALS_SIGN);
410ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (eql != -1) {
411ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            attr.setTo(prop, 0, eql);
412ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            value.setTo(prop, eql + 1);
413ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
414ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto rruleParseError;
415ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
416ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
417103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (attr.compare(ICAL_FREQ, -1) == 0) {
418ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // only support YEARLY frequency type
419103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (value.compare(ICAL_YEARLY, -1) == 0) {
420ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                yearly = TRUE;
421ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
422ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto rruleParseError;
423ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
424103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else if (attr.compare(ICAL_UNTIL, -1) == 0) {
425ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // ISO8601 UTC format, for example, "20060315T020000Z"
426ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            until = parseDateTimeString(value, 0, status);
427ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
428ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto rruleParseError;
429ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
430103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else if (attr.compare(ICAL_BYMONTH, -1) == 0) {
431ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Note: BYMONTH may contain multiple months, but only single month make sense for
432ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // VTIMEZONE property.
433ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (value.length() > 2) {
434ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto rruleParseError;
435ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
436ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            month = parseAsciiDigits(value, 0, value.length(), status) - 1;
437ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status) || month < 0 || month >= 12) {
438ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto rruleParseError;
439ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
440103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else if (attr.compare(ICAL_BYDAY, -1) == 0) {
441ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Note: BYDAY may contain multiple day of week separated by comma.  It is unlikely used for
442ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // VTIMEZONE property.  We do not support the case.
443ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
444ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // 2-letter format is used just for representing a day of week, for example, "SU" for Sunday
445ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // 3 or 4-letter format is used for represeinging Nth day of week, for example, "-1SA" for last Saturday
446ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t length = value.length();
447ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (length < 2 || length > 4) {
448ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto rruleParseError;
449ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
450ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (length > 2) {
451ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Nth day of week
452ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t sign = 1;
453ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (value.charAt(0) == PLUS) {
454ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    sign = 1;
455ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else if (value.charAt(0) == MINUS) {
456ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    sign = -1;
457ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else if (length == 4) {
458ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto rruleParseError;
459ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
460ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t n = parseAsciiDigits(value, length - 3, 1, status);
461ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status) || n == 0 || n > 4) {
462ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto rruleParseError;
463ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
464ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                wim = n * sign;
465ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                value.remove(0, length - 2);
466ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
467ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t wday;
468ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (wday = 0; wday < 7; wday++) {
469ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (value.compare(ICAL_DOW_NAMES[wday], 2) == 0) {
470ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    break;
471ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
472ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
473ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (wday < 7) {
474ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Sunday(1) - Saturday(7)
475ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dow = wday + 1;
476ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
477ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto rruleParseError;
478ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
479103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        } else if (attr.compare(ICAL_BYMONTHDAY, -1) == 0) {
480ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Note: BYMONTHDAY may contain multiple days delimitted by comma
481ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            //
482ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // A value of BYMONTHDAY could be negative, for example, -1 means
483ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // the last day in a month
484ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t dom_idx = 0;
485ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t dom_start = 0;
486ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t dom_end;
487ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UBool nextDOM = TRUE;
488ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            while (nextDOM) {
489ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dom_end = value.indexOf(COMMA, dom_start);
490ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (dom_end == -1) {
491ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dom_end = value.length();
492ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    nextDOM = FALSE;
493ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
494ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (dom_idx < domCount) {
495ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dom[dom_idx] = parseAsciiDigits(value, dom_start, dom_end - dom_start, status);
496ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (U_FAILURE(status)) {
497ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        goto rruleParseError;
498ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
499ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dom_idx++;
500ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
501ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    status = U_BUFFER_OVERFLOW_ERROR;
502ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto rruleParseError;
503ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
504ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dom_start = dom_end + 1;
505ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
506ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            numDom = dom_idx;
507ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
508ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
509ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!yearly) {
510ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // FREQ=YEARLY must be set
511ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto rruleParseError;
512ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
513ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Set actual number of parsed DOM (ICAL_BYMONTHDAY)
514ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    domCount = numDom;
515ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
516ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
517ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerurruleParseError:
518ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_SUCCESS(status)) {
519ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Set error status
520ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        status = U_INVALID_FORMAT_ERROR;
521ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
522ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
523ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
52485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hostatic TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOffset, int dstSavings, UDate start,
525ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       UVector* dates, int fromOffset, UErrorCode& status) {
526ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
527ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
528ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
529ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dates == NULL || dates->size() == 0) {
530ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        status = U_ILLEGAL_ARGUMENT_ERROR;
531ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
532ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
533ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
534ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t i, j;
535ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    DateTimeRule *adtr = NULL;
536ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
537ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Parse the first rule
538ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString rrule = *((UnicodeString*)dates->elementAt(0));
539ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t month, dayOfWeek, nthDayOfWeek, dayOfMonth = 0;
540ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t days[7];
541ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t daysCount = sizeof(days)/sizeof(days[0]);
542ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate until;
543ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
544ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    parseRRULE(rrule, month, dayOfWeek, nthDayOfWeek, days, daysCount, until, status);
545ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
546ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
547ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
548ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
549ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dates->size() == 1) {
550ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // No more rules
551ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (daysCount > 1) {
552ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Multiple BYMONTHDAY values
553ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (daysCount != 7 || month == -1 || dayOfWeek == 0) {
554ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Only support the rule using 7 continuous days
555ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // BYMONTH and BYDAY must be set at the same time
556ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto unsupportedRRule;
557ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
558ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t firstDay = 31; // max possible number of dates in a month
559ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (i = 0; i < 7; i++) {
560ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Resolve negative day numbers.  A negative day number should
561ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // not be used in February, but if we see such case, we use 28
562ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // as the base.
563ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (days[i] < 0) {
564ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    days[i] = MONTHLENGTH[month] + days[i] + 1;
565ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
566ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (days[i] < firstDay) {
567ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    firstDay = days[i];
568ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
569ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
570ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Make sure days are continuous
571ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (i = 1; i < 7; i++) {
572ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UBool found = FALSE;
573ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                for (j = 0; j < 7; j++) {
574ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (days[j] == firstDay + i) {
575ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        found = TRUE;
576ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        break;
577ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
578ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
579ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (!found) {
580ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // days are not continuous
581ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto unsupportedRRule;
582ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
583ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
584ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Use DOW_GEQ_DOM rule with firstDay as the start date
585ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            dayOfMonth = firstDay;
586ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
587ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
588ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Check if BYMONTH + BYMONTHDAY + BYDAY rule with multiple RRULE lines.
589ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Otherwise, not supported.
590ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (month == -1 || dayOfWeek == 0 || daysCount == 0) {
591ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // This is not the case
592ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto unsupportedRRule;
593ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
594ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Parse the rest of rules if number of rules is not exceeding 7.
595ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // We can only support 7 continuous days starting from a day of month.
596ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (dates->size() > 7) {
597ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto unsupportedRRule;
598ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
599ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
600ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Note: To check valid date range across multiple rule is a little
601ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // bit complicated.  For now, this code is not doing strict range
602ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // checking across month boundary
603ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
604ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t earliestMonth = month;
605ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t earliestDay = 31;
606ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (i = 0; i < daysCount; i++) {
607ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t dom = days[i];
608ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            dom = dom > 0 ? dom : MONTHLENGTH[month] + dom + 1;
609ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            earliestDay = dom < earliestDay ? dom : earliestDay;
610ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
611ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
612ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t anotherMonth = -1;
613ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (i = 1; i < dates->size(); i++) {
614ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            rrule = *((UnicodeString*)dates->elementAt(i));
615ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UDate tmp_until;
616ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek;
617ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t tmp_days[7];
618ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t tmp_daysCount = sizeof(tmp_days)/sizeof(tmp_days[0]);
619ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            parseRRULE(rrule, tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek, tmp_days, tmp_daysCount, tmp_until, status);
620ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
621ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return NULL;
622ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
623ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // If UNTIL is newer than previous one, use the one
624ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (tmp_until > until) {
625ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                until = tmp_until;
626ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
627ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
628ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Check if BYMONTH + BYMONTHDAY + BYDAY rule
629ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (tmp_month == -1 || tmp_dayOfWeek == 0 || tmp_daysCount == 0) {
630ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto unsupportedRRule;
631ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
632ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Count number of BYMONTHDAY
633ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (daysCount + tmp_daysCount > 7) {
634ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // We cannot support BYMONTHDAY more than 7
635ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto unsupportedRRule;
636ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
637ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Check if the same BYDAY is used.  Otherwise, we cannot
638ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // support the rule
639ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (tmp_dayOfWeek != dayOfWeek) {
640ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto unsupportedRRule;
641ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
642ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Check if the month is same or right next to the primary month
643ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (tmp_month != month) {
644ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (anotherMonth == -1) {
645ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    int32_t diff = tmp_month - month;
646ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (diff == -11 || diff == -1) {
647ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // Previous month
648ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        anotherMonth = tmp_month;
649ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        earliestMonth = anotherMonth;
650ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // Reset earliest day
651ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        earliestDay = 31;
652ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else if (diff == 11 || diff == 1) {
653ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // Next month
654ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        anotherMonth = tmp_month;
655ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
656ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // The day range cannot exceed more than 2 months
657ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        goto unsupportedRRule;
658ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
659ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else if (tmp_month != month && tmp_month != anotherMonth) {
660ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // The day range cannot exceed more than 2 months
661ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto unsupportedRRule;
662ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
663ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
664ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // If ealier month, go through days to find the earliest day
665ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (tmp_month == earliestMonth) {
666ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                for (j = 0; j < tmp_daysCount; j++) {
667ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    tmp_days[j] = tmp_days[j] > 0 ? tmp_days[j] : MONTHLENGTH[tmp_month] + tmp_days[j] + 1;
668ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    earliestDay = tmp_days[j] < earliestDay ? tmp_days[j] : earliestDay;
669ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
670ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
671ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            daysCount += tmp_daysCount;
672ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
673ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (daysCount != 7) {
674ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Number of BYMONTHDAY entries must be 7
675ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto unsupportedRRule;
676ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
677ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        month = earliestMonth;
678ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dayOfMonth = earliestDay;
679ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
680ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
681ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Calculate start/end year and missing fields
682ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t startYear, startMonth, startDOM, startDOW, startDOY, startMID;
683ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    Grego::timeToFields(start + fromOffset, startYear, startMonth, startDOM,
684ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        startDOW, startDOY, startMID);
685ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (month == -1) {
686ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // If BYMONTH is not set, use the month of DTSTART
687ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        month = startMonth;
688ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
689ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dayOfWeek == 0 && nthDayOfWeek == 0 && dayOfMonth == 0) {
690ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // If only YEARLY is set, use the day of DTSTART as BYMONTHDAY
691ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dayOfMonth = startDOM;
692ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
693ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
694ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t endYear;
695ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (until != MIN_MILLIS) {
696ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t endMonth, endDOM, endDOW, endDOY, endMID;
697ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        Grego::timeToFields(until, endYear, endMonth, endDOM, endDOW, endDOY, endMID);
698ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
699ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        endYear = AnnualTimeZoneRule::MAX_YEAR;
700ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
701ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
702ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Create the AnnualDateTimeRule
703ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dayOfWeek == 0 && nthDayOfWeek == 0 && dayOfMonth != 0) {
704ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Day in month rule, for example, 15th day in the month
705ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        adtr = new DateTimeRule(month, dayOfMonth, startMID, DateTimeRule::WALL_TIME);
706ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (dayOfWeek != 0 && nthDayOfWeek != 0 && dayOfMonth == 0) {
707ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Nth day of week rule, for example, last Sunday
708ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        adtr = new DateTimeRule(month, nthDayOfWeek, dayOfWeek, startMID, DateTimeRule::WALL_TIME);
709ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (dayOfWeek != 0 && nthDayOfWeek == 0 && dayOfMonth != 0) {
710ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // First day of week after day of month rule, for example,
711ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // first Sunday after 15th day in the month
712ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        adtr = new DateTimeRule(month, dayOfMonth, dayOfWeek, TRUE, startMID, DateTimeRule::WALL_TIME);
713ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
714ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (adtr == NULL) {
715ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto unsupportedRRule;
716ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
71785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    return new AnnualTimeZoneRule(zonename, rawOffset, dstSavings, adtr, startYear, endYear);
718ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
719ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruunsupportedRRule:
720ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    status = U_INVALID_STATE_ERROR;
721ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return NULL;
722ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
723ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
724ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
725ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Create a TimeZoneRule by the RDATE definition
726ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
72785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Hostatic TimeZoneRule* createRuleByRDATE(const UnicodeString& zonename, int32_t rawOffset, int32_t dstSavings,
728ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       UDate start, UVector* dates, int32_t fromOffset, UErrorCode& status) {
729ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
730ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
731ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
732ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    TimeArrayTimeZoneRule *retVal = NULL;
733ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dates == NULL || dates->size() == 0) {
734ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // When no RDATE line is provided, use start (DTSTART)
735ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // as the transition time
73685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings,
737ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            &start, 1, DateTimeRule::UTC_TIME);
738ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
739ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Create an array of transition times
740ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t size = dates->size();
741ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UDate* times = (UDate*)uprv_malloc(sizeof(UDate) * size);
742ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (times == NULL) {
743ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            status = U_MEMORY_ALLOCATION_ERROR;
744ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return NULL;
745ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
746ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (int32_t i = 0; i < size; i++) {
747ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UnicodeString *datestr = (UnicodeString*)dates->elementAt(i);
748ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            times[i] = parseDateTimeString(*datestr, fromOffset, status);
749ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
750ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                uprv_free(times);
751ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return NULL;
752ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
753ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
75485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings,
755ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            times, size, DateTimeRule::UTC_TIME);
756ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        uprv_free(times);
757ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
758ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return retVal;
759ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
760ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
761ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
762ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Check if the DOW rule specified by month, weekInMonth and dayOfWeek is equivalent
763ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * to the DateTimerule.
764ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
765ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic UBool isEquivalentDateRule(int32_t month, int32_t weekInMonth, int32_t dayOfWeek, const DateTimeRule *dtrule) {
766ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (month != dtrule->getRuleMonth() || dayOfWeek != dtrule->getRuleDayOfWeek()) {
767ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return FALSE;
768ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
769ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dtrule->getTimeRuleType() != DateTimeRule::WALL_TIME) {
770ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Do not try to do more intelligent comparison for now.
771ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return FALSE;
772ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
773ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dtrule->getDateRuleType() == DateTimeRule::DOW
774ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            && dtrule->getRuleWeekInMonth() == weekInMonth) {
775ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return TRUE;
776ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
777ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t ruleDOM = dtrule->getRuleDayOfMonth();
778ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dtrule->getDateRuleType() == DateTimeRule::DOW_GEQ_DOM) {
779ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (ruleDOM%7 == 1 && (ruleDOM + 6)/7 == weekInMonth) {
780ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return TRUE;
781ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
782ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - ruleDOM)%7 == 6
783ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                && weekInMonth == -1*((MONTHLENGTH[month]-ruleDOM+1)/7)) {
784ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return TRUE;
785ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
786ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
787ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dtrule->getDateRuleType() == DateTimeRule::DOW_LEQ_DOM) {
788ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (ruleDOM%7 == 0 && ruleDOM/7 == weekInMonth) {
789ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return TRUE;
790ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
791ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - ruleDOM)%7 == 0
792ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                && weekInMonth == -1*((MONTHLENGTH[month] - ruleDOM)/7 + 1)) {
793ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return TRUE;
794ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
795ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
796ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return FALSE;
797ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
798ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
799ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
800ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Convert the rule to its equivalent rule using WALL_TIME mode.
801ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * This function returns NULL when the specified DateTimeRule is already
802ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * using WALL_TIME mode.
803ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
804ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic DateTimeRule* toWallTimeRule(const DateTimeRule* rule, int32_t rawOffset, int32_t dstSavings) {
805ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (rule->getTimeRuleType() == DateTimeRule::WALL_TIME) {
806ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
807ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
808ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t wallt = rule->getRuleMillisInDay();
809ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (rule->getTimeRuleType() == DateTimeRule::UTC_TIME) {
810ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        wallt += (rawOffset + dstSavings);
811ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (rule->getTimeRuleType() == DateTimeRule::STANDARD_TIME) {
812ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        wallt += dstSavings;
813ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
814ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
815ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t month = -1, dom = 0, dow = 0;
816ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    DateTimeRule::DateRuleType dtype;
817ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dshift = 0;
818ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (wallt < 0) {
819ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dshift = -1;
820ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        wallt += U_MILLIS_PER_DAY;
821ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (wallt >= U_MILLIS_PER_DAY) {
822ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dshift = 1;
823ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        wallt -= U_MILLIS_PER_DAY;
824ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
825ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
826ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    month = rule->getRuleMonth();
827ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    dom = rule->getRuleDayOfMonth();
828ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    dow = rule->getRuleDayOfWeek();
829ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    dtype = rule->getDateRuleType();
830ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
831ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dshift != 0) {
832ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (dtype == DateTimeRule::DOW) {
833ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Convert to DOW_GEW_DOM or DOW_LEQ_DOM rule first
834ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t wim = rule->getRuleWeekInMonth();
835ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (wim > 0) {
836ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtype = DateTimeRule::DOW_GEQ_DOM;
837ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dom = 7 * (wim - 1) + 1;
838ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
839ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtype = DateTimeRule::DOW_LEQ_DOM;
840ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dom = MONTHLENGTH[month] + 7 * (wim + 1);
841ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
842ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
843ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Shift one day before or after
844ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dom += dshift;
845ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (dom == 0) {
846ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            month--;
847ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            month = month < UCAL_JANUARY ? UCAL_DECEMBER : month;
848ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            dom = MONTHLENGTH[month];
849ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (dom > MONTHLENGTH[month]) {
850ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            month++;
851ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            month = month > UCAL_DECEMBER ? UCAL_JANUARY : month;
852ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            dom = 1;
853ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
854ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (dtype != DateTimeRule::DOM) {
855ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Adjust day of week
856ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            dow += dshift;
857ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (dow < UCAL_SUNDAY) {
858ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dow = UCAL_SATURDAY;
859ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else if (dow > UCAL_SATURDAY) {
860ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dow = UCAL_SUNDAY;
861ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
862ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
863ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
864ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Create a new rule
865ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    DateTimeRule *modifiedRule;
866ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dtype == DateTimeRule::DOM) {
867ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        modifiedRule = new DateTimeRule(month, dom, wallt, DateTimeRule::WALL_TIME);
868ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
869ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        modifiedRule = new DateTimeRule(month, dom, dow,
870ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            (dtype == DateTimeRule::DOW_GEQ_DOM), wallt, DateTimeRule::WALL_TIME);
871ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
872ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return modifiedRule;
873ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
874ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
875ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
876ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Minumum implementations of stream writer/reader, writing/reading
877ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * UnicodeString.  For now, we do not want to introduce the dependency
878ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * on the ICU I/O stream in this module.  But we want to keep the code
879ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * equivalent to the ICU4J implementation, which utilizes java.io.Writer/
880ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Reader.
881ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
882ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruclass VTZWriter {
883ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querupublic:
884ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTZWriter(UnicodeString& out);
885ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    ~VTZWriter();
886ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
887ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    void write(const UnicodeString& str);
888ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    void write(UChar ch);
889103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    void write(const UChar* str);
890ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    //void write(const UChar* str, int32_t length);
891ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruprivate:
892ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString* out;
893ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
894ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
895ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZWriter::VTZWriter(UnicodeString& output) {
896ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    out = &output;
897ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
898ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
899ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZWriter::~VTZWriter() {
900ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
901ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
902ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
903ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZWriter::write(const UnicodeString& str) {
904ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    out->append(str);
905ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
906ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
907ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
908ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZWriter::write(UChar ch) {
909ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    out->append(ch);
910ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
911ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
912103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusvoid
913103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliusVTZWriter::write(const UChar* str) {
914103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    out->append(str, -1);
915103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius}
916103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius
917ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
918ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
919ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZWriter::write(const UChar* str, int32_t length) {
920ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    out->append(str, length);
921ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
922ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*/
923ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
924ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruclass VTZReader {
925ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querupublic:
926ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTZReader(const UnicodeString& input);
927ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    ~VTZReader();
928ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
929ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UChar read(void);
930ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruprivate:
931ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const UnicodeString* in;
932ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t index;
933ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
934ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
935ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZReader::VTZReader(const UnicodeString& input) {
936ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    in = &input;
937ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    index = 0;
938ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
939ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
940ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZReader::~VTZReader() {
941ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
942ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
943ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUChar
944ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTZReader::read(void) {
945ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UChar ch = 0xFFFF;
946ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (index < in->length()) {
947ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        ch = in->charAt(index);
948ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
949ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    index++;
950ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return ch;
951ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
952ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
953ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
954ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUOBJECT_DEFINE_RTTI_IMPLEMENTATION(VTimeZone)
955ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
956ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::VTimeZone()
957ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru:   BasicTimeZone(), tz(NULL), vtzlines(NULL),
958ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    lastmod(MAX_MILLIS) {
959ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
960ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
961ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::VTimeZone(const VTimeZone& source)
962ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru:   BasicTimeZone(source), tz(NULL), vtzlines(NULL),
963ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    tzurl(source.tzurl), lastmod(source.lastmod),
964ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    olsonzid(source.olsonzid), icutzver(source.icutzver) {
965ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (source.tz != NULL) {
966ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        tz = (BasicTimeZone*)source.tz->clone();
967ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
968ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (source.vtzlines != NULL) {
969ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UErrorCode status = U_ZERO_ERROR;
970ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t size = source.vtzlines->size();
971103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
972ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_SUCCESS(status)) {
973ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            for (int32_t i = 0; i < size; i++) {
974ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UnicodeString *line = (UnicodeString*)source.vtzlines->elementAt(i);
975ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                vtzlines->addElement(line->clone(), status);
976ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
977ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    break;
978ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
979ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
980ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
981ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status) && vtzlines != NULL) {
982ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            delete vtzlines;
983ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
984ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
985ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
986ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
987ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::~VTimeZone() {
988ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (tz != NULL) {
989ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete tz;
990ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
991ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (vtzlines != NULL) {
992ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete vtzlines;
993ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
994ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
995ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
996ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone&
997ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::operator=(const VTimeZone& right) {
998ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (this == &right) {
999ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return *this;
1000ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1001ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (*this != right) {
1002ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        BasicTimeZone::operator=(right);
1003ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (tz != NULL) {
1004ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            delete tz;
1005ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            tz = NULL;
1006ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1007ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (right.tz != NULL) {
1008ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            tz = (BasicTimeZone*)right.tz->clone();
1009ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1010ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (vtzlines != NULL) {
1011ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            delete vtzlines;
1012ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1013ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (right.vtzlines != NULL) {
1014ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UErrorCode status = U_ZERO_ERROR;
1015ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t size = right.vtzlines->size();
1016103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
1017ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_SUCCESS(status)) {
1018ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                for (int32_t i = 0; i < size; i++) {
1019ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    UnicodeString *line = (UnicodeString*)right.vtzlines->elementAt(i);
1020ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    vtzlines->addElement(line->clone(), status);
1021ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (U_FAILURE(status)) {
1022ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        break;
1023ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1024ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1025ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1026ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status) && vtzlines != NULL) {
1027ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                delete vtzlines;
1028ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                vtzlines = NULL;
1029ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1030ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1031ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        tzurl = right.tzurl;
1032ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        lastmod = right.lastmod;
1033ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        olsonzid = right.olsonzid;
1034ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        icutzver = right.icutzver;
1035ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1036ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return *this;
1037ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1038ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1039ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1040ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::operator==(const TimeZone& that) const {
1041ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (this == &that) {
1042ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return TRUE;
1043ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
104427f654740f2a26ad62a5c155af9199af9e69b889claireho    if (typeid(*this) != typeid(that) || !BasicTimeZone::operator==(that)) {
1045ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return FALSE;
1046ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1047ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTimeZone *vtz = (VTimeZone*)&that;
1048ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (*tz == *(vtz->tz)
1049ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        && tzurl == vtz->tzurl
1050ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        && lastmod == vtz->lastmod
1051ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        /* && olsonzid = that.olsonzid */
1052ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        /* && icutzver = that.icutzver */) {
1053ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return TRUE;
1054ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1055ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return FALSE;
1056ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1057ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1058ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1059ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::operator!=(const TimeZone& that) const {
1060ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return !operator==(that);
1061ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1062ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1063ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone*
1064ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::createVTimeZoneByID(const UnicodeString& ID) {
1065ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTimeZone *vtz = new VTimeZone();
1066ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    vtz->tz = (BasicTimeZone*)TimeZone::createTimeZone(ID);
1067ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    vtz->tz->getID(vtz->olsonzid);
1068ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1069ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Set ICU tzdata version
1070ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
1071ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UResourceBundle *bundle = NULL;
1072ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const UChar* versionStr = NULL;
107327f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t len = 0;
107427f654740f2a26ad62a5c155af9199af9e69b889claireho    bundle = ures_openDirect(NULL, "zoneinfo64", &status);
107527f654740f2a26ad62a5c155af9199af9e69b889claireho    versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
107627f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_SUCCESS(status)) {
107727f654740f2a26ad62a5c155af9199af9e69b889claireho        vtz->icutzver.setTo(versionStr, len);
107827f654740f2a26ad62a5c155af9199af9e69b889claireho    }
107927f654740f2a26ad62a5c155af9199af9e69b889claireho    ures_close(bundle);
108027f654740f2a26ad62a5c155af9199af9e69b889claireho    return vtz;
108127f654740f2a26ad62a5c155af9199af9e69b889claireho}
108227f654740f2a26ad62a5c155af9199af9e69b889claireho
108327f654740f2a26ad62a5c155af9199af9e69b889clairehoVTimeZone*
108427f654740f2a26ad62a5c155af9199af9e69b889clairehoVTimeZone::createVTimeZoneFromBasicTimeZone(const BasicTimeZone& basic_time_zone, UErrorCode &status) {
108527f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_FAILURE(status)) {
108627f654740f2a26ad62a5c155af9199af9e69b889claireho        return NULL;
108727f654740f2a26ad62a5c155af9199af9e69b889claireho    }
108827f654740f2a26ad62a5c155af9199af9e69b889claireho    VTimeZone *vtz = new VTimeZone();
108927f654740f2a26ad62a5c155af9199af9e69b889claireho    if (vtz == NULL) {
109027f654740f2a26ad62a5c155af9199af9e69b889claireho        status = U_MEMORY_ALLOCATION_ERROR;
109127f654740f2a26ad62a5c155af9199af9e69b889claireho        return NULL;
109227f654740f2a26ad62a5c155af9199af9e69b889claireho    }
109327f654740f2a26ad62a5c155af9199af9e69b889claireho    vtz->tz = (BasicTimeZone *)basic_time_zone.clone();
109427f654740f2a26ad62a5c155af9199af9e69b889claireho    if (vtz->tz == NULL) {
109527f654740f2a26ad62a5c155af9199af9e69b889claireho        status = U_MEMORY_ALLOCATION_ERROR;
109627f654740f2a26ad62a5c155af9199af9e69b889claireho        delete vtz;
109727f654740f2a26ad62a5c155af9199af9e69b889claireho        return NULL;
109827f654740f2a26ad62a5c155af9199af9e69b889claireho    }
109927f654740f2a26ad62a5c155af9199af9e69b889claireho    vtz->tz->getID(vtz->olsonzid);
110027f654740f2a26ad62a5c155af9199af9e69b889claireho
110127f654740f2a26ad62a5c155af9199af9e69b889claireho    // Set ICU tzdata version
110227f654740f2a26ad62a5c155af9199af9e69b889claireho    UResourceBundle *bundle = NULL;
110327f654740f2a26ad62a5c155af9199af9e69b889claireho    const UChar* versionStr = NULL;
110427f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t len = 0;
110527f654740f2a26ad62a5c155af9199af9e69b889claireho    bundle = ures_openDirect(NULL, "zoneinfo64", &status);
1106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
1107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_SUCCESS(status)) {
1108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        vtz->icutzver.setTo(versionStr, len);
1109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    ures_close(bundle);
1111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return vtz;
1112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone*
1115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::createVTimeZone(const UnicodeString& vtzdata, UErrorCode& status) {
1116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
1118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTZReader reader(vtzdata);
1120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTimeZone *vtz = new VTimeZone();
1121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    vtz->load(reader, status);
1122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete vtz;
1124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return NULL;
1125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return vtz;
1127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getTZURL(UnicodeString& url) const {
1131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (tzurl.length() > 0) {
1132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        url = tzurl;
1133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return TRUE;
1134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return FALSE;
1136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::setTZURL(const UnicodeString& url) {
1140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    tzurl = url;
1141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getLastModified(UDate& lastModified) const {
1145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (lastmod != MAX_MILLIS) {
1146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        lastModified = lastmod;
1147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return TRUE;
1148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return FALSE;
1150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::setLastModified(UDate lastModified) {
1154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    lastmod = lastModified;
1155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::write(UnicodeString& result, UErrorCode& status) const {
1159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    result.remove();
1160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTZWriter writer(result);
1161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    write(writer, status);
1162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
11658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::write(UDate start, UnicodeString& result, UErrorCode& status) const {
1166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    result.remove();
1167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTZWriter writer(result);
1168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    write(start, writer, status);
1169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
11728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) const {
1173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    result.remove();
1174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    VTZWriter writer(result);
1175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writeSimple(time, writer, status);
1176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruTimeZone*
1179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::clone(void) const {
1180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return new VTimeZone(*this);
1181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
1184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
1185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                     uint8_t dayOfWeek, int32_t millis, UErrorCode& status) const {
1186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->getOffset(era, year, month, day, dayOfWeek, millis, status);
1187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
1190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
1191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                     uint8_t dayOfWeek, int32_t millis,
1192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                     int32_t monthLength, UErrorCode& status) const {
1193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->getOffset(era, year, month, day, dayOfWeek, millis, monthLength, status);
1194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
1198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                     int32_t& dstOffset, UErrorCode& status) const {
1199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->getOffset(date, local, rawOffset, dstOffset, status);
1200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::setRawOffset(int32_t offsetMillis) {
1204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    tz->setRawOffset(offsetMillis);
1205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
1208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getRawOffset(void) const {
1209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->getRawOffset();
1210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::useDaylightTime(void) const {
1214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->useDaylightTime();
1215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::inDaylightTime(UDate date, UErrorCode& status) const {
1219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->inDaylightTime(date, status);
1220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
1223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::hasSameRules(const TimeZone& other) const {
1224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->hasSameRules(other);
1225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
12288393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
1229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->getNextTransition(base, inclusive, result);
1230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool
12338393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
1234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->getPreviousTransition(base, inclusive, result);
1235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t
12388393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::countTransitionRules(UErrorCode& status) const {
1239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return tz->countTransitionRules(status);
1240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
1244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            const TimeZoneRule* trsrules[], int32_t& trscount,
12458393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius                            UErrorCode& status) const {
1246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    tz->getTimeZoneRules(initial, trsrules, trscount, status);
1247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::load(VTZReader& reader, UErrorCode& status) {
1251103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
1252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool eol = FALSE;
1256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool start = FALSE;
1257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool success = FALSE;
1258ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString line;
1259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (TRUE) {
1261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UChar ch = reader.read();
1262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (ch == 0xFFFF) {
1263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // end of file
1264103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (start && line.startsWith(ICAL_END_VTIMEZONE, -1)) {
1265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                vtzlines->addElement(new UnicodeString(line), status);
1266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
1267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupVtzlines;
1268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                success = TRUE;
1270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
1272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (ch == 0x000D) {
1274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // CR, must be followed by LF according to the definition in RFC2445
1275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            continue;
1276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (eol) {
1278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (ch != 0x0009 && ch != 0x0020) {
1279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // NOT followed by TAB/SP -> new line
1280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (start) {
1281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (line.length() > 0) {
1282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        vtzlines->addElement(new UnicodeString(line), status);
1283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        if (U_FAILURE(status)) {
1284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            goto cleanupVtzlines;
1285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        }
1286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                line.remove();
1289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (ch != 0x000A) {
1290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    line.append(ch);
1291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            eol = FALSE;
1294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
1295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (ch == 0x000A) {
1296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // LF
1297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                eol = TRUE;
1298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (start) {
1299103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    if (line.startsWith(ICAL_END_VTIMEZONE, -1)) {
1300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        vtzlines->addElement(new UnicodeString(line), status);
1301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        if (U_FAILURE(status)) {
1302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            goto cleanupVtzlines;
1303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        }
1304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        success = TRUE;
1305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        break;
1306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
1308103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    if (line.startsWith(ICAL_BEGIN_VTIMEZONE, -1)) {
1309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        vtzlines->addElement(new UnicodeString(line), status);
1310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        if (U_FAILURE(status)) {
1311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            goto cleanupVtzlines;
1312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        }
1313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        line.remove();
1314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        start = TRUE;
1315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        eol = FALSE;
1316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
1319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                line.append(ch);
1320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!success) {
1324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_SUCCESS(status)) {
1325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            status = U_INVALID_STATE_ERROR;
1326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto cleanupVtzlines;
1328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    parse(status);
1330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
1331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerucleanupVtzlines:
1333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    delete vtzlines;
1334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    vtzlines = NULL;
1335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// parser state
1338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define INI 0   // Initial state
1339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define VTZ 1   // In VTIMEZONE
1340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define TZI 2   // In STANDARD or DAYLIGHT
1341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define DEF_DSTSAVINGS (60*60*1000)
1343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#define DEF_TZSTARTTIME (0.0)
1344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::parse(UErrorCode& status) {
1347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (vtzlines == NULL || vtzlines->size() == 0) {
1351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        status = U_INVALID_STATE_ERROR;
1352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1354ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    InitialTimeZoneRule *initialRule = NULL;
1355ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    RuleBasedTimeZone *rbtz = NULL;
1356ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1357ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // timezone ID
1358ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString tzid;
1359ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1360ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t state = INI;
1361ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t n = 0;
1362ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool dst = FALSE;      // current zone type
1363ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString from;     // current zone from offset
1364ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString to;       // current zone offset
136585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    UnicodeString zonename;   // current zone name
1366ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dtstart;  // current zone starts
1367ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool isRRULE = FALSE;  // true if the rule is described by RRULE
1368ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t initialRawOffset = 0;   // initial offset
1369ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t initialDSTSavings = 0;  // initial offset
1370ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate firstStart = MAX_MILLIS;  // the earliest rule start time
1371ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString name;     // RFC2445 prop name
1372ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString value;    // RFC2445 prop value
1373ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1374ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UVector *dates = NULL;  // list of RDATE or RRULE strings
1375ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UVector *rules = NULL;  // list of TimeZoneRule instances
1376ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
137785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    int32_t finalRuleIdx = -1;
137885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    int32_t finalRuleCount = 0;
137985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
1380ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    rules = new UVector(status);
1381ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1382ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto cleanupParse;
1383ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
138485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho     // Set the deleter to remove TimeZoneRule vectors to avoid memory leaks due to unowned TimeZoneRules.
138585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    rules->setDeleter(deleteTimeZoneRule);
138685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
1387103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    dates = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
1388ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1389ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto cleanupParse;
1390ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
139185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (rules == NULL || dates == NULL) {
139285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        status = U_MEMORY_ALLOCATION_ERROR;
139385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        goto cleanupParse;
139485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
1395ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1396ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (n = 0; n < vtzlines->size(); n++) {
1397ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UnicodeString *line = (UnicodeString*)vtzlines->elementAt(n);
1398ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t valueSep = line->indexOf(COLON);
1399ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (valueSep < 0) {
1400ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            continue;
1401ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1402ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        name.setTo(*line, 0, valueSep);
1403ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        value.setTo(*line, valueSep + 1);
1404ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1405ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        switch (state) {
1406ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case INI:
1407103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (name.compare(ICAL_BEGIN, -1) == 0
1408103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                && value.compare(ICAL_VTIMEZONE, -1) == 0) {
1409ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                state = VTZ;
1410ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1411ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
1412ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1413ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case VTZ:
1414103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (name.compare(ICAL_TZID, -1) == 0) {
1415ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                tzid = value;
1416103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_TZURL, -1) == 0) {
1417ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                tzurl = value;
1418103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_LASTMOD, -1) == 0) {
1419ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Always in 'Z' format, so the offset argument for the parse method
1420ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // can be any value.
1421ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                lastmod = parseDateTimeString(value, 0, status);
1422ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
1423ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1424ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1425103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_BEGIN, -1) == 0) {
1426103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                UBool isDST = (value.compare(ICAL_DAYLIGHT, -1) == 0);
1427103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                if (value.compare(ICAL_STANDARD, -1) == 0 || isDST) {
1428ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // tzid must be ready at this point
1429ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (tzid.length() == 0) {
1430ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        goto cleanupParse;
1431ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1432ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // initialize current zone properties
1433ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (dates->size() != 0) {
1434ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        dates->removeAllElements();
1435ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1436ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    isRRULE = FALSE;
1437ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    from.remove();
1438ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    to.remove();
143985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    zonename.remove();
1440ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dst = isDST;
1441ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    state = TZI;
1442ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
1443ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // BEGIN property other than STANDARD/DAYLIGHT
1444ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // must not be there.
1445ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1446ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1447103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_END, -1) == 0) {
1448ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
1449ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1450ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
1451ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        case TZI:
1452103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (name.compare(ICAL_DTSTART, -1) == 0) {
1453ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtstart = value;
1454103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_TZNAME, -1) == 0) {
145585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                zonename = value;
1456103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_TZOFFSETFROM, -1) == 0) {
1457ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                from = value;
1458103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_TZOFFSETTO, -1) == 0) {
1459ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                to = value;
1460103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_RDATE, -1) == 0) {
1461ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // RDATE mixed with RRULE is not supported
1462ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (isRRULE) {
1463ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1464ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1465ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // RDATE value may contain multiple date delimited
1466ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // by comma
1467ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UBool nextDate = TRUE;
1468ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t dstart = 0;
1469ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UnicodeString *dstr;
1470ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                while (nextDate) {
1471ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    int32_t dend = value.indexOf(COMMA, dstart);
1472ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (dend == -1) {
1473ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        dstr = new UnicodeString(value, dstart);
1474ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        nextDate = FALSE;
1475ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
1476ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        dstr = new UnicodeString(value, dstart, dend - dstart);
1477ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1478ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dates->addElement(dstr, status);
1479ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (U_FAILURE(status)) {
1480ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        goto cleanupParse;
1481ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1482ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dstart = dend + 1;
1483ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1484103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_RRULE, -1) == 0) {
1485ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // RRULE mixed with RDATE is not supported
1486ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (!isRRULE && dates->size() != 0) {
1487ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1488ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1489ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                isRRULE = true;
1490ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dates->addElement(new UnicodeString(value), status);
1491ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
1492ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1493ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1494103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (name.compare(ICAL_END, -1) == 0) {
1495ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Mandatory properties
1496ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (dtstart.length() == 0 || from.length() == 0 || to.length() == 0) {
1497ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1498ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
149985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                // if zonename is not available, create one from tzid
150085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                if (zonename.length() == 0) {
150185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    getDefaultTZName(tzid, dst, zonename);
1502ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1503ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1504ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // create a time zone rule
1505ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                TimeZoneRule *rule = NULL;
1506ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t fromOffset = 0;
1507ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t toOffset = 0;
1508ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t rawOffset = 0;
1509ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t dstSavings = 0;
1510ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UDate start = 0;
1511ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1512ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Parse TZOFFSETFROM/TZOFFSETTO
1513ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                fromOffset = offsetStrToMillis(from, status);
1514ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                toOffset = offsetStrToMillis(to, status);
1515ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
1516ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1517ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1518ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1519ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (dst) {
1520ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // If daylight, use the previous offset as rawoffset if positive
1521ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (toOffset - fromOffset > 0) {
1522ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        rawOffset = fromOffset;
1523ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        dstSavings = toOffset - fromOffset;
1524ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
1525ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // This is rare case..  just use 1 hour DST savings
1526ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        rawOffset = toOffset - DEF_DSTSAVINGS;
1527ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        dstSavings = DEF_DSTSAVINGS;
1528ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1529ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
1530ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    rawOffset = toOffset;
1531ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dstSavings = 0;
1532ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1533ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1534ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // start time
1535ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                start = parseDateTimeString(dtstart, fromOffset, status);
1536ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
1537ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1538ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1539ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1540ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Create the rule
1541ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UDate actualStart = MAX_MILLIS;
1542ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (isRRULE) {
154385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    rule = createRuleByRRULE(zonename, rawOffset, dstSavings, start, dates, fromOffset, status);
1544ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
154585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    rule = createRuleByRDATE(zonename, rawOffset, dstSavings, start, dates, fromOffset, status);
1546ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1547ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status) || rule == NULL) {
1548ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1549ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
1550ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    UBool startAvail = rule->getFirstStart(fromOffset, 0, actualStart);
1551ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (startAvail && actualStart < firstStart) {
1552ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // save from offset information for the earliest rule
1553ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        firstStart = actualStart;
1554ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // If this is STD, assume the time before this transtion
1555ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // is DST when the difference is 1 hour.  This might not be
1556ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // accurate, but VTIMEZONE data does not have such info.
1557ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        if (dstSavings > 0) {
1558ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            initialRawOffset = fromOffset;
1559ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            initialDSTSavings = 0;
1560ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        } else {
1561ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            if (fromOffset - toOffset == DEF_DSTSAVINGS) {
1562ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                initialRawOffset = fromOffset - DEF_DSTSAVINGS;
1563ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                initialDSTSavings = DEF_DSTSAVINGS;
1564ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            } else {
1565ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                initialRawOffset = fromOffset;
1566ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                initialDSTSavings = 0;
1567ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            }
1568ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        }
1569ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1570ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1571ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rules->addElement(rule, status);
1572ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
1573ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupParse;
1574ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1575ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                state = VTZ;
1576ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1577ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
1578ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1579ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1580ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Must have at least one rule
1581ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (rules->size() == 0) {
1582ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto cleanupParse;
1583ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1584ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1585ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Create a initial rule
158685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    getDefaultTZName(tzid, FALSE, zonename);
158785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    initialRule = new InitialTimeZoneRule(zonename,
1588ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        initialRawOffset, initialDSTSavings);
158985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (initialRule == NULL) {
159085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        status = U_MEMORY_ALLOCATION_ERROR;
159185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        goto cleanupParse;
159285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
1593ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1594ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Finally, create the RuleBasedTimeZone
1595ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    rbtz = new RuleBasedTimeZone(tzid, initialRule);
159685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (rbtz == NULL) {
159785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        status = U_MEMORY_ALLOCATION_ERROR;
159885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        goto cleanupParse;
159985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
160085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    initialRule = NULL; // already adopted by RBTZ, no need to delete
160185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
160285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    for (n = 0; n < rules->size(); n++) {
160385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        TimeZoneRule *r = (TimeZoneRule*)rules->elementAt(n);
160427f654740f2a26ad62a5c155af9199af9e69b889claireho        AnnualTimeZoneRule *atzrule = dynamic_cast<AnnualTimeZoneRule *>(r);
160527f654740f2a26ad62a5c155af9199af9e69b889claireho        if (atzrule != NULL) {
160627f654740f2a26ad62a5c155af9199af9e69b889claireho            if (atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
160785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                finalRuleCount++;
160885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                finalRuleIdx = n;
160985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
161085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
161185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
161285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (finalRuleCount > 2) {
161385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        // Too many final rules
161485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        status = U_ILLEGAL_ARGUMENT_ERROR;
161585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        goto cleanupParse;
161685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
161785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
161885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    if (finalRuleCount == 1) {
161985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        if (rules->size() == 1) {
162085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // Only one final rule, only governs the initial rule,
162185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // which is already initialized, thus, we do not need to
162285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // add this transition rule
162385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            rules->removeAllElements();
162485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        } else {
162585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // Normalize the final rule
162685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            AnnualTimeZoneRule *finalRule = (AnnualTimeZoneRule*)rules->elementAt(finalRuleIdx);
162785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            int32_t tmpRaw = finalRule->getRawOffset();
162885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            int32_t tmpDST = finalRule->getDSTSavings();
162985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
163085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            // Find the last non-final rule
163185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            UDate finalStart, start;
163285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            finalRule->getFirstStart(initialRawOffset, initialDSTSavings, finalStart);
163385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            start = finalStart;
163485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            for (n = 0; n < rules->size(); n++) {
163585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                if (finalRuleIdx == n) {
163685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    continue;
163785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                }
163885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                TimeZoneRule *r = (TimeZoneRule*)rules->elementAt(n);
163985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                UDate lastStart;
164085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                r->getFinalStart(tmpRaw, tmpDST, lastStart);
164185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                if (lastStart > start) {
164285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                    finalRule->getNextStart(lastStart,
164385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        r->getRawOffset(),
164485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        r->getDSTSavings(),
164585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        FALSE,
164685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        start);
164785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                }
164885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
164985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
165085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            TimeZoneRule *newRule;
165185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            UnicodeString tznam;
165285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            if (start == finalStart) {
165385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                // Transform this into a single transition
165485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                newRule = new TimeArrayTimeZoneRule(
165585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getName(tznam),
165685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getRawOffset(),
165785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getDSTSavings(),
165885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        &finalStart,
165985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        1,
166085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        DateTimeRule::UTC_TIME);
166185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            } else {
166285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                // Update the end year
166385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                int32_t y, m, d, dow, doy, mid;
166485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                Grego::timeToFields(start, y, m, d, dow, doy, mid);
166585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                newRule = new AnnualTimeZoneRule(
166685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getName(tznam),
166785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getRawOffset(),
166885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getDSTSavings(),
166985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        *(finalRule->getRule()),
167085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        finalRule->getStartYear(),
167185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                        y);
167285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
167385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            if (newRule == NULL) {
167485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                status = U_MEMORY_ALLOCATION_ERROR;
167585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                goto cleanupParse;
167685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
167785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            rules->removeElementAt(finalRuleIdx);
167885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            rules->addElement(newRule, status);
167985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            if (U_FAILURE(status)) {
168085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                delete newRule;
168185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho                goto cleanupParse;
168285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            }
168385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        }
168485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    }
168585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho
1686ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (!rules->isEmpty()) {
1687ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        TimeZoneRule *tzr = (TimeZoneRule*)rules->orphanElementAt(0);
1688ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        rbtz->addTransitionRule(tzr, status);
1689ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
1690ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto cleanupParse;
1691ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1692ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1693ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    rbtz->complete(status);
1694ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1695ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto cleanupParse;
1696ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1697ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    delete rules;
1698ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    delete dates;
1699ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1700ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    tz = rbtz;
1701ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    setID(tzid);
1702ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
1703ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1704ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerucleanupParse:
1705ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (rules != NULL) {
1706ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        while (!rules->isEmpty()) {
1707ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            TimeZoneRule *r = (TimeZoneRule*)rules->orphanElementAt(0);
1708ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            delete r;
1709ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1710ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete rules;
1711ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1712ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dates != NULL) {
1713ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete dates;
1714ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1715ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (initialRule != NULL) {
1716ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete initialRule;
1717ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1718ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (rbtz != NULL) {
1719ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete rbtz;
1720ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1721ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
1722ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1723ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1724ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1725ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
1726ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (vtzlines != NULL) {
1727ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (int32_t i = 0; i < vtzlines->size(); i++) {
1728ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UnicodeString *line = (UnicodeString*)vtzlines->elementAt(i);
1729103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            if (line->startsWith(ICAL_TZURL, -1)
1730ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                && line->charAt(u_strlen(ICAL_TZURL)) == COLON) {
1731ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(ICAL_TZURL);
1732ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(COLON);
1733ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(tzurl);
1734ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(ICAL_NEWLINE);
1735103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            } else if (line->startsWith(ICAL_LASTMOD, -1)
1736ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                && line->charAt(u_strlen(ICAL_LASTMOD)) == COLON) {
1737ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UnicodeString utcString;
1738ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(ICAL_LASTMOD);
1739ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(COLON);
1740ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(getUTCDateTimeString(lastmod, utcString));
1741ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(ICAL_NEWLINE);
1742ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
1743ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(*line);
1744ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                writer.write(ICAL_NEWLINE);
1745ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1746ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1747ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
1748ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UVector *customProps = NULL;
1749ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (olsonzid.length() > 0 && icutzver.length() > 0) {
1750103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            customProps = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
1751ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
1752ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return;
1753ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1754ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
1755ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append(olsonzid);
1756ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append((UChar)0x005B/*'['*/);
1757ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append(icutzver);
1758ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append((UChar)0x005D/*']'*/);
1759ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            customProps->addElement(icutzprop, status);
1760ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
1761ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                delete icutzprop;
1762ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                delete customProps;
1763ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return;
1764ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1765ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1766ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZone(writer, *tz, customProps, status);
1767ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete customProps;
1768ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1769ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1770ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1771ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
17728393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
1773ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1774ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1775ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1776ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    InitialTimeZoneRule *initial = NULL;
1777ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UVector *transitionRules = NULL;
1778103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
1779ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString tzid;
1780ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1781ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Extract rules applicable to dates after the start time
1782ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    getTimeZoneRulesAfter(start, initial, transitionRules, status);
1783ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1784ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1785ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1786ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1787ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Create a RuleBasedTimeZone with the subset rule
1788ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    getID(tzid);
1789ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    RuleBasedTimeZone rbtz(tzid, initial);
1790ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (transitionRules != NULL) {
1791ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        while (!transitionRules->isEmpty()) {
1792ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            TimeZoneRule *tr = (TimeZoneRule*)transitionRules->orphanElementAt(0);
1793ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            rbtz.addTransitionRule(tr, status);
1794ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
1795ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto cleanupWritePartial;
1796ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1797ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1798ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete transitionRules;
1799ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        transitionRules = NULL;
1800ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1801ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    rbtz.complete(status);
1802ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1803ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        goto cleanupWritePartial;
1804ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1805ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1806ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (olsonzid.length() > 0 && icutzver.length() > 0) {
1807ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
1808ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        icutzprop->append(olsonzid);
1809ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        icutzprop->append((UChar)0x005B/*'['*/);
1810ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        icutzprop->append(icutzver);
1811103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        icutzprop->append(ICU_TZINFO_PARTIAL, -1);
1812ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendMillis(start, *icutzprop);
1813ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        icutzprop->append((UChar)0x005D/*']'*/);
1814ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        customProps.addElement(icutzprop, status);
1815ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
1816ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            delete icutzprop;
1817ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto cleanupWritePartial;
1818ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1819ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1820ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writeZone(writer, rbtz, &customProps, status);
1821ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
1822ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1823ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerucleanupWritePartial:
1824ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (initial != NULL) {
1825ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete initial;
1826ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1827ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (transitionRules != NULL) {
1828ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        while (!transitionRules->isEmpty()) {
1829ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            TimeZoneRule *tr = (TimeZoneRule*)transitionRules->orphanElementAt(0);
1830ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            delete tr;
1831ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1832ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete transitionRules;
1833ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1834ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1835ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1836ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
18378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig CorneliusVTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) const {
1838ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1839ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1840ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1841ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1842103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
1843ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString tzid;
1844ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1845ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Extract simple rules
1846ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    InitialTimeZoneRule *initial = NULL;
1847ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    AnnualTimeZoneRule *std = NULL, *dst = NULL;
1848ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    getSimpleRulesNear(time, initial, std, dst, status);
1849ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_SUCCESS(status)) {
1850ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Create a RuleBasedTimeZone with the subset rule
1851ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        getID(tzid);
1852ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        RuleBasedTimeZone rbtz(tzid, initial);
1853ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (std != NULL && dst != NULL) {
1854ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            rbtz.addTransitionRule(std, status);
1855ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            rbtz.addTransitionRule(dst, status);
1856ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1857ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
1858ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto cleanupWriteSimple;
1859ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1860ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1861ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (olsonzid.length() > 0 && icutzver.length() > 0) {
1862ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
1863ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append(olsonzid);
1864ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append((UChar)0x005B/*'['*/);
1865ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append(icutzver);
1866103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            icutzprop->append(ICU_TZINFO_SIMPLE, -1);
1867ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            appendMillis(time, *icutzprop);
1868ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            icutzprop->append((UChar)0x005D/*']'*/);
1869ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            customProps.addElement(icutzprop, status);
1870ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
1871ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                delete icutzprop;
1872ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                goto cleanupWriteSimple;
1873ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1874ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1875ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZone(writer, rbtz, &customProps, status);
1876ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1877ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return;
1878ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1879ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerucleanupWriteSimple:
1880ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (initial != NULL) {
1881ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete initial;
1882ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1883ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (std != NULL) {
1884ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete std;
1885ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1886ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dst != NULL) {
1887ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete dst;
1888ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1889ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
1890ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1891ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
1892ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
1893ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                     UVector* customProps, UErrorCode& status) const {
1894ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1895ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1896ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1897ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writeHeaders(w, status);
1898ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
1899ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
1900ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1901ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1902ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (customProps != NULL) {
1903ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        for (int32_t i = 0; i < customProps->size(); i++) {
1904ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            UnicodeString *custprop = (UnicodeString*)customProps->elementAt(i);
1905ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            w.write(*custprop);
1906ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            w.write(ICAL_NEWLINE);
1907ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1908ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
1909ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1910ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate t = MIN_MILLIS;
1911ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dstName;
1912ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstFromOffset = 0;
1913ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstFromDSTSavings = 0;
1914ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstToOffset = 0;
1915ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstStartYear = 0;
1916ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstMonth = 0;
1917ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstDayOfWeek = 0;
1918ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstWeekInMonth = 0;
1919ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstMillisInDay = 0;
1920ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate dstStartTime = 0.0;
1921ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate dstUntilTime = 0.0;
1922ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t dstCount = 0;
1923ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    AnnualTimeZoneRule *finalDstRule = NULL;
1924ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1925ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString stdName;
1926ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdFromOffset = 0;
1927ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdFromDSTSavings = 0;
1928ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdToOffset = 0;
1929ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdStartYear = 0;
1930ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdMonth = 0;
1931ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdDayOfWeek = 0;
1932ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdWeekInMonth = 0;
1933ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdMillisInDay = 0;
1934ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate stdStartTime = 0.0;
1935ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UDate stdUntilTime = 0.0;
1936ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t stdCount = 0;
1937ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    AnnualTimeZoneRule *finalStdRule = NULL;
1938ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1939ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t year, month, dom, dow, doy, mid;
1940ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool hasTransitions = FALSE;
1941ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    TimeZoneTransition tzt;
1942ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool tztAvail;
1943ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString name;
1944ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool isDst;
1945ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
1946ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Going through all transitions
1947ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (TRUE) {
1948ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        tztAvail = basictz.getNextTransition(t, FALSE, tzt);
1949ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (!tztAvail) {
1950ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            break;
1951ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
1952ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        hasTransitions = TRUE;
1953ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        t = tzt.getTime();
1954ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        tzt.getTo()->getName(name);
1955ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        isDst = (tzt.getTo()->getDSTSavings() != 0);
1956ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t fromOffset = tzt.getFrom()->getRawOffset() + tzt.getFrom()->getDSTSavings();
1957ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t fromDSTSavings = tzt.getFrom()->getDSTSavings();
1958ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t toOffset = tzt.getTo()->getRawOffset() + tzt.getTo()->getDSTSavings();
1959ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        Grego::timeToFields(tzt.getTime() + fromOffset, year, month, dom, dow, doy, mid);
1960ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
1961ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UBool sameRule = FALSE;
196227f654740f2a26ad62a5c155af9199af9e69b889claireho        const AnnualTimeZoneRule *atzrule;
1963ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (isDst) {
1964ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (finalDstRule == NULL
196527f654740f2a26ad62a5c155af9199af9e69b889claireho                && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != NULL
196627f654740f2a26ad62a5c155af9199af9e69b889claireho                && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
196727f654740f2a26ad62a5c155af9199af9e69b889claireho            ) {
196827f654740f2a26ad62a5c155af9199af9e69b889claireho                finalDstRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
1969ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1970ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (dstCount > 0) {
1971ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (year == dstStartYear + dstCount
1972ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && name.compare(dstName) == 0
1973ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && dstFromOffset == fromOffset
1974ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && dstToOffset == toOffset
1975ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && dstMonth == month
1976ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && dstDayOfWeek == dow
1977ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && dstWeekInMonth == weekInMonth
1978ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && dstMillisInDay == mid) {
1979ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // Update until time
1980ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dstUntilTime = t;
1981ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    dstCount++;
1982ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    sameRule = TRUE;
1983ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1984ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (!sameRule) {
1985ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (dstCount == 1) {
1986ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByTime(w, TRUE, dstName, dstFromOffset, dstToOffset, dstStartTime,
1987ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                TRUE, status);
1988ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
1989ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
1990ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime, status);
1991ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1992ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (U_FAILURE(status)) {
1993ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        goto cleanupWriteZone;
1994ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
1995ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
1996ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
1997ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (!sameRule) {
1998ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Reset this DST information
1999ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstName = name;
2000ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstFromOffset = fromOffset;
2001ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstFromDSTSavings = fromDSTSavings;
2002ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstToOffset = toOffset;
2003ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstStartYear = year;
2004ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstMonth = month;
2005ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstDayOfWeek = dow;
2006ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstWeekInMonth = weekInMonth;
2007ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstMillisInDay = mid;
2008ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstStartTime = dstUntilTime = t;
2009ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dstCount = 1;
2010ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2011ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (finalStdRule != NULL && finalDstRule != NULL) {
2012ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
2013ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2014ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
2015ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (finalStdRule == NULL
201627f654740f2a26ad62a5c155af9199af9e69b889claireho                && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != NULL
201727f654740f2a26ad62a5c155af9199af9e69b889claireho                && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
201827f654740f2a26ad62a5c155af9199af9e69b889claireho            ) {
201927f654740f2a26ad62a5c155af9199af9e69b889claireho                finalStdRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
2020ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2021ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (stdCount > 0) {
2022ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (year == stdStartYear + stdCount
2023ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && name.compare(stdName) == 0
2024ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && stdFromOffset == fromOffset
2025ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && stdToOffset == toOffset
2026ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && stdMonth == month
2027ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && stdDayOfWeek == dow
2028ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && stdWeekInMonth == weekInMonth
2029ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        && stdMillisInDay == mid) {
2030ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // Update until time
2031ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    stdUntilTime = t;
2032ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    stdCount++;
2033ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    sameRule = TRUE;
2034ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2035ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (!sameRule) {
2036ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (stdCount == 1) {
2037ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByTime(w, FALSE, stdName, stdFromOffset, stdToOffset, stdStartTime,
2038ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                TRUE, status);
2039ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
2040ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
2041ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, stdUntilTime, status);
2042ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
2043ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (U_FAILURE(status)) {
2044ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        goto cleanupWriteZone;
2045ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
2046ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2047ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2048ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (!sameRule) {
2049ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // Reset this STD information
2050ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdName = name;
2051ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdFromOffset = fromOffset;
2052ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdFromDSTSavings = fromDSTSavings;
2053ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdToOffset = toOffset;
2054ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdStartYear = year;
2055ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdMonth = month;
2056ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdDayOfWeek = dow;
2057ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdWeekInMonth = weekInMonth;
2058ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdMillisInDay = mid;
2059ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdStartTime = stdUntilTime = t;
2060ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                stdCount = 1;
2061ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2062ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (finalStdRule != NULL && finalDstRule != NULL) {
2063ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                break;
2064ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2065ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2066ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2067ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (!hasTransitions) {
2068ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // No transition - put a single non transition RDATE
2069ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t raw, dst, offset;
2070ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        basictz.getOffset(0.0/*any time*/, FALSE, raw, dst, status);
2071ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2072ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto cleanupWriteZone;
2073ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2074ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        offset = raw + dst;
2075ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        isDst = (dst != 0);
2076ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UnicodeString tzid;
2077ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        basictz.getID(tzid);
2078ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        getDefaultTZName(tzid, isDst, name);
2079ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZonePropsByTime(w, isDst, name,
2080ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                offset, offset, DEF_TZSTARTTIME - offset, FALSE, status);
2081ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2082ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            goto cleanupWriteZone;
2083ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2084ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
2085ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (dstCount > 0) {
2086ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (finalDstRule == NULL) {
2087ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (dstCount == 1) {
2088ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    writeZonePropsByTime(w, TRUE, dstName, dstFromOffset, dstToOffset, dstStartTime,
2089ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            TRUE, status);
2090ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
2091ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
2092ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime, status);
2093ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2094ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
2095ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupWriteZone;
2096ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2097ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
2098ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (dstCount == 1) {
2099ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    writeFinalRule(w, TRUE, finalDstRule,
2100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, dstStartTime, status);
2101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
2102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // Use a single rule if possible
2103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (isEquivalentDateRule(dstMonth, dstWeekInMonth, dstDayOfWeek, finalDstRule->getRule())) {
2104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
2105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, MAX_MILLIS, status);
2106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
2107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // Not equivalent rule - write out two different rules
2108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByDOW(w, TRUE, dstName, dstFromOffset, dstToOffset,
2109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                dstMonth, dstWeekInMonth, dstDayOfWeek, dstStartTime, dstUntilTime, status);
2110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        if (U_FAILURE(status)) {
2111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            goto cleanupWriteZone;
2112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        }
211359d709d503bab6e2b61931737e662dd293b40578ccornelius                        UDate nextStart;
211459d709d503bab6e2b61931737e662dd293b40578ccornelius                        UBool nextStartAvail = finalDstRule->getNextStart(dstUntilTime, dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, false, nextStart);
211559d709d503bab6e2b61931737e662dd293b40578ccornelius                        U_ASSERT(nextStartAvail);
211659d709d503bab6e2b61931737e662dd293b40578ccornelius                        if (nextStartAvail) {
211759d709d503bab6e2b61931737e662dd293b40578ccornelius                            writeFinalRule(w, TRUE, finalDstRule,
211859d709d503bab6e2b61931737e662dd293b40578ccornelius                                    dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, nextStart, status);
211959d709d503bab6e2b61931737e662dd293b40578ccornelius                        }
2120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
2121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
2123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupWriteZone;
2124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (stdCount > 0) {
2128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (finalStdRule == NULL) {
2129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (stdCount == 1) {
2130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    writeZonePropsByTime(w, FALSE, stdName, stdFromOffset, stdToOffset, stdStartTime,
2131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            TRUE, status);
2132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
2133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
2134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, stdUntilTime, status);
2135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2136ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
2137ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupWriteZone;
2138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
2140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (stdCount == 1) {
2141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    writeFinalRule(w, FALSE, finalStdRule,
2142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, stdStartTime, status);
2143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                } else {
2144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    // Use a single rule if possible
2145ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    if (isEquivalentDateRule(stdMonth, stdWeekInMonth, stdDayOfWeek, finalStdRule->getRule())) {
2146ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
214759d709d503bab6e2b61931737e662dd293b40578ccornelius                                stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, MAX_MILLIS, status);
2148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    } else {
2149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        // Not equivalent rule - write out two different rules
2150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
2151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, stdUntilTime, status);
2152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        if (U_FAILURE(status)) {
2153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                            goto cleanupWriteZone;
2154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                        }
215559d709d503bab6e2b61931737e662dd293b40578ccornelius                        UDate nextStart;
215659d709d503bab6e2b61931737e662dd293b40578ccornelius                        UBool nextStartAvail = finalStdRule->getNextStart(stdUntilTime, stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, false, nextStart);
215759d709d503bab6e2b61931737e662dd293b40578ccornelius                        U_ASSERT(nextStartAvail);
215859d709d503bab6e2b61931737e662dd293b40578ccornelius                        if (nextStartAvail) {
215959d709d503bab6e2b61931737e662dd293b40578ccornelius                            writeFinalRule(w, FALSE, finalStdRule,
216059d709d503bab6e2b61931737e662dd293b40578ccornelius                                    stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, nextStart, status);
216159d709d503bab6e2b61931737e662dd293b40578ccornelius                        }
2162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    }
2163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (U_FAILURE(status)) {
2165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    goto cleanupWriteZone;
2166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
2167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writeFooter(w, status);
2171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2172ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QuerucleanupWriteZone:
2173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2174ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (finalStdRule != NULL) {
2175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete finalStdRule;
2176ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (finalDstRule != NULL) {
2178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete finalDstRule;
2179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::writeHeaders(VTZWriter& writer, UErrorCode& status) const {
2184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString tzid;
2188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    tz->getID(tzid);
2189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BEGIN);
2191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_VTIMEZONE);
2193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_TZID);
2195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(tzid);
2197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (tzurl.length() != 0) {
2199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_TZURL);
2200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(COLON);
2201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(tzurl);
2202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_NEWLINE);
2203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (lastmod != MAX_MILLIS) {
2205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UnicodeString lastmodStr;
2206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_LASTMOD);
2207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(COLON);
2208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(getUTCDateTimeString(lastmod, lastmodStr));
2209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_NEWLINE);
2210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write the closing section of the VTIMEZONE definition block
2215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2216ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::writeFooter(VTZWriter& writer, UErrorCode& status) const {
2218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_END);
2222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_VTIMEZONE);
2224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write a single start time
2229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
223185bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoVTimeZone::writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
2232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                int32_t fromOffset, int32_t toOffset, UDate time, UBool withRDATE,
2233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                UErrorCode& status) const {
2234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
223785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, time, status);
2238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (withRDATE) {
2242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_RDATE);
2243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(COLON);
2244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UnicodeString timestr;
2245ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(getDateTimeString(time + fromOffset, timestr));
2246ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_NEWLINE);
2247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    endZoneProps(writer, isDst, status);
2249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write start times defined by a DOM rule using VTIMEZONE RRULE
2256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
225885bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoVTimeZone::writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
2259ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               int32_t fromOffset, int32_t toOffset,
2260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               int32_t month, int32_t dayOfMonth, UDate startTime, UDate untilTime,
2261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UErrorCode& status) const {
2262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
226585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, startTime, status);
2266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    beginRRULE(writer, month, status);
2270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BYMONTHDAY);
2274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(EQUALS_SIGN);
2275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dstr;
2276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(dayOfMonth, 0, dstr);
2277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(dstr);
2278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (untilTime != MAX_MILLIS) {
2279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
2280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    endZoneProps(writer, isDst, status);
2286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write start times defined by a DOW rule using VTIMEZONE RRULE
2290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
229285bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoVTimeZone::writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
2293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               int32_t fromOffset, int32_t toOffset,
2294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               int32_t month, int32_t weekInMonth, int32_t dayOfWeek,
2295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UDate startTime, UDate untilTime, UErrorCode& status) const {
2296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
229985bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, startTime, status);
2300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    beginRRULE(writer, month, status);
2304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BYDAY);
2308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(EQUALS_SIGN);
2309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dstr;
2310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(weekInMonth, 0, dstr);
2311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(dstr);    // -4, -3, -2, -1, 1, 2, 3, 4
2312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_DOW_NAMES[dayOfWeek - 1]);    // SU, MO, TU...
2313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (untilTime != MAX_MILLIS) {
2315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
2316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    endZoneProps(writer, isDst, status);
2322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write start times defined by a DOW_GEQ_DOM rule using VTIMEZONE RRULE
2326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
232885bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoVTimeZone::writeZonePropsByDOW_GEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
2329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       int32_t fromOffset, int32_t toOffset,
2330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
2331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       UDate startTime, UDate untilTime, UErrorCode& status) const {
2332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Check if this rule can be converted to DOW rule
2336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dayOfMonth%7 == 1) {
2337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Can be represented by DOW rule
233885bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
2339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                month, (dayOfMonth + 6)/7, dayOfWeek, startTime, untilTime, status);
2340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - dayOfMonth)%7 == 6) {
2344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Can be represented by DOW rule with negative week number
234585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
2346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                month, -1*((MONTHLENGTH[month] - dayOfMonth + 1)/7), dayOfWeek, startTime, untilTime, status);
2347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
2351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Otherwise, use BYMONTHDAY to include all possible dates
235285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, startTime, status);
2353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2354ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2355ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2356ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Check if all days are in the same month
2357ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t startDay = dayOfMonth;
2358ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t currentMonthDays = 7;
2359ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2360ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (dayOfMonth <= 0) {
2361ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // The start day is in previous month
2362ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t prevMonthDays = 1 - dayOfMonth;
2363ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            currentMonthDays -= prevMonthDays;
2364ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2365ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t prevMonth = (month - 1) < 0 ? 11 : month - 1;
2366ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2367ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Note: When a rule is separated into two, UNTIL attribute needs to be
2368ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // calculated for each of them.  For now, we skip this, because we basically use this method
2369ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // only for final rules, which does not have the UNTIL attribute
2370ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            writeZonePropsByDOW_GEQ_DOM_sub(writer, prevMonth, -prevMonthDays, dayOfWeek, prevMonthDays,
2371ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                MAX_MILLIS /* Do not use UNTIL */, fromOffset, status);
2372ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
2373ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return;
2374ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2375ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2376ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Start from 1 for the rest
2377ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            startDay = 1;
2378ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (dayOfMonth + 6 > MONTHLENGTH[month]) {
2379ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // Note: This code does not actually work well in February.  For now, days in month in
2380ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // non-leap year.
2381ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t nextMonthDays = dayOfMonth + 6 - MONTHLENGTH[month];
2382ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            currentMonthDays -= nextMonthDays;
2383ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2384ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t nextMonth = (month + 1) > 11 ? 0 : month + 1;
2385ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2386ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            writeZonePropsByDOW_GEQ_DOM_sub(writer, nextMonth, 1, dayOfWeek, nextMonthDays,
2387ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                MAX_MILLIS /* Do not use UNTIL */, fromOffset, status);
2388ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (U_FAILURE(status)) {
2389ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return;
2390ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
2391ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2392ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZonePropsByDOW_GEQ_DOM_sub(writer, month, startDay, dayOfWeek, currentMonthDays,
2393ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            untilTime, fromOffset, status);
2394ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2395ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2396ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2397ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        endZoneProps(writer, isDst, status);
2398ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2399ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2400ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2401ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2402ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Called from writeZonePropsByDOW_GEQ_DOM
2403ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2404ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2405ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::writeZonePropsByDOW_GEQ_DOM_sub(VTZWriter& writer, int32_t month, int32_t dayOfMonth,
2406ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                           int32_t dayOfWeek, int32_t numDays,
2407ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                           UDate untilTime, int32_t fromOffset, UErrorCode& status) const {
2408ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2409ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2410ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2411ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2412ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t startDayNum = dayOfMonth;
2413ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool isFeb = (month == UCAL_FEBRUARY);
2414ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dayOfMonth < 0 && !isFeb) {
2415ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Use positive number if possible
2416ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        startDayNum = MONTHLENGTH[month] + dayOfMonth + 1;
2417ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2418ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    beginRRULE(writer, month, status);
2419ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2420ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2421ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2422ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BYDAY);
2423ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(EQUALS_SIGN);
2424ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_DOW_NAMES[dayOfWeek - 1]);    // SU, MO, TU...
2425ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(SEMICOLON);
2426ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BYMONTHDAY);
2427ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(EQUALS_SIGN);
2428ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2429ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dstr;
2430ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(startDayNum, 0, dstr);
2431ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(dstr);
2432ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (int32_t i = 1; i < numDays; i++) {
2433ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(COMMA);
2434ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dstr.remove();
2435ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendAsciiDigits(startDayNum + i, 0, dstr);
2436ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(dstr);
2437ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2438ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2439ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (untilTime != MAX_MILLIS) {
2440ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendUNTIL(writer, getDateTimeString(untilTime + fromOffset, dstr), status);
2441ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (U_FAILURE(status)) {
2442ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return;
2443ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
2444ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2445ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2446ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2447ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2448ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2449ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write start times defined by a DOW_LEQ_DOM rule using VTIMEZONE RRULE
2450ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2451ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
245285bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoVTimeZone::writeZonePropsByDOW_LEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
2453ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       int32_t fromOffset, int32_t toOffset,
2454ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
2455ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                       UDate startTime, UDate untilTime, UErrorCode& status) const {
2456ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2457ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2458ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2459ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Check if this rule can be converted to DOW rule
2460ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dayOfMonth%7 == 0) {
2461ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Can be represented by DOW rule
246285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
2463ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                month, dayOfMonth/7, dayOfWeek, startTime, untilTime, status);
2464ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - dayOfMonth)%7 == 0){
2465ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Can be represented by DOW rule with negative week number
246685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
2467ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                month, -1*((MONTHLENGTH[month] - dayOfMonth)/7 + 1), dayOfWeek, startTime, untilTime, status);
2468ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else if (month == UCAL_FEBRUARY && dayOfMonth == 29) {
2469ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Specical case for February
247085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
2471ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                UCAL_FEBRUARY, -1, dayOfWeek, startTime, untilTime, status);
2472ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
2473ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Otherwise, convert this to DOW_GEQ_DOM rule
247485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        writeZonePropsByDOW_GEQ_DOM(writer, isDst, zonename, fromOffset, toOffset,
2475ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                month, dayOfMonth - 6, dayOfWeek, startTime, untilTime, status);
2476ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2477ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2478ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2479ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2480ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write the final time zone rule using RRULE, with no UNTIL attribute
2481ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2482ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2483ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::writeFinalRule(VTZWriter& writer, UBool isDst, const AnnualTimeZoneRule* rule,
2484ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                          int32_t fromRawOffset, int32_t fromDSTSavings,
2485ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                          UDate startTime, UErrorCode& status) const {
2486ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2487ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2488ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2489ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UBool modifiedRule = TRUE;
2490ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    const DateTimeRule *dtrule = toWallTimeRule(rule->getRule(), fromRawOffset, fromDSTSavings);
2491ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (dtrule == NULL) {
2492ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        modifiedRule = FALSE;
2493ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        dtrule = rule->getRule();
2494ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
249527f654740f2a26ad62a5c155af9199af9e69b889claireho
249627f654740f2a26ad62a5c155af9199af9e69b889claireho    // If the rule's mills in a day is out of range, adjust start time.
249727f654740f2a26ad62a5c155af9199af9e69b889claireho    // Olson tzdata supports 24:00 of a day, but VTIMEZONE does not.
249827f654740f2a26ad62a5c155af9199af9e69b889claireho    // See ticket#7008/#7518
249927f654740f2a26ad62a5c155af9199af9e69b889claireho
250027f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t timeInDay = dtrule->getRuleMillisInDay();
250127f654740f2a26ad62a5c155af9199af9e69b889claireho    if (timeInDay < 0) {
250227f654740f2a26ad62a5c155af9199af9e69b889claireho        startTime = startTime + (0 - timeInDay);
250327f654740f2a26ad62a5c155af9199af9e69b889claireho    } else if (timeInDay >= U_MILLIS_PER_DAY) {
250427f654740f2a26ad62a5c155af9199af9e69b889claireho        startTime = startTime - (timeInDay - (U_MILLIS_PER_DAY - 1));
250527f654740f2a26ad62a5c155af9199af9e69b889claireho    }
250627f654740f2a26ad62a5c155af9199af9e69b889claireho
2507ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t toOffset = rule->getRawOffset() + rule->getDSTSavings();
2508ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString name;
2509ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    rule->getName(name);
2510ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    switch (dtrule->getDateRuleType()) {
2511ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    case DateTimeRule::DOM:
2512ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZonePropsByDOM(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
2513ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtrule->getRuleMonth(), dtrule->getRuleDayOfMonth(), startTime, MAX_MILLIS, status);
2514ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        break;
2515ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    case DateTimeRule::DOW:
2516ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZonePropsByDOW(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
2517ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtrule->getRuleMonth(), dtrule->getRuleWeekInMonth(), dtrule->getRuleDayOfWeek(), startTime, MAX_MILLIS, status);
2518ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        break;
2519ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    case DateTimeRule::DOW_GEQ_DOM:
2520ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZonePropsByDOW_GEQ_DOM(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
2521ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtrule->getRuleMonth(), dtrule->getRuleDayOfMonth(), dtrule->getRuleDayOfWeek(), startTime, MAX_MILLIS, status);
2522ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        break;
2523ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    case DateTimeRule::DOW_LEQ_DOM:
2524ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writeZonePropsByDOW_LEQ_DOM(writer, isDst, name, fromRawOffset + fromDSTSavings, toOffset,
2525ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                dtrule->getRuleMonth(), dtrule->getRuleDayOfMonth(), dtrule->getRuleDayOfWeek(), startTime, MAX_MILLIS, status);
2526ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        break;
2527ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2528ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (modifiedRule) {
2529ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        delete dtrule;
2530ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2531ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2532ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2533ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2534ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write the opening section of zone properties
2535ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2536ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
253785bf2e2fbc60a9f938064abc8127d61da7d19882Claire HoVTimeZone::beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
2538ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                          int32_t fromOffset, int32_t toOffset, UDate startTime, UErrorCode& status) const {
2539ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2540ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2541ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2542ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BEGIN);
2543ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2544ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (isDst) {
2545ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_DAYLIGHT);
2546ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
2547ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_STANDARD);
2548ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2549ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2550ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2551ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dstr;
2552ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2553ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // TZOFFSETTO
2554ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_TZOFFSETTO);
2555ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2556ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    millisToOffset(toOffset, dstr);
2557ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(dstr);
2558ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2559ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2560ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // TZOFFSETFROM
2561ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_TZOFFSETFROM);
2562ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2563ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    millisToOffset(fromOffset, dstr);
2564ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(dstr);
2565ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2566ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2567ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // TZNAME
2568ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_TZNAME);
2569ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
257085bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho    writer.write(zonename);
2571ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2572ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2573ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // DTSTART
2574ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_DTSTART);
2575ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2576ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(getDateTimeString(startTime + fromOffset, dstr));
2577ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2578ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2579ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2580ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2581ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Writes the closing section of zone properties
2582ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2583ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2584ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::endZoneProps(VTZWriter& writer, UBool isDst, UErrorCode& status) const {
2585ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2586ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2587ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2588ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // END:STANDARD or END:DAYLIGHT
2589ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_END);
2590ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2591ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (isDst) {
2592ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_DAYLIGHT);
2593ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    } else {
2594ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_STANDARD);
2595ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2596ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_NEWLINE);
2597ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2598ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2599ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2600ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Write the beggining part of RRULE line
2601ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2602ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2603ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::beginRRULE(VTZWriter& writer, int32_t month, UErrorCode& status) const {
2604ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2605ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2606ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2607ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UnicodeString dstr;
2608ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_RRULE);
2609ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(COLON);
2610ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_FREQ);
2611ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(EQUALS_SIGN);
2612ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_YEARLY);
2613ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(SEMICOLON);
2614ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(ICAL_BYMONTH);
2615ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(EQUALS_SIGN);
2616ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    appendAsciiDigits(month + 1, 0, dstr);
2617ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(dstr);
2618ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    writer.write(SEMICOLON);
2619ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2620ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2621ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2622ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Append the UNTIL attribute after RRULE line
2623ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
2624ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid
2625ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruVTimeZone::appendUNTIL(VTZWriter& writer, const UnicodeString& until,  UErrorCode& status) const {
2626ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (U_FAILURE(status)) {
2627ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return;
2628ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2629ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (until.length() > 0) {
2630ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(SEMICOLON);
2631ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(ICAL_UNTIL);
2632ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(EQUALS_SIGN);
2633ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        writer.write(until);
2634ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
2635ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
2636ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2637ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
2638ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2639ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#endif /* #if !UCONFIG_NO_FORMATTING */
2640ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
2641ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//eof
2642