merge(3p/absl): subtree merge of Abseil up to e19260f
... notably, this includes Abseil's own StatusOr type, which conflicted with our implementation (that was taken from TensorFlow). Change-Id: Ie7d6764b64055caaeb8dc7b6b9d066291e6b538f
This commit is contained in:
parent
cc27324d02
commit
082c006c04
854 changed files with 11260 additions and 5296 deletions
3
third_party/abseil_cpp/absl/time/BUILD.bazel
vendored
3
third_party/abseil_cpp/absl/time/BUILD.bazel
vendored
|
|
@ -24,7 +24,7 @@ load(
|
|||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
licenses(["notice"])
|
||||
|
||||
cc_library(
|
||||
name = "time",
|
||||
|
|
@ -70,6 +70,7 @@ cc_library(
|
|||
],
|
||||
deps = [
|
||||
":time",
|
||||
"//absl/base:config",
|
||||
"//absl/base:raw_logging_internal",
|
||||
"//absl/time/internal/cctz:time_zone",
|
||||
"@com_google_googletest//:gtest",
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ absl_cc_library(
|
|||
${ABSL_DEFAULT_COPTS}
|
||||
DEPS
|
||||
absl::time
|
||||
absl::config
|
||||
absl::raw_logging_internal
|
||||
absl::time_zone
|
||||
gmock
|
||||
|
|
|
|||
4
third_party/abseil_cpp/absl/time/clock.cc
vendored
4
third_party/abseil_cpp/absl/time/clock.cc
vendored
|
|
@ -74,9 +74,7 @@ ABSL_NAMESPACE_END
|
|||
#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
int64_t GetCurrentTimeNanos() {
|
||||
return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
|
||||
}
|
||||
int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
#else // Use the cyclecounter-based implementation below.
|
||||
|
|
|
|||
25
third_party/abseil_cpp/absl/time/duration.cc
vendored
25
third_party/abseil_cpp/absl/time/duration.cc
vendored
|
|
@ -69,6 +69,7 @@
|
|||
#include "absl/base/casts.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/numeric/int128.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
|
|
@ -355,7 +356,7 @@ namespace time_internal {
|
|||
// the remainder. If it does not saturate, the remainder remain accurate,
|
||||
// but the returned quotient will over/underflow int64_t and should not be used.
|
||||
int64_t IDivDuration(bool satq, const Duration num, const Duration den,
|
||||
Duration* rem) {
|
||||
Duration* rem) {
|
||||
int64_t q = 0;
|
||||
if (IDivFastPath(num, den, &q, rem)) {
|
||||
return q;
|
||||
|
|
@ -710,16 +711,17 @@ char* Format64(char* ep, int width, int64_t v) {
|
|||
// fractional digits, because it is in the noise of what a Duration can
|
||||
// represent.
|
||||
struct DisplayUnit {
|
||||
const char* abbr;
|
||||
absl::string_view abbr;
|
||||
int prec;
|
||||
double pow10;
|
||||
};
|
||||
const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
|
||||
const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
|
||||
const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
|
||||
const DisplayUnit kDisplaySec = {"s", 11, 1e11};
|
||||
const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
|
||||
const DisplayUnit kDisplayHour = {"h", -1, 0.0}; // prec ignored
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplaySec = {"s", 11, 1e11};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayHour = {"h", -1,
|
||||
0.0}; // prec ignored
|
||||
|
||||
void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
|
||||
char buf[sizeof("2562047788015216")]; // hours in max duration
|
||||
|
|
@ -727,7 +729,7 @@ void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
|
|||
char* bp = Format64(ep, 0, n);
|
||||
if (*bp != '0' || bp + 1 != ep) {
|
||||
out->append(bp, ep - bp);
|
||||
out->append(unit.abbr);
|
||||
out->append(unit.abbr.data(), unit.abbr.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -750,7 +752,7 @@ void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
|
|||
while (ep[-1] == '0') --ep;
|
||||
out->append(bp, ep - bp);
|
||||
}
|
||||
out->append(unit.abbr);
|
||||
out->append(unit.abbr.data(), unit.abbr.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +763,8 @@ void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
|
|||
// form "72h3m0.5s". Leading zero units are omitted. As a special
|
||||
// case, durations less than one second format use a smaller unit
|
||||
// (milli-, micro-, or nanoseconds) to ensure that the leading digit
|
||||
// is non-zero. The zero duration formats as 0, with no unit.
|
||||
// is non-zero.
|
||||
// Unlike Go, we format the zero duration as 0, with no unit.
|
||||
std::string FormatDuration(Duration d) {
|
||||
const Duration min_duration = Seconds(kint64min);
|
||||
if (d == min_duration) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
|||
|
||||
package(features = ["-parse_headers"])
|
||||
|
||||
licenses(["notice"]) # Apache License
|
||||
licenses(["notice"])
|
||||
|
||||
filegroup(
|
||||
name = "zoneinfo",
|
||||
|
|
@ -92,6 +92,11 @@ cc_library(
|
|||
|
||||
### tests
|
||||
|
||||
test_suite(
|
||||
name = "all_tests",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "civil_time_test",
|
||||
size = "small",
|
||||
|
|
|
|||
|
|
@ -416,16 +416,10 @@ class civil_time {
|
|||
|
||||
// Assigning arithmetic.
|
||||
CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
|
||||
f_ = step(T{}, f_, n);
|
||||
return *this;
|
||||
return *this = *this + n;
|
||||
}
|
||||
CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
|
||||
if (n != (std::numeric_limits<diff_t>::min)()) {
|
||||
f_ = step(T{}, f_, -n);
|
||||
} else {
|
||||
f_ = step(T{}, step(T{}, f_, -(n + 1)), 1);
|
||||
}
|
||||
return *this;
|
||||
return *this = *this - n;
|
||||
}
|
||||
CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; }
|
||||
CONSTEXPR_M civil_time operator++(int) noexcept {
|
||||
|
|
@ -442,13 +436,15 @@ class civil_time {
|
|||
|
||||
// Binary arithmetic operators.
|
||||
friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
|
||||
return a += n;
|
||||
return civil_time(step(T{}, a.f_, n));
|
||||
}
|
||||
friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
|
||||
return a += n;
|
||||
return a + n;
|
||||
}
|
||||
friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
|
||||
return a -= n;
|
||||
return n != (std::numeric_limits<diff_t>::min)()
|
||||
? civil_time(step(T{}, a.f_, -n))
|
||||
: civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
|
||||
}
|
||||
friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
|
||||
return difference(T{}, lhs.f_, rhs.f_);
|
||||
|
|
|
|||
|
|
@ -654,14 +654,23 @@ const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
|
|||
}
|
||||
|
||||
// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
|
||||
// and the day on which weeks are defined to start.
|
||||
void FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
|
||||
// and the day on which weeks are defined to start. Returns false if year
|
||||
// would need to move outside its bounds.
|
||||
bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
|
||||
const civil_year y(*year % 400);
|
||||
civil_day cd = prev_weekday(y, week_start); // week 0
|
||||
cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
|
||||
*year += cd.year() - y.year();
|
||||
if (const year_t shift = cd.year() - y.year()) {
|
||||
if (shift > 0) {
|
||||
if (*year > std::numeric_limits<year_t>::max() - shift) return false;
|
||||
} else {
|
||||
if (*year < std::numeric_limits<year_t>::min() - shift) return false;
|
||||
}
|
||||
*year += shift;
|
||||
}
|
||||
tm->tm_mon = cd.month() - 1;
|
||||
tm->tm_mday = cd.day();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -965,7 +974,12 @@ bool parse(const std::string& format, const std::string& input,
|
|||
}
|
||||
|
||||
// Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
|
||||
if (week_num != -1) FromWeek(week_num, week_start, &year, &tm);
|
||||
if (week_num != -1) {
|
||||
if (!FromWeek(week_num, week_start, &year, &tm)) {
|
||||
if (err != nullptr) *err = "Out-of-range field";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const int month = tm.tm_mon + 1;
|
||||
civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
|
|
|||
|
|
@ -1481,6 +1481,11 @@ TEST(Parse, WeekYearShift) {
|
|||
EXPECT_EQ(exp, tp);
|
||||
EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
|
||||
EXPECT_EQ(exp, tp);
|
||||
|
||||
// Slipping into the previous/following calendar years should fail when
|
||||
// we're already at the extremes.
|
||||
EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
|
||||
EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
|
||||
}
|
||||
|
||||
TEST(Parse, MaxRange) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
|
@ -83,6 +82,27 @@ const std::int_least32_t kSecsPerYear[2] = {
|
|||
366 * kSecsPerDay,
|
||||
};
|
||||
|
||||
// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
|
||||
inline int ToPosixWeekday(weekday wd) {
|
||||
switch (wd) {
|
||||
case weekday::sunday:
|
||||
return 0;
|
||||
case weekday::monday:
|
||||
return 1;
|
||||
case weekday::tuesday:
|
||||
return 2;
|
||||
case weekday::wednesday:
|
||||
return 3;
|
||||
case weekday::thursday:
|
||||
return 4;
|
||||
case weekday::friday:
|
||||
return 5;
|
||||
case weekday::saturday:
|
||||
return 6;
|
||||
}
|
||||
return 0; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
// Single-byte, unsigned numeric values are encoded directly.
|
||||
inline std::uint_fast8_t Decode8(const char* cp) {
|
||||
return static_cast<std::uint_fast8_t>(*cp) & 0xff;
|
||||
|
|
@ -188,15 +208,13 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
|
|||
tt.is_dst = false;
|
||||
tt.abbr_index = 0;
|
||||
|
||||
// We temporarily add some redundant, contemporary (2013 through 2023)
|
||||
// We temporarily add some redundant, contemporary (2015 through 2025)
|
||||
// transitions for performance reasons. See TimeZoneInfo::LocalTime().
|
||||
// TODO: Fix the performance issue and remove the extra transitions.
|
||||
transitions_.clear();
|
||||
transitions_.reserve(12);
|
||||
for (const std::int_fast64_t unix_time : {
|
||||
-(1LL << 59), // BIG_BANG
|
||||
1356998400LL, // 2013-01-01T00:00:00+00:00
|
||||
1388534400LL, // 2014-01-01T00:00:00+00:00
|
||||
-(1LL << 59), // a "first half" transition
|
||||
1420070400LL, // 2015-01-01T00:00:00+00:00
|
||||
1451606400LL, // 2016-01-01T00:00:00+00:00
|
||||
1483228800LL, // 2017-01-01T00:00:00+00:00
|
||||
|
|
@ -206,7 +224,8 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
|
|||
1609459200LL, // 2021-01-01T00:00:00+00:00
|
||||
1640995200LL, // 2022-01-01T00:00:00+00:00
|
||||
1672531200LL, // 2023-01-01T00:00:00+00:00
|
||||
2147483647LL, // 2^31 - 1
|
||||
1704067200LL, // 2024-01-01T00:00:00+00:00
|
||||
1735689600LL, // 2025-01-01T00:00:00+00:00
|
||||
}) {
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = unix_time;
|
||||
|
|
@ -217,8 +236,8 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
|
|||
|
||||
default_transition_type_ = 0;
|
||||
abbreviations_ = FixedOffsetToAbbr(offset);
|
||||
abbreviations_.append(1, '\0'); // add NUL
|
||||
future_spec_.clear(); // never needed for a fixed-offset zone
|
||||
abbreviations_.append(1, '\0');
|
||||
future_spec_.clear(); // never needed for a fixed-offset zone
|
||||
extended_ = false;
|
||||
|
||||
tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
|
||||
|
|
@ -259,21 +278,6 @@ std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
|
|||
return len;
|
||||
}
|
||||
|
||||
// Check that the TransitionType has the expected offset/is_dst/abbreviation.
|
||||
void TimeZoneInfo::CheckTransition(const std::string& name,
|
||||
const TransitionType& tt,
|
||||
std::int_fast32_t offset, bool is_dst,
|
||||
const std::string& abbr) const {
|
||||
if (tt.utc_offset != offset || tt.is_dst != is_dst ||
|
||||
&abbreviations_[tt.abbr_index] != abbr) {
|
||||
std::clog << name << ": Transition"
|
||||
<< " offset=" << tt.utc_offset << "/"
|
||||
<< (tt.is_dst ? "DST" : "STD")
|
||||
<< "/abbr=" << &abbreviations_[tt.abbr_index]
|
||||
<< " does not match POSIX spec '" << future_spec_ << "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
// zic(8) can generate no-op transitions when a zone changes rules at an
|
||||
// instant when there is actually no discontinuity. So we check whether
|
||||
// two transitions have equivalent types (same offset/is_dst/abbr).
|
||||
|
|
@ -282,117 +286,108 @@ bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
|
|||
if (tt1_index == tt2_index) return true;
|
||||
const TransitionType& tt1(transition_types_[tt1_index]);
|
||||
const TransitionType& tt2(transition_types_[tt2_index]);
|
||||
if (tt1.is_dst != tt2.is_dst) return false;
|
||||
if (tt1.utc_offset != tt2.utc_offset) return false;
|
||||
if (tt1.is_dst != tt2.is_dst) return false;
|
||||
if (tt1.abbr_index != tt2.abbr_index) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find/make a transition type with these attributes.
|
||||
bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
|
||||
const std::string& abbr,
|
||||
std::uint_least8_t* index) {
|
||||
std::size_t type_index = 0;
|
||||
std::size_t abbr_index = abbreviations_.size();
|
||||
for (; type_index != transition_types_.size(); ++type_index) {
|
||||
const TransitionType& tt(transition_types_[type_index]);
|
||||
const char* tt_abbr = &abbreviations_[tt.abbr_index];
|
||||
if (tt_abbr == abbr) abbr_index = tt.abbr_index;
|
||||
if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
|
||||
if (abbr_index == tt.abbr_index) break; // reuse
|
||||
}
|
||||
}
|
||||
if (type_index > 255 || abbr_index > 255) {
|
||||
// No index space (8 bits) available for a new type or abbreviation.
|
||||
return false;
|
||||
}
|
||||
if (type_index == transition_types_.size()) {
|
||||
TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
|
||||
tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
|
||||
tt.is_dst = is_dst;
|
||||
if (abbr_index == abbreviations_.size()) {
|
||||
abbreviations_.append(abbr);
|
||||
abbreviations_.append(1, '\0');
|
||||
}
|
||||
tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
|
||||
}
|
||||
*index = static_cast<std::uint_least8_t>(type_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use the POSIX-TZ-environment-variable-style string to handle times
|
||||
// in years after the last transition stored in the zoneinfo data.
|
||||
void TimeZoneInfo::ExtendTransitions(const std::string& name,
|
||||
const Header& hdr) {
|
||||
bool TimeZoneInfo::ExtendTransitions() {
|
||||
extended_ = false;
|
||||
bool extending = !future_spec_.empty();
|
||||
if (future_spec_.empty()) return true; // last transition prevails
|
||||
|
||||
PosixTimeZone posix;
|
||||
if (extending && !ParsePosixSpec(future_spec_, &posix)) {
|
||||
std::clog << name << ": Failed to parse '" << future_spec_ << "'\n";
|
||||
extending = false;
|
||||
if (!ParsePosixSpec(future_spec_, &posix)) return false;
|
||||
|
||||
// Find transition type for the future std specification.
|
||||
std::uint_least8_t std_ti;
|
||||
if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
|
||||
return false;
|
||||
|
||||
if (posix.dst_abbr.empty()) { // std only
|
||||
// The future specification should match the last transition, and
|
||||
// that means that handling the future will fall out naturally.
|
||||
return EquivTransitions(transitions_.back().type_index, std_ti);
|
||||
}
|
||||
|
||||
if (extending && posix.dst_abbr.empty()) { // std only
|
||||
// The future specification should match the last/default transition,
|
||||
// and that means that handling the future will fall out naturally.
|
||||
std::uint_fast8_t index = default_transition_type_;
|
||||
if (hdr.timecnt != 0) index = transitions_[hdr.timecnt - 1].type_index;
|
||||
const TransitionType& tt(transition_types_[index]);
|
||||
CheckTransition(name, tt, posix.std_offset, false, posix.std_abbr);
|
||||
extending = false;
|
||||
}
|
||||
|
||||
if (extending && hdr.timecnt < 2) {
|
||||
std::clog << name << ": Too few transitions for POSIX spec\n";
|
||||
extending = false;
|
||||
}
|
||||
|
||||
if (!extending) {
|
||||
// Ensure that there is always a transition in the second half of the
|
||||
// time line (the BIG_BANG transition is in the first half) so that the
|
||||
// signed difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
const Transition& last(transitions_.back());
|
||||
if (last.unix_time < 0) {
|
||||
const std::uint_fast8_t type_index = last.type_index;
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
|
||||
tr.type_index = type_index;
|
||||
}
|
||||
return; // last transition wins
|
||||
}
|
||||
// Find transition type for the future dst specification.
|
||||
std::uint_least8_t dst_ti;
|
||||
if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
|
||||
return false;
|
||||
|
||||
// Extend the transitions for an additional 400 years using the
|
||||
// future specification. Years beyond those can be handled by
|
||||
// mapping back to a cycle-equivalent year within that range.
|
||||
// zic(8) should probably do this so that we don't have to.
|
||||
// TODO: Reduce the extension by the number of compatible
|
||||
// transitions already in place.
|
||||
transitions_.reserve(hdr.timecnt + 400 * 2 + 1);
|
||||
transitions_.resize(hdr.timecnt + 400 * 2);
|
||||
// We may need two additional transitions for the current year.
|
||||
transitions_.reserve(transitions_.size() + 400 * 2 + 2);
|
||||
extended_ = true;
|
||||
|
||||
// The future specification should match the last two transitions,
|
||||
// and those transitions should have different is_dst flags. Note
|
||||
// that nothing says the UTC offset used by the is_dst transition
|
||||
// must be greater than that used by the !is_dst transition. (See
|
||||
// Europe/Dublin, for example.)
|
||||
const Transition* tr0 = &transitions_[hdr.timecnt - 1];
|
||||
const Transition* tr1 = &transitions_[hdr.timecnt - 2];
|
||||
const TransitionType* tt0 = &transition_types_[tr0->type_index];
|
||||
const TransitionType* tt1 = &transition_types_[tr1->type_index];
|
||||
const TransitionType& dst(tt0->is_dst ? *tt0 : *tt1);
|
||||
const TransitionType& std(tt0->is_dst ? *tt1 : *tt0);
|
||||
CheckTransition(name, dst, posix.dst_offset, true, posix.dst_abbr);
|
||||
CheckTransition(name, std, posix.std_offset, false, posix.std_abbr);
|
||||
|
||||
// Add the transitions to tr1 and back to tr0 for each extra year.
|
||||
last_year_ = LocalTime(tr0->unix_time, *tt0).cs.year();
|
||||
const Transition& last(transitions_.back());
|
||||
const std::int_fast64_t last_time = last.unix_time;
|
||||
const TransitionType& last_tt(transition_types_[last.type_index]);
|
||||
last_year_ = LocalTime(last_time, last_tt).cs.year();
|
||||
bool leap_year = IsLeap(last_year_);
|
||||
const civil_day jan1(last_year_, 1, 1);
|
||||
std::int_fast64_t jan1_time = civil_second(jan1) - civil_second();
|
||||
int jan1_weekday = (static_cast<int>(get_weekday(jan1)) + 1) % 7;
|
||||
Transition* tr = &transitions_[hdr.timecnt]; // next trans to fill
|
||||
if (LocalTime(tr1->unix_time, *tt1).cs.year() != last_year_) {
|
||||
// Add a single extra transition to align to a calendar year.
|
||||
transitions_.resize(transitions_.size() + 1);
|
||||
assert(tr == &transitions_[hdr.timecnt]); // no reallocation
|
||||
const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
|
||||
std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
|
||||
tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
|
||||
tr++->type_index = tr1->type_index;
|
||||
tr0 = &transitions_[hdr.timecnt];
|
||||
tr1 = &transitions_[hdr.timecnt - 1];
|
||||
tt0 = &transition_types_[tr0->type_index];
|
||||
tt1 = &transition_types_[tr1->type_index];
|
||||
}
|
||||
const PosixTransition& pt1(tt0->is_dst ? posix.dst_end : posix.dst_start);
|
||||
const PosixTransition& pt0(tt0->is_dst ? posix.dst_start : posix.dst_end);
|
||||
for (const year_t limit = last_year_ + 400; last_year_ < limit;) {
|
||||
last_year_ += 1; // an additional year of generated transitions
|
||||
const civil_second jan1(last_year_);
|
||||
std::int_fast64_t jan1_time = jan1 - civil_second();
|
||||
int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
|
||||
|
||||
Transition dst = {0, dst_ti, civil_second(), civil_second()};
|
||||
Transition std = {0, std_ti, civil_second(), civil_second()};
|
||||
for (const year_t limit = last_year_ + 400;; ++last_year_) {
|
||||
auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
|
||||
auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
|
||||
dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
|
||||
std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
|
||||
const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
|
||||
const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
|
||||
if (last_time < tb->unix_time) {
|
||||
if (last_time < ta->unix_time) transitions_.push_back(*ta);
|
||||
transitions_.push_back(*tb);
|
||||
}
|
||||
if (last_year_ == limit) break;
|
||||
jan1_time += kSecsPerYear[leap_year];
|
||||
jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
|
||||
leap_year = !leap_year && IsLeap(last_year_);
|
||||
std::int_fast64_t tr1_offset = TransOffset(leap_year, jan1_weekday, pt1);
|
||||
tr->unix_time = jan1_time + tr1_offset - tt0->utc_offset;
|
||||
tr++->type_index = tr1->type_index;
|
||||
std::int_fast64_t tr0_offset = TransOffset(leap_year, jan1_weekday, pt0);
|
||||
tr->unix_time = jan1_time + tr0_offset - tt1->utc_offset;
|
||||
tr++->type_index = tr0->type_index;
|
||||
leap_year = !leap_year && IsLeap(last_year_ + 1);
|
||||
}
|
||||
assert(tr == &transitions_[0] + transitions_.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
|
||||
// Read and validate the header.
|
||||
tzhead tzh;
|
||||
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
|
||||
|
|
@ -430,7 +425,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
const char* bp = tbuf.data();
|
||||
|
||||
// Decode and validate the transitions.
|
||||
transitions_.reserve(hdr.timecnt + 2); // We might add a couple.
|
||||
transitions_.reserve(hdr.timecnt + 2);
|
||||
transitions_.resize(hdr.timecnt);
|
||||
for (std::size_t i = 0; i != hdr.timecnt; ++i) {
|
||||
transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
|
||||
|
|
@ -449,6 +444,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
}
|
||||
|
||||
// Decode and validate the transition types.
|
||||
transition_types_.reserve(hdr.typecnt + 2);
|
||||
transition_types_.resize(hdr.typecnt);
|
||||
for (std::size_t i = 0; i != hdr.typecnt; ++i) {
|
||||
transition_types_[i].utc_offset =
|
||||
|
|
@ -475,6 +471,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
}
|
||||
|
||||
// Copy all the abbreviations.
|
||||
abbreviations_.reserve(hdr.charcnt + 10);
|
||||
abbreviations_.assign(bp, hdr.charcnt);
|
||||
bp += hdr.charcnt;
|
||||
|
||||
|
|
@ -525,19 +522,29 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
transitions_.resize(hdr.timecnt);
|
||||
|
||||
// Ensure that there is always a transition in the first half of the
|
||||
// time line (the second half is handled in ExtendTransitions()) so that
|
||||
// the signed difference between a civil_second and the civil_second of
|
||||
// its previous transition is always representable, without overflow.
|
||||
// A contemporary zic will usually have already done this for us.
|
||||
// time line (the second half is handled below) so that the signed
|
||||
// difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
if (transitions_.empty() || transitions_.front().unix_time >= 0) {
|
||||
Transition& tr(*transitions_.emplace(transitions_.begin()));
|
||||
tr.unix_time = -(1LL << 59); // see tz/zic.c "BIG_BANG"
|
||||
tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
|
||||
tr.type_index = default_transition_type_;
|
||||
hdr.timecnt += 1;
|
||||
}
|
||||
|
||||
// Extend the transitions using the future specification.
|
||||
ExtendTransitions(name, hdr);
|
||||
if (!ExtendTransitions()) return false;
|
||||
|
||||
// Ensure that there is always a transition in the second half of the
|
||||
// time line (the first half is handled above) so that the signed
|
||||
// difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
const Transition& last(transitions_.back());
|
||||
if (last.unix_time < 0) {
|
||||
const std::uint_fast8_t type_index = last.type_index;
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
|
||||
tr.type_index = type_index;
|
||||
}
|
||||
|
||||
// Compute the local civil time for each transition and the preceding
|
||||
// second. These will be used for reverse conversions in MakeTime().
|
||||
|
|
@ -718,12 +725,12 @@ bool TimeZoneInfo::Load(const std::string& name) {
|
|||
|
||||
// Find and use a ZoneInfoSource to load the named zone.
|
||||
auto zip = cctz_extension::zone_info_source_factory(
|
||||
name, [](const std::string& name) -> std::unique_ptr<ZoneInfoSource> {
|
||||
if (auto zip = FileZoneInfoSource::Open(name)) return zip;
|
||||
if (auto zip = AndroidZoneInfoSource::Open(name)) return zip;
|
||||
name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
|
||||
if (auto z = FileZoneInfoSource::Open(n)) return z;
|
||||
if (auto z = AndroidZoneInfoSource::Open(n)) return z;
|
||||
return nullptr;
|
||||
});
|
||||
return zip != nullptr && Load(name, zip.get());
|
||||
return zip != nullptr && Load(zip.get());
|
||||
}
|
||||
|
||||
// BreakTime() translation for a particular transition type.
|
||||
|
|
@ -897,8 +904,8 @@ bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
|
|||
const Transition* begin = &transitions_[0];
|
||||
const Transition* end = begin + transitions_.size();
|
||||
if (begin->unix_time <= -(1LL << 59)) {
|
||||
// Do not report the BIG_BANG found in recent zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See tz/zic.c.
|
||||
// Do not report the BIG_BANG found in some zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See pre-2018f tz/zic.c.
|
||||
++begin;
|
||||
}
|
||||
std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
||||
|
|
@ -923,8 +930,8 @@ bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
|
|||
const Transition* begin = &transitions_[0];
|
||||
const Transition* end = begin + transitions_.size();
|
||||
if (begin->unix_time <= -(1LL << 59)) {
|
||||
// Do not report the BIG_BANG found in recent zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See tz/zic.c.
|
||||
// Do not report the BIG_BANG found in some zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See pre-2018f tz/zic.c.
|
||||
++begin;
|
||||
}
|
||||
std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
||||
|
|
|
|||
|
|
@ -95,15 +95,14 @@ class TimeZoneInfo : public TimeZoneIf {
|
|||
std::size_t DataLength(std::size_t time_len) const;
|
||||
};
|
||||
|
||||
void CheckTransition(const std::string& name, const TransitionType& tt,
|
||||
std::int_fast32_t offset, bool is_dst,
|
||||
const std::string& abbr) const;
|
||||
bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
|
||||
const std::string& abbr, std::uint_least8_t* index);
|
||||
bool EquivTransitions(std::uint_fast8_t tt1_index,
|
||||
std::uint_fast8_t tt2_index) const;
|
||||
void ExtendTransitions(const std::string& name, const Header& hdr);
|
||||
bool ExtendTransitions();
|
||||
|
||||
bool ResetToBuiltinUTC(const seconds& offset);
|
||||
bool Load(const std::string& name, ZoneInfoSource* zip);
|
||||
bool Load(ZoneInfoSource* zip);
|
||||
|
||||
// Helpers for BreakTime() and MakeTime().
|
||||
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@
|
|||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
#if defined(_AIX)
|
||||
extern "C" {
|
||||
extern long altzone;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
|
|
@ -44,7 +50,7 @@ auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
|
|||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return _tzname[is_dst];
|
||||
}
|
||||
#elif defined(__sun)
|
||||
#elif defined(__sun) || defined(_AIX)
|
||||
// Uses the globals: 'timezone', 'altzone' and 'tzname'.
|
||||
auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
|
|
@ -153,7 +159,8 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
|
|||
std::tm tm;
|
||||
while (lo + 1 != hi) {
|
||||
const std::time_t mid = lo + (hi - lo) / 2;
|
||||
if (std::tm* tmp = local_time(&mid, &tm)) {
|
||||
std::tm* tmp = local_time(&mid, &tm);
|
||||
if (tmp != nullptr) {
|
||||
if (tm_gmtoff(*tmp) == offset) {
|
||||
hi = mid;
|
||||
} else {
|
||||
|
|
@ -163,7 +170,8 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
|
|||
// If std::tm cannot hold some result we resort to a linear search,
|
||||
// ignoring all failed conversions. Slow, but never really happens.
|
||||
while (++lo != hi) {
|
||||
if (std::tm* tmp = local_time(&lo, &tm)) {
|
||||
tmp = local_time(&lo, &tm);
|
||||
if (tmp != nullptr) {
|
||||
if (tm_gmtoff(*tmp) == offset) break;
|
||||
}
|
||||
}
|
||||
|
|
@ -223,11 +231,10 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
|
|||
civil_second() + ToUnixSeconds(time_point<seconds>::min());
|
||||
static const civil_second max_tp_cs =
|
||||
civil_second() + ToUnixSeconds(time_point<seconds>::max());
|
||||
const time_point<seconds> tp =
|
||||
(cs < min_tp_cs)
|
||||
? time_point<seconds>::min()
|
||||
: (cs > max_tp_cs) ? time_point<seconds>::max()
|
||||
: FromUnixSeconds(cs - civil_second());
|
||||
const time_point<seconds> tp = (cs < min_tp_cs) ? time_point<seconds>::min()
|
||||
: (cs > max_tp_cs)
|
||||
? time_point<seconds>::max()
|
||||
: FromUnixSeconds(cs - civil_second());
|
||||
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1004,13 +1004,17 @@ TEST(MakeTime, SysSecondsLimits) {
|
|||
#if defined(_WIN32) || defined(_WIN64)
|
||||
// localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
|
||||
#else
|
||||
const time_zone utc = LoadZone("libc:UTC");
|
||||
const time_zone cut = LoadZone("libc:UTC");
|
||||
const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
|
||||
tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), utc);
|
||||
EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, utc));
|
||||
tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
// The BSD gmtime_r() fails on extreme positive tm_year values.
|
||||
#else
|
||||
EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
|
||||
#endif
|
||||
const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
|
||||
tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), utc);
|
||||
EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, utc));
|
||||
tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
|
||||
EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2020a
|
||||
2020d
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue