1/*
2**********************************************************************
3* Copyright (c) 2003-2007, International Business Machines
4* Corporation and others.  All Rights Reserved.
5**********************************************************************
6* Author: Alan Liu
7* Created: July 21 2003
8* Since: ICU 2.8
9**********************************************************************
10*/
11#ifndef OLSONTZ_H
12#define OLSONTZ_H
13
14#include "unicode/utypes.h"
15
16#if !UCONFIG_NO_FORMATTING
17
18#include "unicode/basictz.h"
19
20struct UResourceBundle;
21
22U_NAMESPACE_BEGIN
23
24class SimpleTimeZone;
25
26/**
27 * A time zone based on the Olson database.  Olson time zones change
28 * behavior over time.  The raw offset, rules, presence or absence of
29 * daylight savings time, and even the daylight savings amount can all
30 * vary.
31 *
32 * This class uses a resource bundle named "zoneinfo".  Zoneinfo is a
33 * table containing different kinds of resources.  In several places,
34 * zones are referred to using integers.  A zone's integer is a number
35 * from 0..n-1, where n is the number of zones, with the zones sorted
36 * in lexicographic order.
37 *
38 * 1. Zones.  These have keys corresponding to the Olson IDs, e.g.,
39 * "Asia/Shanghai".  Each resource describes the behavior of the given
40 * zone.  Zones come in several formats, which are differentiated
41 * based on length.
42 *
43 *  a. Alias (int, length 1).  An alias zone is an int resource.  The
44 *  integer is the zone number of the target zone.  The key of this
45 *  resource is an alternate name for the target zone.  Aliases
46 *  represent Olson links and ICU compatibility IDs.
47 *
48 *  b. Simple zone (array, length 3).  The three subelements are:
49 *
50 *   i. An intvector of transitions.  These are given in epoch
51 *   seconds.  This may be an empty invector (length 0).  If the
52 *   transtions list is empty, then the zone's behavior is fixed and
53 *   given by the offset list, which will contain exactly one pair.
54 *   Otherwise each transtion indicates a time after which (inclusive)
55 *   the associated offset pair is in effect.
56 *
57 *   ii. An intvector of offsets.  These are in pairs of raw offset /
58 *   DST offset, in units of seconds.  There will be at least one pair
59 *   (length >= 2 && length % 2 == 0).
60 *
61 *   iii. A binary resource.  This is of the same length as the
62 *   transitions vector, so length may be zero.  Each unsigned byte
63 *   corresponds to one transition, and has a value of 0..n-1, where n
64 *   is the number of pairs in the offset vector.  This forms a map
65 *   between transitions and offset pairs.
66 *
67 *  c. Simple zone with aliases (array, length 4).  This is like a
68 *  simple zone, but also contains a fourth element:
69 *
70 *   iv. An intvector of aliases.  This list includes this zone
71 *   itself, and lists all aliases of this zone.
72 *
73 *  d. Complex zone (array, length 5).  This is like a simple zone,
74 *  but contains two more elements:
75 *
76 *   iv. A string, giving the name of a rule.  This is the "final
77 *   rule", which governs the zone's behavior beginning in the "final
78 *   year".  The rule ID is given without leading underscore, e.g.,
79 *   "EU".
80 *
81 *   v. An intvector of length 2, containing the raw offset for the
82 *   final rule (in seconds), and the final year.  The final rule
83 *   takes effect for years >= the final year.
84 *
85 *  e. Complex zone with aliases (array, length 6).  This is like a
86 *  complex zone, but also contains a sixth element:
87 *
88 *   vi. An intvector of aliases.  This list includes this zone
89 *   itself, and lists all aliases of this zone.
90 *
91 * 2. Rules.  These have keys corresponding to the Olson rule IDs,
92 * with an underscore prepended, e.g., "_EU".  Each resource describes
93 * the behavior of the given rule using an intvector, containing the
94 * onset list, the cessation list, and the DST savings.  The onset and
95 * cessation lists consist of the month, dowim, dow, time, and time
96 * mode.  The end result is that the 11 integers describing the rule
97 * can be passed directly into the SimpleTimeZone 13-argument
98 * constructor (the other two arguments will be the raw offset, taken
99 * from the complex zone element 5, and the ID string, which is not
100 * used), with the times and the DST savings multiplied by 1000 to
101 * scale from seconds to milliseconds.
102 *
103 * 3. Countries.  These have keys corresponding to the 2-letter ISO
104 * country codes, with a percent sign prepended, e.g., "%US".  Each
105 * resource is an intvector listing the zones associated with the
106 * given country.  The special entry "%" corresponds to "no country",
107 * that is, the category of zones assigned to no country in the Olson
108 * DB.
109 *
110 * 4. Metadata.  Metadata is stored under the key "_".  It is an
111 * intvector of length three containing the number of zones resources,
112 * rule resources, and country resources.  For the purposes of this
113 * count, the metadata entry itself is considered a rule resource,
114 * since its key begins with an underscore.
115 */
116class OlsonTimeZone: public BasicTimeZone {
117 public:
118    /**
119     * Construct from a resource bundle.
120     * @param top the top-level zoneinfo resource bundle.  This is used
121     * to lookup the rule that `res' may refer to, if there is one.
122     * @param res the resource bundle of the zone to be constructed
123     * @param ec input-output error code
124     */
125    OlsonTimeZone(const UResourceBundle* top,
126                  const UResourceBundle* res, UErrorCode& ec);
127
128    /**
129     * Copy constructor
130     */
131    OlsonTimeZone(const OlsonTimeZone& other);
132
133    /**
134     * Destructor
135     */
136    virtual ~OlsonTimeZone();
137
138    /**
139     * Assignment operator
140     */
141    OlsonTimeZone& operator=(const OlsonTimeZone& other);
142
143    /**
144     * Returns true if the two TimeZone objects are equal.
145     */
146    virtual UBool operator==(const TimeZone& other) const;
147
148    /**
149     * TimeZone API.
150     */
151    virtual TimeZone* clone() const;
152
153    /**
154     * TimeZone API.
155     */
156    U_I18N_API static UClassID U_EXPORT2 getStaticClassID();
157
158    /**
159     * TimeZone API.
160     */
161    virtual UClassID getDynamicClassID() const;
162
163    /**
164     * TimeZone API.  Do not call this; prefer getOffset(UDate,...).
165     */
166    virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month,
167                              int32_t day, uint8_t dayOfWeek,
168                              int32_t millis, UErrorCode& ec) const;
169
170    /**
171     * TimeZone API.  Do not call this; prefer getOffset(UDate,...).
172     */
173    virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month,
174                              int32_t day, uint8_t dayOfWeek,
175                              int32_t millis, int32_t monthLength,
176                              UErrorCode& ec) const;
177
178    /**
179     * TimeZone API.
180     */
181    virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
182                   int32_t& dstOffset, UErrorCode& ec) const;
183
184    /**
185     * BasicTimeZone API.
186     */
187    virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
188        int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/;
189
190    /**
191     * TimeZone API.  This method has no effect since objects of this
192     * class are quasi-immutable (the base class allows the ID to be
193     * changed).
194     */
195    virtual void setRawOffset(int32_t offsetMillis);
196
197    /**
198     * TimeZone API.  For a historical zone, the raw offset can change
199     * over time, so this API is not useful.  In order to approximate
200     * expected behavior, this method returns the raw offset for the
201     * current moment in time.
202     */
203    virtual int32_t getRawOffset() const;
204
205    /**
206     * TimeZone API.  For a historical zone, whether DST is used or
207     * not varies over time.  In order to approximate expected
208     * behavior, this method returns TRUE if DST is observed at any
209     * point in the current year.
210     */
211    virtual UBool useDaylightTime() const;
212
213    /**
214     * TimeZone API.
215     */
216    virtual UBool inDaylightTime(UDate date, UErrorCode& ec) const;
217
218    /**
219     * TimeZone API.
220     */
221    virtual int32_t getDSTSavings() const;
222
223    /**
224     * TimeZone API.  Also comare historic transitions.
225     */
226    virtual UBool hasSameRules(const TimeZone& other) const;
227
228    /**
229     * BasicTimeZone API.
230     * Gets the first time zone transition after the base time.
231     * @param base      The base time.
232     * @param inclusive Whether the base time is inclusive or not.
233     * @param result    Receives the first transition after the base time.
234     * @return  TRUE if the transition is found.
235     */
236    virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
237
238    /**
239     * BasicTimeZone API.
240     * Gets the most recent time zone transition before the base time.
241     * @param base      The base time.
242     * @param inclusive Whether the base time is inclusive or not.
243     * @param result    Receives the most recent transition before the base time.
244     * @return  TRUE if the transition is found.
245     */
246    virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/;
247
248    /**
249     * BasicTimeZone API.
250     * Returns the number of <code>TimeZoneRule</code>s which represents time transitions,
251     * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except
252     * <code>InitialTimeZoneRule</code>.  The return value range is 0 or any positive value.
253     * @param status    Receives error status code.
254     * @return The number of <code>TimeZoneRule</code>s representing time transitions.
255     */
256    virtual int32_t countTransitionRules(UErrorCode& status) /*const*/;
257
258    /**
259     * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code>
260     * which represent time transitions for this time zone.  On successful return,
261     * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and
262     * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code>
263     * instances up to the size specified by trscount.  The results are referencing the
264     * rule instance held by this time zone instance.  Therefore, after this time zone
265     * is destructed, they are no longer available.
266     * @param initial       Receives the initial timezone rule
267     * @param trsrules      Receives the timezone transition rules
268     * @param trscount      On input, specify the size of the array 'transitions' receiving
269     *                      the timezone transition rules.  On output, actual number of
270     *                      rules filled in the array will be set.
271     * @param status        Receives error status code.
272     * @draft ICU 3.8
273     */
274    virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
275        const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
276
277private:
278    /**
279     * Default constructor.  Creates a time zone with an empty ID and
280     * a fixed GMT offset of zero.
281     */
282    OlsonTimeZone();
283
284private:
285
286    void constructEmpty();
287
288    void getHistoricalOffset(UDate date, UBool local,
289        int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
290        int32_t& rawoff, int32_t& dstoff) const;
291
292    int32_t zoneOffset(int16_t index) const;
293    int32_t rawOffset(int16_t index) const;
294    int32_t dstOffset(int16_t index) const;
295
296    /**
297     * Number of transitions, 0..~370
298     */
299    int16_t transitionCount;
300
301    /**
302     * Number of types, 1..255
303     */
304    int16_t typeCount;
305
306    /**
307     * Time of each transition in seconds from 1970 epoch.
308     * Length is transitionCount int32_t's.
309     */
310    const int32_t *transitionTimes; // alias into res; do not delete
311
312    /**
313     * Offset from GMT in seconds for each type.
314     * Length is typeCount int32_t's.
315     */
316    const int32_t *typeOffsets; // alias into res; do not delete
317
318    /**
319     * Type description data, consisting of transitionCount uint8_t
320     * type indices (from 0..typeCount-1).
321     * Length is transitionCount int8_t's.
322     */
323    const uint8_t *typeData; // alias into res; do not delete
324
325    /**
326     * The last year for which the transitions data are to be used
327     * rather than the finalZone.  If there is no finalZone, then this
328     * is set to INT32_MAX.  NOTE: This corresponds to the year _before_
329     * the one indicated by finalMillis.
330     */
331    int32_t finalYear;
332
333    /**
334     * The millis for the start of the first year for which finalZone
335     * is to be used, or DBL_MAX if finalZone is 0.  NOTE: This is
336     * 0:00 GMT Jan 1, <finalYear + 1> (not <finalMillis>).
337     */
338    double finalMillis;
339
340    /**
341     * A SimpleTimeZone that governs the behavior for years > finalYear.
342     * If and only if finalYear == INT32_MAX then finalZone == 0.
343     */
344    SimpleTimeZone *finalZone; // owned, may be NULL
345
346    /* BasicTimeZone support */
347    void clearTransitionRules(void);
348    void deleteTransitionRules(void);
349    void initTransitionRules(UErrorCode& status);
350
351    InitialTimeZoneRule *initialRule;
352    TimeZoneTransition  *firstTZTransition;
353    int16_t             firstTZTransitionIdx;
354    TimeZoneTransition  *firstFinalTZTransition;
355    TimeArrayTimeZoneRule   **historicRules;
356    int16_t             historicRuleCount;
357    SimpleTimeZone      *finalZoneWithStartYear; // hack
358    UBool               transitionRulesInitialized;
359};
360
361inline int32_t
362OlsonTimeZone::zoneOffset(int16_t index) const {
363    index <<= 1;
364    return typeOffsets[index] + typeOffsets[index+1];
365}
366
367inline int32_t
368OlsonTimeZone::rawOffset(int16_t index) const {
369    return typeOffsets[(uint32_t)(index << 1)];
370}
371
372inline int32_t
373OlsonTimeZone::dstOffset(int16_t index) const {
374    return typeOffsets[(uint32_t)((index << 1) + 1)];
375}
376
377U_NAMESPACE_END
378
379#endif // !UCONFIG_NO_FORMATTING
380#endif // OLSONTZ_H
381
382//eof
383