1// © 2016 and later: Unicode, Inc. and others. 2// License & terms of use: http://www.unicode.org/copyright.html 3/* 4********************************************************************** 5* Copyright (c) 2003-2013, International Business Machines 6* Corporation and others. All Rights Reserved. 7********************************************************************** 8* Author: Alan Liu 9* Created: July 21 2003 10* Since: ICU 2.8 11********************************************************************** 12*/ 13#ifndef OLSONTZ_H 14#define OLSONTZ_H 15 16#include "unicode/utypes.h" 17 18#if !UCONFIG_NO_FORMATTING 19 20#include "unicode/basictz.h" 21#include "umutex.h" 22 23struct UResourceBundle; 24 25U_NAMESPACE_BEGIN 26 27class SimpleTimeZone; 28 29/** 30 * A time zone based on the Olson tz database. Olson time zones change 31 * behavior over time. The raw offset, rules, presence or absence of 32 * daylight savings time, and even the daylight savings amount can all 33 * vary. 34 * 35 * This class uses a resource bundle named "zoneinfo". Zoneinfo is a 36 * table containing different kinds of resources. In several places, 37 * zones are referred to using integers. A zone's integer is a number 38 * from 0..n-1, where n is the number of zones, with the zones sorted 39 * in lexicographic order. 40 * 41 * 1. Zones. These have keys corresponding to the Olson IDs, e.g., 42 * "Asia/Shanghai". Each resource describes the behavior of the given 43 * zone. Zones come in two different formats. 44 * 45 * a. Zone (table). A zone is a table resource contains several 46 * type of resources below: 47 * 48 * - typeOffsets:intvector (Required) 49 * 50 * Sets of UTC raw/dst offset pairs in seconds. Entries at 51 * 2n represents raw offset and 2n+1 represents dst offset 52 * paired with the raw offset at 2n. The very first pair represents 53 * the initial zone offset (before the first transition) always. 54 * 55 * - trans:intvector (Optional) 56 * 57 * List of transition times represented by 32bit seconds from the 58 * epoch (1970-01-01T00:00Z) in ascending order. 59 * 60 * - transPre32/transPost32:intvector (Optional) 61 * 62 * List of transition times before/after 32bit minimum seconds. 63 * Each time is represented by a pair of 32bit integer. 64 * 65 * - typeMap:bin (Optional) 66 * 67 * Array of bytes representing the mapping between each transition 68 * time (transPre32/trans/transPost32) and its corresponding offset 69 * data (typeOffsets). 70 * 71 * - finalRule:string (Optional) 72 * 73 * If a recurrent transition rule is applicable to a zone forever 74 * after the final transition time, finalRule represents the rule 75 * in Rules data. 76 * 77 * - finalRaw:int (Optional) 78 * 79 * When finalRule is available, finalRaw is required and specifies 80 * the raw (base) offset of the rule. 81 * 82 * - finalYear:int (Optional) 83 * 84 * When finalRule is available, finalYear is required and specifies 85 * the start year of the rule. 86 * 87 * - links:intvector (Optional) 88 * 89 * When this zone data is shared with other zones, links specifies 90 * all zones including the zone itself. Each zone is referenced by 91 * integer index. 92 * 93 * b. Link (int, length 1). A link zone is an int resource. The 94 * integer is the zone number of the target zone. The key of this 95 * resource is an alternate name for the target zone. This data 96 * is corresponding to Link data in the tz database. 97 * 98 * 99 * 2. Rules. These have keys corresponding to the Olson rule IDs, 100 * with an underscore prepended, e.g., "_EU". Each resource describes 101 * the behavior of the given rule using an intvector, containing the 102 * onset list, the cessation list, and the DST savings. The onset and 103 * cessation lists consist of the month, dowim, dow, time, and time 104 * mode. The end result is that the 11 integers describing the rule 105 * can be passed directly into the SimpleTimeZone 13-argument 106 * constructor (the other two arguments will be the raw offset, taken 107 * from the complex zone element 5, and the ID string, which is not 108 * used), with the times and the DST savings multiplied by 1000 to 109 * scale from seconds to milliseconds. 110 * 111 * 3. Regions. An array specifies mapping between zones and regions. 112 * Each item is either a 2-letter ISO country code or "001" 113 * (UN M.49 - World). This data is generated from "zone.tab" 114 * in the tz database. 115 */ 116class U_I18N_API 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 tzid the time zone ID 124 * @param ec input-output error code 125 */ 126 OlsonTimeZone(const UResourceBundle* top, 127 const UResourceBundle* res, 128 const UnicodeString& tzid, 129 UErrorCode& ec); 130 131 /** 132 * Copy constructor 133 */ 134 OlsonTimeZone(const OlsonTimeZone& other); 135 136 /** 137 * Destructor 138 */ 139 virtual ~OlsonTimeZone(); 140 141 /** 142 * Assignment operator 143 */ 144 OlsonTimeZone& operator=(const OlsonTimeZone& other); 145 146 /** 147 * Returns true if the two TimeZone objects are equal. 148 */ 149 virtual UBool operator==(const TimeZone& other) const; 150 151 /** 152 * TimeZone API. 153 */ 154 virtual TimeZone* clone() const; 155 156 /** 157 * TimeZone API. 158 */ 159 static UClassID U_EXPORT2 getStaticClassID(); 160 161 /** 162 * TimeZone API. 163 */ 164 virtual UClassID getDynamicClassID() const; 165 166 /** 167 * TimeZone API. Do not call this; prefer getOffset(UDate,...). 168 */ 169 virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, 170 int32_t day, uint8_t dayOfWeek, 171 int32_t millis, UErrorCode& ec) const; 172 173 /** 174 * TimeZone API. Do not call this; prefer getOffset(UDate,...). 175 */ 176 virtual int32_t getOffset(uint8_t era, int32_t year, int32_t month, 177 int32_t day, uint8_t dayOfWeek, 178 int32_t millis, int32_t monthLength, 179 UErrorCode& ec) const; 180 181 /** 182 * TimeZone API. 183 */ 184 virtual void getOffset(UDate date, UBool local, int32_t& rawOffset, 185 int32_t& dstOffset, UErrorCode& ec) const; 186 187 /** 188 * BasicTimeZone API. 189 */ 190 virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt, 191 int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) const; 192 193 /** 194 * TimeZone API. This method has no effect since objects of this 195 * class are quasi-immutable (the base class allows the ID to be 196 * changed). 197 */ 198 virtual void setRawOffset(int32_t offsetMillis); 199 200 /** 201 * TimeZone API. For a historical zone, the raw offset can change 202 * over time, so this API is not useful. In order to approximate 203 * expected behavior, this method returns the raw offset for the 204 * current moment in time. 205 */ 206 virtual int32_t getRawOffset() const; 207 208 /** 209 * TimeZone API. For a historical zone, whether DST is used or 210 * not varies over time. In order to approximate expected 211 * behavior, this method returns TRUE if DST is observed at any 212 * point in the current year. 213 */ 214 virtual UBool useDaylightTime() const; 215 216 /** 217 * TimeZone API. 218 */ 219 virtual UBool inDaylightTime(UDate date, UErrorCode& ec) const; 220 221 /** 222 * TimeZone API. 223 */ 224 virtual int32_t getDSTSavings() const; 225 226 /** 227 * TimeZone API. Also comare historic transitions. 228 */ 229 virtual UBool hasSameRules(const TimeZone& other) const; 230 231 /** 232 * BasicTimeZone API. 233 * Gets the first time zone transition after the base time. 234 * @param base The base time. 235 * @param inclusive Whether the base time is inclusive or not. 236 * @param result Receives the first transition after the base time. 237 * @return TRUE if the transition is found. 238 */ 239 virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const; 240 241 /** 242 * BasicTimeZone API. 243 * Gets the most recent time zone transition before the base time. 244 * @param base The base time. 245 * @param inclusive Whether the base time is inclusive or not. 246 * @param result Receives the most recent transition before the base time. 247 * @return TRUE if the transition is found. 248 */ 249 virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const; 250 251 /** 252 * BasicTimeZone API. 253 * Returns the number of <code>TimeZoneRule</code>s which represents time transitions, 254 * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except 255 * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value. 256 * @param status Receives error status code. 257 * @return The number of <code>TimeZoneRule</code>s representing time transitions. 258 */ 259 virtual int32_t countTransitionRules(UErrorCode& status) const; 260 261 /** 262 * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code> 263 * which represent time transitions for this time zone. On successful return, 264 * the argument initial points to non-NULL <code>InitialTimeZoneRule</code> and 265 * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code> 266 * instances up to the size specified by trscount. The results are referencing the 267 * rule instance held by this time zone instance. Therefore, after this time zone 268 * is destructed, they are no longer available. 269 * @param initial Receives the initial timezone rule 270 * @param trsrules Receives the timezone transition rules 271 * @param trscount On input, specify the size of the array 'transitions' receiving 272 * the timezone transition rules. On output, actual number of 273 * rules filled in the array will be set. 274 * @param status Receives error status code. 275 */ 276 virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial, 277 const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) const; 278 279 /** 280 * Internal API returning the canonical ID of this zone. 281 * This ID won't be affected by setID(). 282 */ 283 const UChar *getCanonicalID() const; 284 285private: 286 /** 287 * Default constructor. Creates a time zone with an empty ID and 288 * a fixed GMT offset of zero. 289 */ 290 OlsonTimeZone(); 291 292private: 293 294 void constructEmpty(); 295 296 void getHistoricalOffset(UDate date, UBool local, 297 int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt, 298 int32_t& rawoff, int32_t& dstoff) const; 299 300 int16_t transitionCount() const; 301 302 int64_t transitionTimeInSeconds(int16_t transIdx) const; 303 double transitionTime(int16_t transIdx) const; 304 305 /* 306 * Following 3 methods return an offset at the given transition time index. 307 * When the index is negative, return the initial offset. 308 */ 309 int32_t zoneOffsetAt(int16_t transIdx) const; 310 int32_t rawOffsetAt(int16_t transIdx) const; 311 int32_t dstOffsetAt(int16_t transIdx) const; 312 313 /* 314 * Following methods return the initial offset. 315 */ 316 int32_t initialRawOffset() const; 317 int32_t initialDstOffset() const; 318 319 /** 320 * Number of transitions in each time range 321 */ 322 int16_t transitionCountPre32; 323 int16_t transitionCount32; 324 int16_t transitionCountPost32; 325 326 /** 327 * Time of each transition in seconds from 1970 epoch before 32bit second range (<= 1900). 328 * Each transition in this range is represented by a pair of int32_t. 329 * Length is transitionCount int32_t's. NULL if no transitions in this range. 330 */ 331 const int32_t *transitionTimesPre32; // alias into res; do not delete 332 333 /** 334 * Time of each transition in seconds from 1970 epoch in 32bit second range. 335 * Length is transitionCount int32_t's. NULL if no transitions in this range. 336 */ 337 const int32_t *transitionTimes32; // alias into res; do not delete 338 339 /** 340 * Time of each transition in seconds from 1970 epoch after 32bit second range (>= 2038). 341 * Each transition in this range is represented by a pair of int32_t. 342 * Length is transitionCount int32_t's. NULL if no transitions in this range. 343 */ 344 const int32_t *transitionTimesPost32; // alias into res; do not delete 345 346 /** 347 * Number of types, 1..255 348 */ 349 int16_t typeCount; 350 351 /** 352 * Offset from GMT in seconds for each type. 353 * Length is typeCount int32_t's. At least one type (a pair of int32_t) 354 * is required. 355 */ 356 const int32_t *typeOffsets; // alias into res; do not delete 357 358 /** 359 * Type description data, consisting of transitionCount uint8_t 360 * type indices (from 0..typeCount-1). 361 * Length is transitionCount int16_t's. NULL if no transitions. 362 */ 363 const uint8_t *typeMapData; // alias into res; do not delete 364 365 /** 366 * A SimpleTimeZone that governs the behavior for date >= finalMillis. 367 */ 368 SimpleTimeZone *finalZone; // owned, may be NULL 369 370 /** 371 * For date >= finalMillis, the finalZone will be used. 372 */ 373 double finalStartMillis; 374 375 /** 376 * For year >= finalYear, the finalZone will be used. 377 */ 378 int32_t finalStartYear; 379 380 /* 381 * Canonical (CLDR) ID of this zone 382 */ 383 const UChar *canonicalID; 384 385 /* BasicTimeZone support */ 386 void clearTransitionRules(void); 387 void deleteTransitionRules(void); 388 void checkTransitionRules(UErrorCode& status) const; 389 390 public: // Internal, for access from plain C code 391 void initTransitionRules(UErrorCode& status); 392 private: 393 394 InitialTimeZoneRule *initialRule; 395 TimeZoneTransition *firstTZTransition; 396 int16_t firstTZTransitionIdx; 397 TimeZoneTransition *firstFinalTZTransition; 398 TimeArrayTimeZoneRule **historicRules; 399 int16_t historicRuleCount; 400 SimpleTimeZone *finalZoneWithStartYear; // hack 401 UInitOnce transitionRulesInitOnce; 402}; 403 404inline int16_t 405OlsonTimeZone::transitionCount() const { 406 return transitionCountPre32 + transitionCount32 + transitionCountPost32; 407} 408 409inline double 410OlsonTimeZone::transitionTime(int16_t transIdx) const { 411 return (double)transitionTimeInSeconds(transIdx) * U_MILLIS_PER_SECOND; 412} 413 414inline int32_t 415OlsonTimeZone::zoneOffsetAt(int16_t transIdx) const { 416 int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1; 417 return typeOffsets[typeIdx] + typeOffsets[typeIdx + 1]; 418} 419 420inline int32_t 421OlsonTimeZone::rawOffsetAt(int16_t transIdx) const { 422 int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1; 423 return typeOffsets[typeIdx]; 424} 425 426inline int32_t 427OlsonTimeZone::dstOffsetAt(int16_t transIdx) const { 428 int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1; 429 return typeOffsets[typeIdx + 1]; 430} 431 432inline int32_t 433OlsonTimeZone::initialRawOffset() const { 434 return typeOffsets[0]; 435} 436 437inline int32_t 438OlsonTimeZone::initialDstOffset() const { 439 return typeOffsets[1]; 440} 441 442inline const UChar* 443OlsonTimeZone::getCanonicalID() const { 444 return canonicalID; 445} 446 447 448U_NAMESPACE_END 449 450#endif // !UCONFIG_NO_FORMATTING 451#endif // OLSONTZ_H 452 453//eof 454