1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // This file implements the TimeZoneIf interface using the "zoneinfo"
16 // data provided by the IANA Time Zone Database (i.e., the only real game
17 // in town).
18 //
19 // TimeZoneInfo represents the history of UTC-offset changes within a time
20 // zone. Most changes are due to daylight-saving rules, but occasionally
21 // shifts are made to the time-zone's base offset. The database only attempts
22 // to be definitive for times since 1970, so be wary of local-time conversions
23 // before that. Also, rule and zone-boundary changes are made at the whim
24 // of governments, so the conversion of future times needs to be taken with
25 // a grain of salt.
26 //
27 // For more information see tzfile(5), http://www.iana.org/time-zones, or
28 // https://en.wikipedia.org/wiki/Zoneinfo.
29 //
30 // Note that we assume the proleptic Gregorian calendar and 60-second
31 // minutes throughout.
32
33 #include "time_zone_info.h"
34
35 #include <algorithm>
36 #include <cassert>
37 #include <chrono>
38 #include <cstdint>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <functional>
43 #include <memory>
44 #include <sstream>
45 #include <string>
46 #include <utility>
47
48 #include "absl/base/config.h"
49 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
50 #include "time_zone_fixed.h"
51 #include "time_zone_posix.h"
52
53 namespace absl {
54 ABSL_NAMESPACE_BEGIN
55 namespace time_internal {
56 namespace cctz {
57
58 namespace {
59
IsLeap(year_t year)60 inline bool IsLeap(year_t year) {
61 return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
62 }
63
64 // The number of days in non-leap and leap years respectively.
65 const std::int_least32_t kDaysPerYear[2] = {365, 366};
66
67 // The day offsets of the beginning of each (1-based) month in non-leap and
68 // leap years respectively (e.g., 335 days before December in a leap year).
69 const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
70 {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
71 {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
72 };
73
74 // We reject leap-second encoded zoneinfo and so assume 60-second minutes.
75 const std::int_least32_t kSecsPerDay = 24 * 60 * 60;
76
77 // 400-year chunks always have 146097 days (20871 weeks).
78 const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay;
79
80 // Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay.
81 const std::int_least32_t kSecsPerYear[2] = {
82 365 * kSecsPerDay,
83 366 * kSecsPerDay,
84 };
85
86 // Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
ToPosixWeekday(weekday wd)87 inline int ToPosixWeekday(weekday wd) {
88 switch (wd) {
89 case weekday::sunday:
90 return 0;
91 case weekday::monday:
92 return 1;
93 case weekday::tuesday:
94 return 2;
95 case weekday::wednesday:
96 return 3;
97 case weekday::thursday:
98 return 4;
99 case weekday::friday:
100 return 5;
101 case weekday::saturday:
102 return 6;
103 }
104 return 0; /*NOTREACHED*/
105 }
106
107 // Single-byte, unsigned numeric values are encoded directly.
Decode8(const char * cp)108 inline std::uint_fast8_t Decode8(const char* cp) {
109 return static_cast<std::uint_fast8_t>(*cp) & 0xff;
110 }
111
112 // Multi-byte, numeric values are encoded using a MSB first,
113 // twos-complement representation. These helpers decode, from
114 // the given address, 4-byte and 8-byte values respectively.
115 // Note: If int_fastXX_t == intXX_t and this machine is not
116 // twos complement, then there will be at least one input value
117 // we cannot represent.
Decode32(const char * cp)118 std::int_fast32_t Decode32(const char* cp) {
119 std::uint_fast32_t v = 0;
120 for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++);
121 const std::int_fast32_t s32max = 0x7fffffff;
122 const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
123 if (v <= s32maxU) return static_cast<std::int_fast32_t>(v);
124 return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1;
125 }
126
Decode64(const char * cp)127 std::int_fast64_t Decode64(const char* cp) {
128 std::uint_fast64_t v = 0;
129 for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++);
130 const std::int_fast64_t s64max = 0x7fffffffffffffff;
131 const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
132 if (v <= s64maxU) return static_cast<std::int_fast64_t>(v);
133 return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1;
134 }
135
136 // Generate a year-relative offset for a PosixTransition.
TransOffset(bool leap_year,int jan1_weekday,const PosixTransition & pt)137 std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
138 const PosixTransition& pt) {
139 std::int_fast64_t days = 0;
140 switch (pt.date.fmt) {
141 case PosixTransition::J: {
142 days = pt.date.j.day;
143 if (!leap_year || days < kMonthOffsets[1][3]) days -= 1;
144 break;
145 }
146 case PosixTransition::N: {
147 days = pt.date.n.day;
148 break;
149 }
150 case PosixTransition::M: {
151 const bool last_week = (pt.date.m.week == 5);
152 days = kMonthOffsets[leap_year][pt.date.m.month + last_week];
153 const std::int_fast64_t weekday = (jan1_weekday + days) % 7;
154 if (last_week) {
155 days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1;
156 } else {
157 days += (pt.date.m.weekday + 7 - weekday) % 7;
158 days += (pt.date.m.week - 1) * 7;
159 }
160 break;
161 }
162 }
163 return (days * kSecsPerDay) + pt.time.offset;
164 }
165
MakeUnique(const time_point<seconds> & tp)166 inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) {
167 time_zone::civil_lookup cl;
168 cl.kind = time_zone::civil_lookup::UNIQUE;
169 cl.pre = cl.trans = cl.post = tp;
170 return cl;
171 }
172
MakeUnique(std::int_fast64_t unix_time)173 inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) {
174 return MakeUnique(FromUnixSeconds(unix_time));
175 }
176
MakeSkipped(const Transition & tr,const civil_second & cs)177 inline time_zone::civil_lookup MakeSkipped(const Transition& tr,
178 const civil_second& cs) {
179 time_zone::civil_lookup cl;
180 cl.kind = time_zone::civil_lookup::SKIPPED;
181 cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec));
182 cl.trans = FromUnixSeconds(tr.unix_time);
183 cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs));
184 return cl;
185 }
186
MakeRepeated(const Transition & tr,const civil_second & cs)187 inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
188 const civil_second& cs) {
189 time_zone::civil_lookup cl;
190 cl.kind = time_zone::civil_lookup::REPEATED;
191 cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs));
192 cl.trans = FromUnixSeconds(tr.unix_time);
193 cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec));
194 return cl;
195 }
196
YearShift(const civil_second & cs,year_t shift)197 inline civil_second YearShift(const civil_second& cs, year_t shift) {
198 return civil_second(cs.year() + shift, cs.month(), cs.day(), cs.hour(),
199 cs.minute(), cs.second());
200 }
201
202 } // namespace
203
204 // What (no leap-seconds) UTC+seconds zoneinfo would look like.
ResetToBuiltinUTC(const seconds & offset)205 bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
206 transition_types_.resize(1);
207 TransitionType& tt(transition_types_.back());
208 tt.utc_offset = static_cast<std::int_least32_t>(offset.count());
209 tt.is_dst = false;
210 tt.abbr_index = 0;
211
212 // We temporarily add some redundant, contemporary (2015 through 2025)
213 // transitions for performance reasons. See TimeZoneInfo::LocalTime().
214 // TODO: Fix the performance issue and remove the extra transitions.
215 transitions_.clear();
216 transitions_.reserve(12);
217 for (const std::int_fast64_t unix_time : {
218 -(1LL << 59), // a "first half" transition
219 1420070400LL, // 2015-01-01T00:00:00+00:00
220 1451606400LL, // 2016-01-01T00:00:00+00:00
221 1483228800LL, // 2017-01-01T00:00:00+00:00
222 1514764800LL, // 2018-01-01T00:00:00+00:00
223 1546300800LL, // 2019-01-01T00:00:00+00:00
224 1577836800LL, // 2020-01-01T00:00:00+00:00
225 1609459200LL, // 2021-01-01T00:00:00+00:00
226 1640995200LL, // 2022-01-01T00:00:00+00:00
227 1672531200LL, // 2023-01-01T00:00:00+00:00
228 1704067200LL, // 2024-01-01T00:00:00+00:00
229 1735689600LL, // 2025-01-01T00:00:00+00:00
230 }) {
231 Transition& tr(*transitions_.emplace(transitions_.end()));
232 tr.unix_time = unix_time;
233 tr.type_index = 0;
234 tr.civil_sec = LocalTime(tr.unix_time, tt).cs;
235 tr.prev_civil_sec = tr.civil_sec - 1;
236 }
237
238 default_transition_type_ = 0;
239 abbreviations_ = FixedOffsetToAbbr(offset);
240 abbreviations_.append(1, '\0');
241 future_spec_.clear(); // never needed for a fixed-offset zone
242 extended_ = false;
243
244 tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
245 tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
246
247 transitions_.shrink_to_fit();
248 return true;
249 }
250
251 // Builds the in-memory header using the raw bytes from the file.
Build(const tzhead & tzh)252 bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
253 std::int_fast32_t v;
254 if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false;
255 timecnt = static_cast<std::size_t>(v);
256 if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false;
257 typecnt = static_cast<std::size_t>(v);
258 if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false;
259 charcnt = static_cast<std::size_t>(v);
260 if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false;
261 leapcnt = static_cast<std::size_t>(v);
262 if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
263 ttisstdcnt = static_cast<std::size_t>(v);
264 if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false;
265 ttisutcnt = static_cast<std::size_t>(v);
266 return true;
267 }
268
269 // How many bytes of data are associated with this header. The result
270 // depends upon whether this is a section with 4-byte or 8-byte times.
DataLength(std::size_t time_len) const271 std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
272 std::size_t len = 0;
273 len += (time_len + 1) * timecnt; // unix_time + type_index
274 len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index
275 len += 1 * charcnt; // abbreviations
276 len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC
277 len += 1 * ttisstdcnt; // UTC/local indicators
278 len += 1 * ttisutcnt; // standard/wall indicators
279 return len;
280 }
281
282 // zic(8) can generate no-op transitions when a zone changes rules at an
283 // instant when there is actually no discontinuity. So we check whether
284 // two transitions have equivalent types (same offset/is_dst/abbr).
EquivTransitions(std::uint_fast8_t tt1_index,std::uint_fast8_t tt2_index) const285 bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
286 std::uint_fast8_t tt2_index) const {
287 if (tt1_index == tt2_index) return true;
288 const TransitionType& tt1(transition_types_[tt1_index]);
289 const TransitionType& tt2(transition_types_[tt2_index]);
290 if (tt1.utc_offset != tt2.utc_offset) return false;
291 if (tt1.is_dst != tt2.is_dst) return false;
292 if (tt1.abbr_index != tt2.abbr_index) return false;
293 return true;
294 }
295
296 // Find/make a transition type with these attributes.
GetTransitionType(std::int_fast32_t utc_offset,bool is_dst,const std::string & abbr,std::uint_least8_t * index)297 bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
298 const std::string& abbr,
299 std::uint_least8_t* index) {
300 std::size_t type_index = 0;
301 std::size_t abbr_index = abbreviations_.size();
302 for (; type_index != transition_types_.size(); ++type_index) {
303 const TransitionType& tt(transition_types_[type_index]);
304 const char* tt_abbr = &abbreviations_[tt.abbr_index];
305 if (tt_abbr == abbr) abbr_index = tt.abbr_index;
306 if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
307 if (abbr_index == tt.abbr_index) break; // reuse
308 }
309 }
310 if (type_index > 255 || abbr_index > 255) {
311 // No index space (8 bits) available for a new type or abbreviation.
312 return false;
313 }
314 if (type_index == transition_types_.size()) {
315 TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
316 tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
317 tt.is_dst = is_dst;
318 if (abbr_index == abbreviations_.size()) {
319 abbreviations_.append(abbr);
320 abbreviations_.append(1, '\0');
321 }
322 tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
323 }
324 *index = static_cast<std::uint_least8_t>(type_index);
325 return true;
326 }
327
328 // Use the POSIX-TZ-environment-variable-style string to handle times
329 // in years after the last transition stored in the zoneinfo data.
ExtendTransitions()330 bool TimeZoneInfo::ExtendTransitions() {
331 extended_ = false;
332 if (future_spec_.empty()) return true; // last transition prevails
333
334 PosixTimeZone posix;
335 if (!ParsePosixSpec(future_spec_, &posix)) return false;
336
337 // Find transition type for the future std specification.
338 std::uint_least8_t std_ti;
339 if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
340 return false;
341
342 if (posix.dst_abbr.empty()) { // std only
343 // The future specification should match the last transition, and
344 // that means that handling the future will fall out naturally.
345 return EquivTransitions(transitions_.back().type_index, std_ti);
346 }
347
348 // Find transition type for the future dst specification.
349 std::uint_least8_t dst_ti;
350 if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
351 return false;
352
353 // Extend the transitions for an additional 400 years using the
354 // future specification. Years beyond those can be handled by
355 // mapping back to a cycle-equivalent year within that range.
356 // We may need two additional transitions for the current year.
357 transitions_.reserve(transitions_.size() + 400 * 2 + 2);
358 extended_ = true;
359
360 const Transition& last(transitions_.back());
361 const std::int_fast64_t last_time = last.unix_time;
362 const TransitionType& last_tt(transition_types_[last.type_index]);
363 last_year_ = LocalTime(last_time, last_tt).cs.year();
364 bool leap_year = IsLeap(last_year_);
365 const civil_second jan1(last_year_);
366 std::int_fast64_t jan1_time = jan1 - civil_second();
367 int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
368
369 Transition dst = {0, dst_ti, civil_second(), civil_second()};
370 Transition std = {0, std_ti, civil_second(), civil_second()};
371 for (const year_t limit = last_year_ + 400;; ++last_year_) {
372 auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
373 auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
374 dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
375 std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
376 const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
377 const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
378 if (last_time < tb->unix_time) {
379 if (last_time < ta->unix_time) transitions_.push_back(*ta);
380 transitions_.push_back(*tb);
381 }
382 if (last_year_ == limit) break;
383 jan1_time += kSecsPerYear[leap_year];
384 jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
385 leap_year = !leap_year && IsLeap(last_year_ + 1);
386 }
387
388 return true;
389 }
390
Load(ZoneInfoSource * zip)391 bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
392 // Read and validate the header.
393 tzhead tzh;
394 if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
395 if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
396 return false;
397 Header hdr;
398 if (!hdr.Build(tzh)) return false;
399 std::size_t time_len = 4;
400 if (tzh.tzh_version[0] != '\0') {
401 // Skip the 4-byte data.
402 if (zip->Skip(hdr.DataLength(time_len)) != 0) return false;
403 // Read and validate the header for the 8-byte data.
404 if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
405 if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
406 return false;
407 if (tzh.tzh_version[0] == '\0') return false;
408 if (!hdr.Build(tzh)) return false;
409 time_len = 8;
410 }
411 if (hdr.typecnt == 0) return false;
412 if (hdr.leapcnt != 0) {
413 // This code assumes 60-second minutes so we do not want
414 // the leap-second encoded zoneinfo. We could reverse the
415 // compensation, but the "right" encoding is rarely used
416 // so currently we simply reject such data.
417 return false;
418 }
419 if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false;
420 if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false;
421
422 // Read the data into a local buffer.
423 std::size_t len = hdr.DataLength(time_len);
424 std::vector<char> tbuf(len);
425 if (zip->Read(tbuf.data(), len) != len) return false;
426 const char* bp = tbuf.data();
427
428 // Decode and validate the transitions.
429 transitions_.reserve(hdr.timecnt + 2);
430 transitions_.resize(hdr.timecnt);
431 for (std::size_t i = 0; i != hdr.timecnt; ++i) {
432 transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
433 bp += time_len;
434 if (i != 0) {
435 // Check that the transitions are ordered by time (as zic guarantees).
436 if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
437 return false; // out of order
438 }
439 }
440 bool seen_type_0 = false;
441 for (std::size_t i = 0; i != hdr.timecnt; ++i) {
442 transitions_[i].type_index = Decode8(bp++);
443 if (transitions_[i].type_index >= hdr.typecnt) return false;
444 if (transitions_[i].type_index == 0) seen_type_0 = true;
445 }
446
447 // Decode and validate the transition types.
448 transition_types_.reserve(hdr.typecnt + 2);
449 transition_types_.resize(hdr.typecnt);
450 for (std::size_t i = 0; i != hdr.typecnt; ++i) {
451 transition_types_[i].utc_offset =
452 static_cast<std::int_least32_t>(Decode32(bp));
453 if (transition_types_[i].utc_offset >= kSecsPerDay ||
454 transition_types_[i].utc_offset <= -kSecsPerDay)
455 return false;
456 bp += 4;
457 transition_types_[i].is_dst = (Decode8(bp++) != 0);
458 transition_types_[i].abbr_index = Decode8(bp++);
459 if (transition_types_[i].abbr_index >= hdr.charcnt) return false;
460 }
461
462 // Determine the before-first-transition type.
463 default_transition_type_ = 0;
464 if (seen_type_0 && hdr.timecnt != 0) {
465 std::uint_fast8_t index = 0;
466 if (transition_types_[0].is_dst) {
467 index = transitions_[0].type_index;
468 while (index != 0 && transition_types_[index].is_dst) --index;
469 }
470 while (index != hdr.typecnt && transition_types_[index].is_dst) ++index;
471 if (index != hdr.typecnt) default_transition_type_ = index;
472 }
473
474 // Copy all the abbreviations.
475 abbreviations_.reserve(hdr.charcnt + 10);
476 abbreviations_.assign(bp, hdr.charcnt);
477 bp += hdr.charcnt;
478
479 // Skip the unused portions. We've already dispensed with leap-second
480 // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when
481 // interpreting a POSIX spec that does not include start/end rules, and
482 // that isn't the case here (see "zic -p").
483 bp += (8 + 4) * hdr.leapcnt; // leap-time + TAI-UTC
484 bp += 1 * hdr.ttisstdcnt; // UTC/local indicators
485 bp += 1 * hdr.ttisutcnt; // standard/wall indicators
486 assert(bp == tbuf.data() + tbuf.size());
487
488 future_spec_.clear();
489 if (tzh.tzh_version[0] != '\0') {
490 // Snarf up the NL-enclosed future POSIX spec. Note
491 // that version '3' files utilize an extended format.
492 auto get_char = [](ZoneInfoSource* azip) -> int {
493 unsigned char ch; // all non-EOF results are positive
494 return (azip->Read(&ch, 1) == 1) ? ch : EOF;
495 };
496 if (get_char(zip) != '\n') return false;
497 for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
498 if (c == EOF) return false;
499 future_spec_.push_back(static_cast<char>(c));
500 }
501 }
502
503 // We don't check for EOF so that we're forwards compatible.
504
505 // If we did not find version information during the standard loading
506 // process (as of tzh_version '3' that is unsupported), then ask the
507 // ZoneInfoSource for any out-of-bound version string it may be privy to.
508 if (version_.empty()) {
509 version_ = zip->Version();
510 }
511
512 // Trim redundant transitions. zic may have added these to work around
513 // differences between the glibc and reference implementations (see
514 // zic.c:dontmerge) and the Qt library (see zic.c:WORK_AROUND_QTBUG_53071).
515 // For us, they just get in the way when we do future_spec_ extension.
516 while (hdr.timecnt > 1) {
517 if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index,
518 transitions_[hdr.timecnt - 2].type_index)) {
519 break;
520 }
521 hdr.timecnt -= 1;
522 }
523 transitions_.resize(hdr.timecnt);
524
525 // Ensure that there is always a transition in the first half of the
526 // time line (the second half is handled below) so that the signed
527 // difference between a civil_second and the civil_second of its
528 // previous transition is always representable, without overflow.
529 if (transitions_.empty() || transitions_.front().unix_time >= 0) {
530 Transition& tr(*transitions_.emplace(transitions_.begin()));
531 tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
532 tr.type_index = default_transition_type_;
533 }
534
535 // Extend the transitions using the future specification.
536 if (!ExtendTransitions()) return false;
537
538 // Ensure that there is always a transition in the second half of the
539 // time line (the first half is handled above) so that the signed
540 // difference between a civil_second and the civil_second of its
541 // previous transition is always representable, without overflow.
542 const Transition& last(transitions_.back());
543 if (last.unix_time < 0) {
544 const std::uint_fast8_t type_index = last.type_index;
545 Transition& tr(*transitions_.emplace(transitions_.end()));
546 tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
547 tr.type_index = type_index;
548 }
549
550 // Compute the local civil time for each transition and the preceding
551 // second. These will be used for reverse conversions in MakeTime().
552 const TransitionType* ttp = &transition_types_[default_transition_type_];
553 for (std::size_t i = 0; i != transitions_.size(); ++i) {
554 Transition& tr(transitions_[i]);
555 tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1;
556 ttp = &transition_types_[tr.type_index];
557 tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs;
558 if (i != 0) {
559 // Check that the transitions are ordered by civil time. Essentially
560 // this means that an offset change cannot cross another such change.
561 // No one does this in practice, and we depend on it in MakeTime().
562 if (!Transition::ByCivilTime()(transitions_[i - 1], tr))
563 return false; // out of order
564 }
565 }
566
567 // Compute the maximum/minimum civil times that can be converted to a
568 // time_point<seconds> for each of the zone's transition types.
569 for (auto& tt : transition_types_) {
570 tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
571 tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
572 }
573
574 transitions_.shrink_to_fit();
575 return true;
576 }
577
578 namespace {
579
580 using FilePtr = std::unique_ptr<FILE, int (*)(FILE*)>;
581
582 // fopen(3) adaptor.
FOpen(const char * path,const char * mode)583 inline FilePtr FOpen(const char* path, const char* mode) {
584 #if defined(_MSC_VER)
585 FILE* fp;
586 if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
587 return FilePtr(fp, fclose);
588 #else
589 // TODO: Enable the close-on-exec flag.
590 return FilePtr(fopen(path, mode), fclose);
591 #endif
592 }
593
594 // A stdio(3)-backed implementation of ZoneInfoSource.
595 class FileZoneInfoSource : public ZoneInfoSource {
596 public:
597 static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
598
Read(void * ptr,std::size_t size)599 std::size_t Read(void* ptr, std::size_t size) override {
600 size = std::min(size, len_);
601 std::size_t nread = fread(ptr, 1, size, fp_.get());
602 len_ -= nread;
603 return nread;
604 }
Skip(std::size_t offset)605 int Skip(std::size_t offset) override {
606 offset = std::min(offset, len_);
607 int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR);
608 if (rc == 0) len_ -= offset;
609 return rc;
610 }
Version() const611 std::string Version() const override {
612 // TODO: It would nice if the zoneinfo data included the tzdb version.
613 return std::string();
614 }
615
616 protected:
FileZoneInfoSource(FilePtr fp,std::size_t len=std::numeric_limits<std::size_t>::max ())617 explicit FileZoneInfoSource(
618 FilePtr fp, std::size_t len = std::numeric_limits<std::size_t>::max())
619 : fp_(std::move(fp)), len_(len) {}
620
621 private:
622 FilePtr fp_;
623 std::size_t len_;
624 };
625
Open(const std::string & name)626 std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
627 const std::string& name) {
628 // Use of the "file:" prefix is intended for testing purposes only.
629 const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
630
631 // Map the time-zone name to a path name.
632 std::string path;
633 if (pos == name.size() || name[pos] != '/') {
634 const char* tzdir = "/usr/share/zoneinfo";
635 char* tzdir_env = nullptr;
636 #if defined(_MSC_VER)
637 _dupenv_s(&tzdir_env, nullptr, "TZDIR");
638 #else
639 tzdir_env = std::getenv("TZDIR");
640 #endif
641 if (tzdir_env && *tzdir_env) tzdir = tzdir_env;
642 path += tzdir;
643 path += '/';
644 #if defined(_MSC_VER)
645 free(tzdir_env);
646 #endif
647 }
648 path.append(name, pos, std::string::npos);
649
650 // Open the zoneinfo file.
651 auto fp = FOpen(path.c_str(), "rb");
652 if (fp.get() == nullptr) return nullptr;
653 return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(std::move(fp)));
654 }
655
656 class AndroidZoneInfoSource : public FileZoneInfoSource {
657 public:
658 static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
Version() const659 std::string Version() const override { return version_; }
660
661 private:
AndroidZoneInfoSource(FilePtr fp,std::size_t len,std::string version)662 explicit AndroidZoneInfoSource(FilePtr fp, std::size_t len,
663 std::string version)
664 : FileZoneInfoSource(std::move(fp), len), version_(std::move(version)) {}
665 std::string version_;
666 };
667
Open(const std::string & name)668 std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
669 const std::string& name) {
670 // Use of the "file:" prefix is intended for testing purposes only.
671 const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
672
673 // See Android's libc/tzcode/bionic.cpp for additional information.
674 for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
675 "/system/usr/share/zoneinfo/tzdata"}) {
676 auto fp = FOpen(tzdata, "rb");
677 if (fp.get() == nullptr) continue;
678
679 char hbuf[24]; // covers header.zonetab_offset too
680 if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
681 if (strncmp(hbuf, "tzdata", 6) != 0) continue;
682 const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
683 const std::int_fast32_t index_offset = Decode32(hbuf + 12);
684 const std::int_fast32_t data_offset = Decode32(hbuf + 16);
685 if (index_offset < 0 || data_offset < index_offset) continue;
686 if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
687 continue;
688
689 char ebuf[52]; // covers entry.unused too
690 const std::size_t index_size =
691 static_cast<std::size_t>(data_offset - index_offset);
692 const std::size_t zonecnt = index_size / sizeof(ebuf);
693 if (zonecnt * sizeof(ebuf) != index_size) continue;
694 for (std::size_t i = 0; i != zonecnt; ++i) {
695 if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
696 const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
697 const std::int_fast32_t length = Decode32(ebuf + 44);
698 if (start < 0 || length < 0) break;
699 ebuf[40] = '\0'; // ensure zone name is NUL terminated
700 if (strcmp(name.c_str() + pos, ebuf) == 0) {
701 if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
702 return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
703 std::move(fp), static_cast<std::size_t>(length), vers));
704 }
705 }
706 }
707
708 return nullptr;
709 }
710
711 } // namespace
712
Load(const std::string & name)713 bool TimeZoneInfo::Load(const std::string& name) {
714 // We can ensure that the loading of UTC or any other fixed-offset
715 // zone never fails because the simple, fixed-offset state can be
716 // internally generated. Note that this depends on our choice to not
717 // accept leap-second encoded ("right") zoneinfo.
718 auto offset = seconds::zero();
719 if (FixedOffsetFromName(name, &offset)) {
720 return ResetToBuiltinUTC(offset);
721 }
722
723 // Find and use a ZoneInfoSource to load the named zone.
724 auto zip = cctz_extension::zone_info_source_factory(
725 name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
726 if (auto z = FileZoneInfoSource::Open(n)) return z;
727 if (auto z = AndroidZoneInfoSource::Open(n)) return z;
728 return nullptr;
729 });
730 return zip != nullptr && Load(zip.get());
731 }
732
733 // BreakTime() translation for a particular transition type.
LocalTime(std::int_fast64_t unix_time,const TransitionType & tt) const734 time_zone::absolute_lookup TimeZoneInfo::LocalTime(
735 std::int_fast64_t unix_time, const TransitionType& tt) const {
736 // A civil time in "+offset" looks like (time+offset) in UTC.
737 // Note: We perform two additions in the civil_second domain to
738 // sidestep the chance of overflow in (unix_time + tt.utc_offset).
739 return {(civil_second() + unix_time) + tt.utc_offset, tt.utc_offset,
740 tt.is_dst, &abbreviations_[tt.abbr_index]};
741 }
742
743 // BreakTime() translation for a particular transition.
LocalTime(std::int_fast64_t unix_time,const Transition & tr) const744 time_zone::absolute_lookup TimeZoneInfo::LocalTime(std::int_fast64_t unix_time,
745 const Transition& tr) const {
746 const TransitionType& tt = transition_types_[tr.type_index];
747 // Note: (unix_time - tr.unix_time) will never overflow as we
748 // have ensured that there is always a "nearby" transition.
749 return {tr.civil_sec + (unix_time - tr.unix_time), // TODO: Optimize.
750 tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
751 }
752
753 // MakeTime() translation with a conversion-preserving +N * 400-year shift.
TimeLocal(const civil_second & cs,year_t c4_shift) const754 time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
755 year_t c4_shift) const {
756 assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_);
757 time_zone::civil_lookup cl = MakeTime(cs);
758 if (c4_shift > seconds::max().count() / kSecsPer400Years) {
759 cl.pre = cl.trans = cl.post = time_point<seconds>::max();
760 } else {
761 const auto offset = seconds(c4_shift * kSecsPer400Years);
762 const auto limit = time_point<seconds>::max() - offset;
763 for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) {
764 if (*tp > limit) {
765 *tp = time_point<seconds>::max();
766 } else {
767 *tp += offset;
768 }
769 }
770 }
771 return cl;
772 }
773
BreakTime(const time_point<seconds> & tp) const774 time_zone::absolute_lookup TimeZoneInfo::BreakTime(
775 const time_point<seconds>& tp) const {
776 std::int_fast64_t unix_time = ToUnixSeconds(tp);
777 const std::size_t timecnt = transitions_.size();
778 assert(timecnt != 0); // We always add a transition.
779
780 if (unix_time < transitions_[0].unix_time) {
781 return LocalTime(unix_time, transition_types_[default_transition_type_]);
782 }
783 if (unix_time >= transitions_[timecnt - 1].unix_time) {
784 // After the last transition. If we extended the transitions using
785 // future_spec_, shift back to a supported year using the 400-year
786 // cycle of calendaric equivalence and then compensate accordingly.
787 if (extended_) {
788 const std::int_fast64_t diff =
789 unix_time - transitions_[timecnt - 1].unix_time;
790 const year_t shift = diff / kSecsPer400Years + 1;
791 const auto d = seconds(shift * kSecsPer400Years);
792 time_zone::absolute_lookup al = BreakTime(tp - d);
793 al.cs = YearShift(al.cs, shift * 400);
794 return al;
795 }
796 return LocalTime(unix_time, transitions_[timecnt - 1]);
797 }
798
799 const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
800 if (0 < hint && hint < timecnt) {
801 if (transitions_[hint - 1].unix_time <= unix_time) {
802 if (unix_time < transitions_[hint].unix_time) {
803 return LocalTime(unix_time, transitions_[hint - 1]);
804 }
805 }
806 }
807
808 const Transition target = {unix_time, 0, civil_second(), civil_second()};
809 const Transition* begin = &transitions_[0];
810 const Transition* tr = std::upper_bound(begin, begin + timecnt, target,
811 Transition::ByUnixTime());
812 local_time_hint_.store(static_cast<std::size_t>(tr - begin),
813 std::memory_order_relaxed);
814 return LocalTime(unix_time, *--tr);
815 }
816
MakeTime(const civil_second & cs) const817 time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
818 const std::size_t timecnt = transitions_.size();
819 assert(timecnt != 0); // We always add a transition.
820
821 // Find the first transition after our target civil time.
822 const Transition* tr = nullptr;
823 const Transition* begin = &transitions_[0];
824 const Transition* end = begin + timecnt;
825 if (cs < begin->civil_sec) {
826 tr = begin;
827 } else if (cs >= transitions_[timecnt - 1].civil_sec) {
828 tr = end;
829 } else {
830 const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed);
831 if (0 < hint && hint < timecnt) {
832 if (transitions_[hint - 1].civil_sec <= cs) {
833 if (cs < transitions_[hint].civil_sec) {
834 tr = begin + hint;
835 }
836 }
837 }
838 if (tr == nullptr) {
839 const Transition target = {0, 0, cs, civil_second()};
840 tr = std::upper_bound(begin, end, target, Transition::ByCivilTime());
841 time_local_hint_.store(static_cast<std::size_t>(tr - begin),
842 std::memory_order_relaxed);
843 }
844 }
845
846 if (tr == begin) {
847 if (tr->prev_civil_sec >= cs) {
848 // Before first transition, so use the default offset.
849 const TransitionType& tt(transition_types_[default_transition_type_]);
850 if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min());
851 return MakeUnique(cs - (civil_second() + tt.utc_offset));
852 }
853 // tr->prev_civil_sec < cs < tr->civil_sec
854 return MakeSkipped(*tr, cs);
855 }
856
857 if (tr == end) {
858 if (cs > (--tr)->prev_civil_sec) {
859 // After the last transition. If we extended the transitions using
860 // future_spec_, shift back to a supported year using the 400-year
861 // cycle of calendaric equivalence and then compensate accordingly.
862 if (extended_ && cs.year() > last_year_) {
863 const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
864 return TimeLocal(YearShift(cs, shift * -400), shift);
865 }
866 const TransitionType& tt(transition_types_[tr->type_index]);
867 if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
868 return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
869 }
870 // tr->civil_sec <= cs <= tr->prev_civil_sec
871 return MakeRepeated(*tr, cs);
872 }
873
874 if (tr->prev_civil_sec < cs) {
875 // tr->prev_civil_sec < cs < tr->civil_sec
876 return MakeSkipped(*tr, cs);
877 }
878
879 if (cs <= (--tr)->prev_civil_sec) {
880 // tr->civil_sec <= cs <= tr->prev_civil_sec
881 return MakeRepeated(*tr, cs);
882 }
883
884 // In between transitions.
885 return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
886 }
887
Version() const888 std::string TimeZoneInfo::Version() const { return version_; }
889
Description() const890 std::string TimeZoneInfo::Description() const {
891 std::ostringstream oss;
892 oss << "#trans=" << transitions_.size();
893 oss << " #types=" << transition_types_.size();
894 oss << " spec='" << future_spec_ << "'";
895 return oss.str();
896 }
897
NextTransition(const time_point<seconds> & tp,time_zone::civil_transition * trans) const898 bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
899 time_zone::civil_transition* trans) const {
900 if (transitions_.empty()) return false;
901 const Transition* begin = &transitions_[0];
902 const Transition* end = begin + transitions_.size();
903 if (begin->unix_time <= -(1LL << 59)) {
904 // Do not report the BIG_BANG found in some zoneinfo data as it is
905 // really a sentinel, not a transition. See pre-2018f tz/zic.c.
906 ++begin;
907 }
908 std::int_fast64_t unix_time = ToUnixSeconds(tp);
909 const Transition target = {unix_time, 0, civil_second(), civil_second()};
910 const Transition* tr =
911 std::upper_bound(begin, end, target, Transition::ByUnixTime());
912 for (; tr != end; ++tr) { // skip no-op transitions
913 std::uint_fast8_t prev_type_index =
914 (tr == begin) ? default_transition_type_ : tr[-1].type_index;
915 if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
916 }
917 // When tr == end we return false, ignoring future_spec_.
918 if (tr == end) return false;
919 trans->from = tr->prev_civil_sec + 1;
920 trans->to = tr->civil_sec;
921 return true;
922 }
923
PrevTransition(const time_point<seconds> & tp,time_zone::civil_transition * trans) const924 bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
925 time_zone::civil_transition* trans) const {
926 if (transitions_.empty()) return false;
927 const Transition* begin = &transitions_[0];
928 const Transition* end = begin + transitions_.size();
929 if (begin->unix_time <= -(1LL << 59)) {
930 // Do not report the BIG_BANG found in some zoneinfo data as it is
931 // really a sentinel, not a transition. See pre-2018f tz/zic.c.
932 ++begin;
933 }
934 std::int_fast64_t unix_time = ToUnixSeconds(tp);
935 if (FromUnixSeconds(unix_time) != tp) {
936 if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) {
937 if (end == begin) return false; // Ignore future_spec_.
938 trans->from = (--end)->prev_civil_sec + 1;
939 trans->to = end->civil_sec;
940 return true;
941 }
942 unix_time += 1; // ceils
943 }
944 const Transition target = {unix_time, 0, civil_second(), civil_second()};
945 const Transition* tr =
946 std::lower_bound(begin, end, target, Transition::ByUnixTime());
947 for (; tr != begin; --tr) { // skip no-op transitions
948 std::uint_fast8_t prev_type_index =
949 (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
950 if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
951 }
952 // When tr == end we return the "last" transition, ignoring future_spec_.
953 if (tr == begin) return false;
954 trans->from = (--tr)->prev_civil_sec + 1;
955 trans->to = tr->civil_sec;
956 return true;
957 }
958
959 } // namespace cctz
960 } // namespace time_internal
961 ABSL_NAMESPACE_END
962 } // namespace absl
963