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
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue