• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 struct UResourceBundle;
21 
22 U_NAMESPACE_BEGIN
23 
24 class 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  */
116 class 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 
277 private:
278     /**
279      * Default constructor.  Creates a time zone with an empty ID and
280      * a fixed GMT offset of zero.
281      */
282     OlsonTimeZone();
283 
284 private:
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 
361 inline int32_t
zoneOffset(int16_t index)362 OlsonTimeZone::zoneOffset(int16_t index) const {
363     index <<= 1;
364     return typeOffsets[index] + typeOffsets[index+1];
365 }
366 
367 inline int32_t
rawOffset(int16_t index)368 OlsonTimeZone::rawOffset(int16_t index) const {
369     return typeOffsets[(uint32_t)(index << 1)];
370 }
371 
372 inline int32_t
dstOffset(int16_t index)373 OlsonTimeZone::dstOffset(int16_t index) const {
374     return typeOffsets[(uint32_t)((index << 1) + 1)];
375 }
376 
377 U_NAMESPACE_END
378 
379 #endif // !UCONFIG_NO_FORMATTING
380 #endif // OLSONTZ_H
381 
382 //eof
383