olsontz.h (15615B)
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 23 struct UResourceBundle; 24 25 U_NAMESPACE_BEGIN 26 27 class 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 */ 116 class U_I18N_API_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 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 U_I18N_API OlsonTimeZone& operator=(const OlsonTimeZone& other); 145 146 /** 147 * Returns true if the two TimeZone objects are equal. 148 */ 149 virtual bool operator==(const TimeZone& other) const override; 150 151 /** 152 * TimeZone API. 153 */ 154 virtual OlsonTimeZone* clone() const override; 155 156 /** 157 * TimeZone API. 158 */ 159 U_I18N_API static UClassID U_EXPORT2 getStaticClassID(); 160 161 /** 162 * TimeZone API. 163 */ 164 virtual UClassID getDynamicClassID() const override; 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 override; 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 override; 180 181 /** 182 * TimeZone API. 183 */ 184 virtual void getOffset(UDate date, UBool local, int32_t& rawOffset, 185 int32_t& dstOffset, UErrorCode& ec) const override; 186 187 /** 188 * BasicTimeZone API. 189 */ 190 virtual void getOffsetFromLocal( 191 UDate date, UTimeZoneLocalOption nonExistingTimeOpt, 192 UTimeZoneLocalOption duplicatedTimeOpt, 193 int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) const override; 194 195 /** 196 * TimeZone API. This method has no effect since objects of this 197 * class are quasi-immutable (the base class allows the ID to be 198 * changed). 199 */ 200 virtual void setRawOffset(int32_t offsetMillis) override; 201 202 /** 203 * TimeZone API. For a historical zone, the raw offset can change 204 * over time, so this API is not useful. In order to approximate 205 * expected behavior, this method returns the raw offset for the 206 * current moment in time. 207 */ 208 virtual int32_t getRawOffset() const override; 209 210 /** 211 * TimeZone API. For a historical zone, whether DST is used or 212 * not varies over time. In order to approximate expected 213 * behavior, this method returns true if DST is observed at any 214 * point in the current year. 215 */ 216 virtual UBool useDaylightTime() const override; 217 218 /** 219 * TimeZone API. 220 */ 221 virtual UBool inDaylightTime(UDate date, UErrorCode& ec) const override; 222 223 /** 224 * TimeZone API. 225 */ 226 virtual int32_t getDSTSavings() const override; 227 228 /** 229 * TimeZone API. Also comare historic transitions. 230 */ 231 virtual UBool hasSameRules(const TimeZone& other) const override; 232 233 /** 234 * BasicTimeZone API. 235 * Gets the first time zone transition after the base time. 236 * @param base The base time. 237 * @param inclusive Whether the base time is inclusive or not. 238 * @param result Receives the first transition after the base time. 239 * @return true if the transition is found. 240 */ 241 virtual UBool getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const override; 242 243 /** 244 * BasicTimeZone API. 245 * Gets the most recent time zone transition before the base time. 246 * @param base The base time. 247 * @param inclusive Whether the base time is inclusive or not. 248 * @param result Receives the most recent transition before the base time. 249 * @return true if the transition is found. 250 */ 251 virtual UBool getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const override; 252 253 /** 254 * BasicTimeZone API. 255 * Returns the number of <code>TimeZoneRule</code>s which represents time transitions, 256 * for this time zone, that is, all <code>TimeZoneRule</code>s for this time zone except 257 * <code>InitialTimeZoneRule</code>. The return value range is 0 or any positive value. 258 * @param status Receives error status code. 259 * @return The number of <code>TimeZoneRule</code>s representing time transitions. 260 */ 261 virtual int32_t countTransitionRules(UErrorCode& status) const override; 262 263 /** 264 * Gets the <code>InitialTimeZoneRule</code> and the set of <code>TimeZoneRule</code> 265 * which represent time transitions for this time zone. On successful return, 266 * the argument initial points to non-nullptr <code>InitialTimeZoneRule</code> and 267 * the array trsrules is filled with 0 or multiple <code>TimeZoneRule</code> 268 * instances up to the size specified by trscount. The results are referencing the 269 * rule instance held by this time zone instance. Therefore, after this time zone 270 * is destructed, they are no longer available. 271 * @param initial Receives the initial timezone rule 272 * @param trsrules Receives the timezone transition rules 273 * @param trscount On input, specify the size of the array 'transitions' receiving 274 * the timezone transition rules. On output, actual number of 275 * rules filled in the array will be set. 276 * @param status Receives error status code. 277 */ 278 virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial, 279 const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) const override; 280 281 /** 282 * Internal API returning the canonical ID of this zone. 283 * This ID won't be affected by setID(). 284 */ 285 const char16_t *getCanonicalID() const; 286 287 private: 288 /** 289 * Default constructor. Creates a time zone with an empty ID and 290 * a fixed GMT offset of zero. 291 */ 292 OlsonTimeZone(); 293 294 private: 295 296 void constructEmpty(); 297 298 void getHistoricalOffset(UDate date, UBool local, 299 int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt, 300 int32_t& rawoff, int32_t& dstoff) const; 301 302 int16_t transitionCount() const; 303 304 int64_t transitionTimeInSeconds(int16_t transIdx) const; 305 double transitionTime(int16_t transIdx) const; 306 307 /* 308 * Following 3 methods return an offset at the given transition time index. 309 * When the index is negative, return the initial offset. 310 */ 311 int32_t zoneOffsetAt(int16_t transIdx) const; 312 int32_t rawOffsetAt(int16_t transIdx) const; 313 int32_t dstOffsetAt(int16_t transIdx) const; 314 315 /* 316 * Following methods return the initial offset. 317 */ 318 int32_t initialRawOffset() const; 319 int32_t initialDstOffset() const; 320 321 /** 322 * Number of transitions in each time range 323 */ 324 int16_t transitionCountPre32; 325 int16_t transitionCount32; 326 int16_t transitionCountPost32; 327 328 /** 329 * Time of each transition in seconds from 1970 epoch before 32bit second range (<= 1900). 330 * Each transition in this range is represented by a pair of int32_t. 331 * Length is transitionCount int32_t's. nullptr if no transitions in this range. 332 */ 333 const int32_t *transitionTimesPre32; // alias into res; do not delete 334 335 /** 336 * Time of each transition in seconds from 1970 epoch in 32bit second range. 337 * Length is transitionCount int32_t's. nullptr if no transitions in this range. 338 */ 339 const int32_t *transitionTimes32; // alias into res; do not delete 340 341 /** 342 * Time of each transition in seconds from 1970 epoch after 32bit second range (>= 2038). 343 * Each transition in this range is represented by a pair of int32_t. 344 * Length is transitionCount int32_t's. nullptr if no transitions in this range. 345 */ 346 const int32_t *transitionTimesPost32; // alias into res; do not delete 347 348 /** 349 * Number of types, 1..255 350 */ 351 int16_t typeCount; 352 353 /** 354 * Offset from GMT in seconds for each type. 355 * Length is typeCount int32_t's. At least one type (a pair of int32_t) 356 * is required. 357 */ 358 const int32_t *typeOffsets; // alias into res; do not delete 359 360 /** 361 * Type description data, consisting of transitionCount uint8_t 362 * type indices (from 0..typeCount-1). 363 * Length is transitionCount int16_t's. nullptr if no transitions. 364 */ 365 const uint8_t *typeMapData; // alias into res; do not delete 366 367 /** 368 * A SimpleTimeZone that governs the behavior for date >= finalMillis. 369 */ 370 SimpleTimeZone *finalZone; // owned, may be nullptr 371 372 /** 373 * For date >= finalMillis, the finalZone will be used. 374 */ 375 double finalStartMillis; 376 377 /** 378 * For year >= finalYear, the finalZone will be used. 379 */ 380 int32_t finalStartYear; 381 382 /* 383 * Canonical (CLDR) ID of this zone 384 */ 385 const char16_t *canonicalID; 386 387 /* BasicTimeZone support */ 388 void clearTransitionRules(); 389 void deleteTransitionRules(); 390 void checkTransitionRules(UErrorCode& status) const; 391 392 public: // Internal, for access from plain C code 393 void initTransitionRules(UErrorCode& status); 394 private: 395 396 InitialTimeZoneRule *initialRule; 397 TimeZoneTransition *firstTZTransition; 398 int16_t firstTZTransitionIdx; 399 TimeZoneTransition *firstFinalTZTransition; 400 TimeArrayTimeZoneRule **historicRules; 401 int16_t historicRuleCount; 402 SimpleTimeZone *finalZoneWithStartYear; // hack 403 UInitOnce transitionRulesInitOnce {}; 404 }; 405 406 inline int16_t 407 OlsonTimeZone::transitionCount() const { 408 return transitionCountPre32 + transitionCount32 + transitionCountPost32; 409 } 410 411 inline double 412 OlsonTimeZone::transitionTime(int16_t transIdx) const { 413 return static_cast<double>(transitionTimeInSeconds(transIdx)) * U_MILLIS_PER_SECOND; 414 } 415 416 inline int32_t 417 OlsonTimeZone::zoneOffsetAt(int16_t transIdx) const { 418 int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1; 419 return typeOffsets[typeIdx] + typeOffsets[typeIdx + 1]; 420 } 421 422 inline int32_t 423 OlsonTimeZone::rawOffsetAt(int16_t transIdx) const { 424 int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1; 425 return typeOffsets[typeIdx]; 426 } 427 428 inline int32_t 429 OlsonTimeZone::dstOffsetAt(int16_t transIdx) const { 430 int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1; 431 return typeOffsets[typeIdx + 1]; 432 } 433 434 inline int32_t 435 OlsonTimeZone::initialRawOffset() const { 436 return typeOffsets[0]; 437 } 438 439 inline int32_t 440 OlsonTimeZone::initialDstOffset() const { 441 return typeOffsets[1]; 442 } 443 444 inline const char16_t* 445 OlsonTimeZone::getCanonicalID() const { 446 return canonicalID; 447 } 448 449 450 U_NAMESPACE_END 451 452 #endif // !UCONFIG_NO_FORMATTING 453 #endif // OLSONTZ_H 454 455 //eof