00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "time_zone_info.h"
00034
00035 #include <algorithm>
00036 #include <cassert>
00037 #include <chrono>
00038 #include <cstdint>
00039 #include <cstdio>
00040 #include <cstdlib>
00041 #include <cstring>
00042 #include <functional>
00043 #include <iostream>
00044 #include <memory>
00045 #include <sstream>
00046 #include <string>
00047
00048 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
00049 #include "time_zone_fixed.h"
00050 #include "time_zone_posix.h"
00051
00052 namespace absl {
00053 namespace time_internal {
00054 namespace cctz {
00055
00056 namespace {
00057
00058 inline bool IsLeap(year_t year) {
00059 return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
00060 }
00061
00062
00063 const std::int_least32_t kDaysPerYear[2] = {365, 366};
00064
00065
00066
00067 const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
00068 {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
00069 {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
00070 };
00071
00072
00073 const std::int_least32_t kSecsPerDay = 24 * 60 * 60;
00074
00075
00076 const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay;
00077
00078
00079 const std::int_least32_t kSecsPerYear[2] = {
00080 365 * kSecsPerDay,
00081 366 * kSecsPerDay,
00082 };
00083
00084
00085 inline std::uint_fast8_t Decode8(const char* cp) {
00086 return static_cast<std::uint_fast8_t>(*cp) & 0xff;
00087 }
00088
00089
00090
00091
00092
00093
00094
00095 std::int_fast32_t Decode32(const char* cp) {
00096 std::uint_fast32_t v = 0;
00097 for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++);
00098 const std::int_fast32_t s32max = 0x7fffffff;
00099 const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
00100 if (v <= s32maxU) return static_cast<std::int_fast32_t>(v);
00101 return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1;
00102 }
00103
00104 std::int_fast64_t Decode64(const char* cp) {
00105 std::uint_fast64_t v = 0;
00106 for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++);
00107 const std::int_fast64_t s64max = 0x7fffffffffffffff;
00108 const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
00109 if (v <= s64maxU) return static_cast<std::int_fast64_t>(v);
00110 return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1;
00111 }
00112
00113
00114 std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
00115 const PosixTransition& pt) {
00116 std::int_fast64_t days = 0;
00117 switch (pt.date.fmt) {
00118 case PosixTransition::J: {
00119 days = pt.date.j.day;
00120 if (!leap_year || days < kMonthOffsets[1][3]) days -= 1;
00121 break;
00122 }
00123 case PosixTransition::N: {
00124 days = pt.date.n.day;
00125 break;
00126 }
00127 case PosixTransition::M: {
00128 const bool last_week = (pt.date.m.week == 5);
00129 days = kMonthOffsets[leap_year][pt.date.m.month + last_week];
00130 const std::int_fast64_t weekday = (jan1_weekday + days) % 7;
00131 if (last_week) {
00132 days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1;
00133 } else {
00134 days += (pt.date.m.weekday + 7 - weekday) % 7;
00135 days += (pt.date.m.week - 1) * 7;
00136 }
00137 break;
00138 }
00139 }
00140 return (days * kSecsPerDay) + pt.time.offset;
00141 }
00142
00143 inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) {
00144 time_zone::civil_lookup cl;
00145 cl.kind = time_zone::civil_lookup::UNIQUE;
00146 cl.pre = cl.trans = cl.post = tp;
00147 return cl;
00148 }
00149
00150 inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) {
00151 return MakeUnique(FromUnixSeconds(unix_time));
00152 }
00153
00154 inline time_zone::civil_lookup MakeSkipped(const Transition& tr,
00155 const civil_second& cs) {
00156 time_zone::civil_lookup cl;
00157 cl.kind = time_zone::civil_lookup::SKIPPED;
00158 cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec));
00159 cl.trans = FromUnixSeconds(tr.unix_time);
00160 cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs));
00161 return cl;
00162 }
00163
00164 inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
00165 const civil_second& cs) {
00166 time_zone::civil_lookup cl;
00167 cl.kind = time_zone::civil_lookup::REPEATED;
00168 cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs));
00169 cl.trans = FromUnixSeconds(tr.unix_time);
00170 cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec));
00171 return cl;
00172 }
00173
00174 inline civil_second YearShift(const civil_second& cs, year_t shift) {
00175 return civil_second(cs.year() + shift, cs.month(), cs.day(),
00176 cs.hour(), cs.minute(), cs.second());
00177 }
00178
00179 }
00180
00181
00182 bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
00183 transition_types_.resize(1);
00184 TransitionType& tt(transition_types_.back());
00185 tt.utc_offset = static_cast<std::int_least32_t>(offset.count());
00186 tt.is_dst = false;
00187 tt.abbr_index = 0;
00188
00189
00190
00191
00192 transitions_.clear();
00193 transitions_.reserve(12);
00194 for (const std::int_fast64_t unix_time : {
00195 -(1LL << 59),
00196 1356998400LL,
00197 1388534400LL,
00198 1420070400LL,
00199 1451606400LL,
00200 1483228800LL,
00201 1514764800LL,
00202 1546300800LL,
00203 1577836800LL,
00204 1609459200LL,
00205 1640995200LL,
00206 1672531200LL,
00207 2147483647LL,
00208 }) {
00209 Transition& tr(*transitions_.emplace(transitions_.end()));
00210 tr.unix_time = unix_time;
00211 tr.type_index = 0;
00212 tr.civil_sec = LocalTime(tr.unix_time, tt).cs;
00213 tr.prev_civil_sec = tr.civil_sec - 1;
00214 }
00215
00216 default_transition_type_ = 0;
00217 abbreviations_ = FixedOffsetToAbbr(offset);
00218 abbreviations_.append(1, '\0');
00219 future_spec_.clear();
00220 extended_ = false;
00221
00222 tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
00223 tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
00224
00225 transitions_.shrink_to_fit();
00226 return true;
00227 }
00228
00229
00230 bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
00231 std::int_fast32_t v;
00232 if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false;
00233 timecnt = static_cast<std::size_t>(v);
00234 if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false;
00235 typecnt = static_cast<std::size_t>(v);
00236 if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false;
00237 charcnt = static_cast<std::size_t>(v);
00238 if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false;
00239 leapcnt = static_cast<std::size_t>(v);
00240 if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
00241 ttisstdcnt = static_cast<std::size_t>(v);
00242 if ((v = Decode32(tzh.tzh_ttisgmtcnt)) < 0) return false;
00243 ttisgmtcnt = static_cast<std::size_t>(v);
00244 return true;
00245 }
00246
00247
00248
00249 std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
00250 std::size_t len = 0;
00251 len += (time_len + 1) * timecnt;
00252 len += (4 + 1 + 1) * typecnt;
00253 len += 1 * charcnt;
00254 len += (time_len + 4) * leapcnt;
00255 len += 1 * ttisstdcnt;
00256 len += 1 * ttisgmtcnt;
00257 return len;
00258 }
00259
00260
00261 void TimeZoneInfo::CheckTransition(const std::string& name,
00262 const TransitionType& tt,
00263 std::int_fast32_t offset, bool is_dst,
00264 const std::string& abbr) const {
00265 if (tt.utc_offset != offset || tt.is_dst != is_dst ||
00266 &abbreviations_[tt.abbr_index] != abbr) {
00267 std::clog << name << ": Transition"
00268 << " offset=" << tt.utc_offset << "/"
00269 << (tt.is_dst ? "DST" : "STD")
00270 << "/abbr=" << &abbreviations_[tt.abbr_index]
00271 << " does not match POSIX spec '" << future_spec_ << "'\n";
00272 }
00273 }
00274
00275
00276
00277
00278 bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
00279 std::uint_fast8_t tt2_index) const {
00280 if (tt1_index == tt2_index) return true;
00281 const TransitionType& tt1(transition_types_[tt1_index]);
00282 const TransitionType& tt2(transition_types_[tt2_index]);
00283 if (tt1.is_dst != tt2.is_dst) return false;
00284 if (tt1.utc_offset != tt2.utc_offset) return false;
00285 if (tt1.abbr_index != tt2.abbr_index) return false;
00286 return true;
00287 }
00288
00289
00290
00291 void TimeZoneInfo::ExtendTransitions(const std::string& name,
00292 const Header& hdr) {
00293 extended_ = false;
00294 bool extending = !future_spec_.empty();
00295
00296 PosixTimeZone posix;
00297 if (extending && !ParsePosixSpec(future_spec_, &posix)) {
00298 std::clog << name << ": Failed to parse '" << future_spec_ << "'\n";
00299 extending = false;
00300 }
00301
00302 if (extending && posix.dst_abbr.empty()) {
00303
00304
00305 std::uint_fast8_t index = default_transition_type_;
00306 if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index;
00307 const TransitionType& tt(transition_types_[index]);
00308 CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr);
00309 extending = false;
00310 }
00311
00312 if (extending && hdr.timecnt < 2) {
00313 std::clog << name << ": Too few transitions for POSIX spec\n";
00314 extending = false;
00315 }
00316
00317 if (!extending) {
00318
00319
00320
00321
00322 const Transition& last(transitions_.back());
00323 if (last.unix_time < 0) {
00324 const std::uint_fast8_t type_index = last.type_index;
00325 Transition& tr(*transitions_.emplace(transitions_.end()));
00326 tr.unix_time = 2147483647;
00327 tr.type_index = type_index;
00328 }
00329 return;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338 transitions_.reserve(hdr.timecnt + 400 * 2 + 1);
00339 transitions_.resize(hdr.timecnt + 400 * 2);
00340 extended_ = true;
00341
00342
00343
00344
00345
00346
00347 const Transition* tr0 = &transitions_[hdr.timecnt - 1];
00348 const Transition* tr1 = &transitions_[hdr.timecnt - 2];
00349 const TransitionType* tt0 = &transition_types_[tr0->type_index];
00350 const TransitionType* tt1 = &transition_types_[tr1->type_index];
00351 const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1);
00352 const TransitionType& std(tt0->is_dst ? *tt1 : *tt0);
00353 CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr);
00354 CheckTransition(name, std, posix.std_offset, false, posix.std_abbr);
00355
00356
00357 last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year();
00358 bool leap_year = IsLeap(last_year_);
00359 const civil_day jan1(last_year_, 1, 1);
00360 std::int_fast64_t jan1_time = civil_second(jan1) - civil_second();
00361 int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7;
00362 Transition* tr = &transitions_[hdr.timecnt];
00363 if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) {
00364
00365 transitions_.resize(transitions_.size() + 1);
00366 assert(tr == &transitions_[hdr.timecnt]);
00367 const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
00368 std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
00369 tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
00370 tr++->type_index = tr1->type_index;
00371 tr0 = &transitions_[hdr.timecnt];
00372 tr1 = &transitions_[hdr.timecnt - 1];
00373 tt0 = &transition_types_[tr0->type_index];
00374 tt1 = &transition_types_[tr1->type_index];
00375 }
00376 const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
00377 const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end);
00378 for (const year_t limit = last_year_ + 400; last_year_ < limit;) {
00379 last_year_ += 1;
00380 jan1_time += kSecsPerYear[leap_year];
00381 jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
00382 leap_year = !leap_year && IsLeap(last_year_);
00383 std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
00384 tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
00385 tr++->type_index = tr1->type_index;
00386 std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0);
00387 tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset;
00388 tr++->type_index = tr0->type_index;
00389 }
00390 assert(tr == &transitions_[0] + transitions_.size());
00391 }
00392
00393 bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
00394
00395 tzhead tzh;
00396 if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
00397 return false;
00398 if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
00399 return false;
00400 Header hdr;
00401 if (!hdr.Build(tzh))
00402 return false;
00403 std::size_t time_len = 4;
00404 if (tzh.tzh_version[0] != '\0') {
00405
00406 if (zip->Skip(hdr.DataLength(time_len)) != 0)
00407 return false;
00408
00409 if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
00410 return false;
00411 if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
00412 return false;
00413 if (tzh.tzh_version[0] == '\0')
00414 return false;
00415 if (!hdr.Build(tzh))
00416 return false;
00417 time_len = 8;
00418 }
00419 if (hdr.typecnt == 0)
00420 return false;
00421 if (hdr.leapcnt != 0) {
00422
00423
00424
00425
00426 return false;
00427 }
00428 if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
00429 return false;
00430 if (hdr.ttisgmtcnt != 0 && hdr.ttisgmtcnt != hdr.typecnt)
00431 return false;
00432
00433
00434 std::size_t len = hdr.DataLength(time_len);
00435 std::vector<char> tbuf(len);
00436 if (zip->Read(tbuf.data(), len) != len)
00437 return false;
00438 const char* bp = tbuf.data();
00439
00440
00441 transitions_.reserve(hdr.timecnt + 2);
00442 transitions_.resize(hdr.timecnt);
00443 for (std::size_t i = 0; i != hdr.timecnt; ++i) {
00444 transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
00445 bp += time_len;
00446 if (i != 0) {
00447
00448 if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
00449 return false;
00450 }
00451 }
00452 bool seen_type_0 = false;
00453 for (std::size_t i = 0; i != hdr.timecnt; ++i) {
00454 transitions_[i].type_index = Decode8(bp++);
00455 if (transitions_[i].type_index >= hdr.typecnt)
00456 return false;
00457 if (transitions_[i].type_index == 0)
00458 seen_type_0 = true;
00459 }
00460
00461
00462 transition_types_.resize(hdr.typecnt);
00463 for (std::size_t i = 0; i != hdr.typecnt; ++i) {
00464 transition_types_[i].utc_offset =
00465 static_cast<std::int_least32_t>(Decode32(bp));
00466 if (transition_types_[i].utc_offset >= kSecsPerDay ||
00467 transition_types_[i].utc_offset <= -kSecsPerDay)
00468 return false;
00469 bp += 4;
00470 transition_types_[i].is_dst = (Decode8(bp++) != 0);
00471 transition_types_[i].abbr_index = Decode8(bp++);
00472 if (transition_types_[i].abbr_index >= hdr.charcnt)
00473 return false;
00474 }
00475
00476
00477 default_transition_type_ = 0;
00478 if (seen_type_0 && hdr.timecnt != 0) {
00479 std::uint_fast8_t index = 0;
00480 if (transition_types_[0].is_dst) {
00481 index = transitions_[0].type_index;
00482 while (index != 0 && transition_types_[index].is_dst)
00483 --index;
00484 }
00485 while (index != hdr.typecnt && transition_types_[index].is_dst)
00486 ++index;
00487 if (index != hdr.typecnt)
00488 default_transition_type_ = index;
00489 }
00490
00491
00492 abbreviations_.assign(bp, hdr.charcnt);
00493 bp += hdr.charcnt;
00494
00495
00496
00497
00498
00499 bp += (8 + 4) * hdr.leapcnt;
00500 bp += 1 * hdr.ttisstdcnt;
00501 bp += 1 * hdr.ttisgmtcnt;
00502 assert(bp == tbuf.data() + tbuf.size());
00503
00504 future_spec_.clear();
00505 if (tzh.tzh_version[0] != '\0') {
00506
00507
00508 auto get_char = [](ZoneInfoSource* zip) -> int {
00509 unsigned char ch;
00510 return (zip->Read(&ch, 1) == 1) ? ch : EOF;
00511 };
00512 if (get_char(zip) != '\n')
00513 return false;
00514 for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
00515 if (c == EOF)
00516 return false;
00517 future_spec_.push_back(static_cast<char>(c));
00518 }
00519 }
00520
00521
00522
00523
00524
00525
00526 if (version_.empty()) {
00527 version_ = zip->Version();
00528 }
00529
00530
00531
00532
00533
00534 while (hdr.timecnt > 1) {
00535 if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index,
00536 transitions_[hdr.timecnt - 2].type_index)) {
00537 break;
00538 }
00539 hdr.timecnt -= 1;
00540 }
00541 transitions_.resize(hdr.timecnt);
00542
00543
00544
00545
00546
00547
00548 if (transitions_.empty() || transitions_.front().unix_time >= 0) {
00549 Transition& tr(*transitions_.emplace(transitions_.begin()));
00550 tr.unix_time = -(1LL << 59);
00551 tr.type_index = default_transition_type_;
00552 hdr.timecnt += 1;
00553 }
00554
00555
00556 ExtendTransitions(name, hdr);
00557
00558
00559
00560 const TransitionType* ttp = &transition_types_[default_transition_type_];
00561 for (std::size_t i = 0; i != transitions_.size(); ++i) {
00562 Transition& tr(transitions_[i]);
00563 tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1;
00564 ttp = &transition_types_[tr.type_index];
00565 tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs;
00566 if (i != 0) {
00567
00568
00569
00570 if (!Transition::ByCivilTime()(transitions_[i - 1], tr))
00571 return false;
00572 }
00573 }
00574
00575
00576
00577 for (auto& tt : transition_types_) {
00578 tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
00579 tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
00580 }
00581
00582 transitions_.shrink_to_fit();
00583 return true;
00584 }
00585
00586 namespace {
00587
00588
00589 inline FILE* FOpen(const char* path, const char* mode) {
00590 #if defined(_MSC_VER)
00591 FILE* fp;
00592 if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
00593 return fp;
00594 #else
00595 return fopen(path, mode);
00596 #endif
00597 }
00598
00599
00600 class FileZoneInfoSource : public ZoneInfoSource {
00601 public:
00602 static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
00603
00604 std::size_t Read(void* ptr, std::size_t size) override {
00605 size = std::min(size, len_);
00606 std::size_t nread = fread(ptr, 1, size, fp_.get());
00607 len_ -= nread;
00608 return nread;
00609 }
00610 int Skip(std::size_t offset) override {
00611 offset = std::min(offset, len_);
00612 int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR);
00613 if (rc == 0) len_ -= offset;
00614 return rc;
00615 }
00616 std::string Version() const override {
00617
00618 return std::string();
00619 }
00620
00621 protected:
00622 explicit FileZoneInfoSource(
00623 FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max())
00624 : fp_(fp, fclose), len_(len) {}
00625
00626 private:
00627 std::unique_ptr<FILE, int(*)(FILE*)> fp_;
00628 std::size_t len_;
00629 };
00630
00631 std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
00632 const std::string& name) {
00633
00634 if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
00635
00636
00637 std::string path;
00638 if (name.empty() || name[0] != '/') {
00639 const char* tzdir = "/usr/share/zoneinfo";
00640 char* tzdir_env = nullptr;
00641 #if defined(_MSC_VER)
00642 _dupenv_s(&tzdir_env, nullptr, "TZDIR");
00643 #else
00644 tzdir_env = std::getenv("TZDIR");
00645 #endif
00646 if (tzdir_env && *tzdir_env) tzdir = tzdir_env;
00647 path += tzdir;
00648 path += '/';
00649 #if defined(_MSC_VER)
00650 free(tzdir_env);
00651 #endif
00652 }
00653 path += name;
00654
00655
00656 FILE* fp = FOpen(path.c_str(), "rb");
00657 if (fp == nullptr) return nullptr;
00658 std::size_t length = 0;
00659 if (fseek(fp, 0, SEEK_END) == 0) {
00660 long pos = ftell(fp);
00661 if (pos >= 0) {
00662 length = static_cast<std::size_t>(pos);
00663 }
00664 rewind(fp);
00665 }
00666 return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length));
00667 }
00668
00669 class AndroidZoneInfoSource : public FileZoneInfoSource {
00670 public:
00671 static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
00672 std::string Version() const override { return version_; }
00673
00674 private:
00675 explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers)
00676 : FileZoneInfoSource(fp, len), version_(vers) {}
00677 std::string version_;
00678 };
00679
00680 std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
00681 const std::string& name) {
00682
00683 if (name.compare(0, 5, "file:") == 0) return Open(name.substr(5));
00684
00685 #if defined(__ANDROID__)
00686
00687 for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
00688 "/system/usr/share/zoneinfo/tzdata"}) {
00689 std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose);
00690 if (fp.get() == nullptr) continue;
00691
00692 char hbuf[24];
00693 if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
00694 if (strncmp(hbuf, "tzdata", 6) != 0) continue;
00695 const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
00696 const std::int_fast32_t index_offset = Decode32(hbuf + 12);
00697 const std::int_fast32_t data_offset = Decode32(hbuf + 16);
00698 if (index_offset < 0 || data_offset < index_offset) continue;
00699 if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
00700 continue;
00701
00702 char ebuf[52];
00703 const std::size_t index_size =
00704 static_cast<std::size_t>(data_offset - index_offset);
00705 const std::size_t zonecnt = index_size / sizeof(ebuf);
00706 if (zonecnt * sizeof(ebuf) != index_size) continue;
00707 for (std::size_t i = 0; i != zonecnt; ++i) {
00708 if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
00709 const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
00710 const std::int_fast32_t length = Decode32(ebuf + 44);
00711 if (start < 0 || length < 0) break;
00712 ebuf[40] = '\0';
00713 if (strcmp(name.c_str(), ebuf) == 0) {
00714 if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
00715 return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
00716 fp.release(), static_cast<std::size_t>(length), vers));
00717 }
00718 }
00719 }
00720 #endif // __ANDROID__
00721 return nullptr;
00722 }
00723
00724 }
00725
00726 bool TimeZoneInfo::Load(const std::string& name) {
00727
00728
00729
00730
00731 auto offset = seconds::zero();
00732 if (FixedOffsetFromName(name, &offset)) {
00733 return ResetToBuiltinUTC(offset);
00734 }
00735
00736
00737 auto zip = cctz_extension::zone_info_source_factory(
00738 name, [](const std::string& name) -> std::unique_ptr<ZoneInfoSource> {
00739 if (auto zip = FileZoneInfoSource::Open(name)) return zip;
00740 if (auto zip = AndroidZoneInfoSource::Open(name)) return zip;
00741 return nullptr;
00742 });
00743 return zip != nullptr && Load(name, zip.get());
00744 }
00745
00746
00747 time_zone::absolute_lookup TimeZoneInfo::LocalTime(
00748 std::int_fast64_t unix_time, const TransitionType& tt) const {
00749
00750
00751
00752 return {(civil_second() + unix_time) + tt.utc_offset,
00753 tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
00754 }
00755
00756
00757 time_zone::absolute_lookup TimeZoneInfo::LocalTime(
00758 std::int_fast64_t unix_time, const Transition& tr) const {
00759 const TransitionType& tt = transition_types_[tr.type_index];
00760
00761
00762 return {tr.civil_sec + (unix_time - tr.unix_time),
00763 tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
00764 }
00765
00766
00767 time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
00768 year_t c4_shift) const {
00769 assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_);
00770 time_zone::civil_lookup cl = MakeTime(cs);
00771 if (c4_shift > seconds::max().count() / kSecsPer400Years) {
00772 cl.pre = cl.trans = cl.post = time_point<seconds>::max();
00773 } else {
00774 const auto offset = seconds(c4_shift * kSecsPer400Years);
00775 const auto limit = time_point<seconds>::max() - offset;
00776 for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) {
00777 if (*tp > limit) {
00778 *tp = time_point<seconds>::max();
00779 } else {
00780 *tp += offset;
00781 }
00782 }
00783 }
00784 return cl;
00785 }
00786
00787 time_zone::absolute_lookup TimeZoneInfo::BreakTime(
00788 const time_point<seconds>& tp) const {
00789 std::int_fast64_t unix_time = ToUnixSeconds(tp);
00790 const std::size_t timecnt = transitions_.size();
00791 assert(timecnt != 0);
00792
00793 if (unix_time < transitions_[0].unix_time) {
00794 return LocalTime(unix_time, transition_types_[default_transition_type_]);
00795 }
00796 if (unix_time >= transitions_[timecnt - 1].unix_time) {
00797
00798
00799
00800 if (extended_) {
00801 const std::int_fast64_t diff =
00802 unix_time - transitions_[timecnt - 1].unix_time;
00803 const year_t shift = diff / kSecsPer400Years + 1;
00804 const auto d = seconds(shift * kSecsPer400Years);
00805 time_zone::absolute_lookup al = BreakTime(tp - d);
00806 al.cs = YearShift(al.cs, shift * 400);
00807 return al;
00808 }
00809 return LocalTime(unix_time, transitions_[timecnt - 1]);
00810 }
00811
00812 const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
00813 if (0 < hint && hint < timecnt) {
00814 if (transitions_[hint - 1].unix_time <= unix_time) {
00815 if (unix_time < transitions_[hint].unix_time) {
00816 return LocalTime(unix_time, transitions_[hint - 1]);
00817 }
00818 }
00819 }
00820
00821 const Transition target = {unix_time, 0, civil_second(), civil_second()};
00822 const Transition* begin = &transitions_[0];
00823 const Transition* tr = std::upper_bound(begin, begin + timecnt, target,
00824 Transition::ByUnixTime());
00825 local_time_hint_.store(static_cast<std::size_t>(tr - begin),
00826 std::memory_order_relaxed);
00827 return LocalTime(unix_time, *--tr);
00828 }
00829
00830 time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
00831 const std::size_t timecnt = transitions_.size();
00832 assert(timecnt != 0);
00833
00834
00835 const Transition* tr = nullptr;
00836 const Transition* begin = &transitions_[0];
00837 const Transition* end = begin + timecnt;
00838 if (cs < begin->civil_sec) {
00839 tr = begin;
00840 } else if (cs >= transitions_[timecnt - 1].civil_sec) {
00841 tr = end;
00842 } else {
00843 const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed);
00844 if (0 < hint && hint < timecnt) {
00845 if (transitions_[hint - 1].civil_sec <= cs) {
00846 if (cs < transitions_[hint].civil_sec) {
00847 tr = begin + hint;
00848 }
00849 }
00850 }
00851 if (tr == nullptr) {
00852 const Transition target = {0, 0, cs, civil_second()};
00853 tr = std::upper_bound(begin, end, target, Transition::ByCivilTime());
00854 time_local_hint_.store(static_cast<std::size_t>(tr - begin),
00855 std::memory_order_relaxed);
00856 }
00857 }
00858
00859 if (tr == begin) {
00860 if (tr->prev_civil_sec >= cs) {
00861
00862 const TransitionType& tt(transition_types_[default_transition_type_]);
00863 if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min());
00864 return MakeUnique(cs - (civil_second() + tt.utc_offset));
00865 }
00866
00867 return MakeSkipped(*tr, cs);
00868 }
00869
00870 if (tr == end) {
00871 if (cs > (--tr)->prev_civil_sec) {
00872
00873
00874
00875 if (extended_ && cs.year() > last_year_) {
00876 const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
00877 return TimeLocal(YearShift(cs, shift * -400), shift);
00878 }
00879 const TransitionType& tt(transition_types_[tr->type_index]);
00880 if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
00881 return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
00882 }
00883
00884 return MakeRepeated(*tr, cs);
00885 }
00886
00887 if (tr->prev_civil_sec < cs) {
00888
00889 return MakeSkipped(*tr, cs);
00890 }
00891
00892 if (cs <= (--tr)->prev_civil_sec) {
00893
00894 return MakeRepeated(*tr, cs);
00895 }
00896
00897
00898 return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
00899 }
00900
00901 std::string TimeZoneInfo::Version() const {
00902 return version_;
00903 }
00904
00905 std::string TimeZoneInfo::Description() const {
00906 std::ostringstream oss;
00907 oss << "#trans=" << transitions_.size();
00908 oss << " #types=" << transition_types_.size();
00909 oss << " spec='" << future_spec_ << "'";
00910 return oss.str();
00911 }
00912
00913 bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
00914 time_zone::civil_transition* trans) const {
00915 if (transitions_.empty()) return false;
00916 const Transition* begin = &transitions_[0];
00917 const Transition* end = begin + transitions_.size();
00918 if (begin->unix_time <= -(1LL << 59)) {
00919
00920
00921 ++begin;
00922 }
00923 std::int_fast64_t unix_time = ToUnixSeconds(tp);
00924 const Transition target = {unix_time, 0, civil_second(), civil_second()};
00925 const Transition* tr = std::upper_bound(begin, end, target,
00926 Transition::ByUnixTime());
00927 for (; tr != end; ++tr) {
00928 std::uint_fast8_t prev_type_index =
00929 (tr == begin) ? default_transition_type_ : tr[-1].type_index;
00930 if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
00931 }
00932
00933 if (tr == end) return false;
00934 trans->from = tr->prev_civil_sec + 1;
00935 trans->to = tr->civil_sec;
00936 return true;
00937 }
00938
00939 bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
00940 time_zone::civil_transition* trans) const {
00941 if (transitions_.empty()) return false;
00942 const Transition* begin = &transitions_[0];
00943 const Transition* end = begin + transitions_.size();
00944 if (begin->unix_time <= -(1LL << 59)) {
00945
00946
00947 ++begin;
00948 }
00949 std::int_fast64_t unix_time = ToUnixSeconds(tp);
00950 if (FromUnixSeconds(unix_time) != tp) {
00951 if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) {
00952 if (end == begin) return false;
00953 trans->from = (--end)->prev_civil_sec + 1;
00954 trans->to = end->civil_sec;
00955 return true;
00956 }
00957 unix_time += 1;
00958 }
00959 const Transition target = {unix_time, 0, civil_second(), civil_second()};
00960 const Transition* tr = std::lower_bound(begin, end, target,
00961 Transition::ByUnixTime());
00962 for (; tr != begin; --tr) {
00963 std::uint_fast8_t prev_type_index =
00964 (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
00965 if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
00966 }
00967
00968 if (tr == begin) return false;
00969 trans->from = (--tr)->prev_civil_sec + 1;
00970 trans->to = tr->civil_sec;
00971 return true;
00972 }
00973
00974 }
00975 }
00976 }