Home | History | Annotate | Download | only in i18n
      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
    362 OlsonTimeZone::zoneOffset(int16_t index) const {
    363     index <<= 1;
    364     return typeOffsets[index] + typeOffsets[index+1];
    365 }
    366 
    367 inline int32_t
    368 OlsonTimeZone::rawOffset(int16_t index) const {
    369     return typeOffsets[(uint32_t)(index << 1)];
    370 }
    371 
    372 inline int32_t
    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