mirror of
https://github.com/abseil/abseil-cpp.git
synced 2026-06-04 20:14:23 +08:00
Import of CCTZ from GitHub.
PiperOrigin-RevId: 538241594 Change-Id: Ie6f0d913bcf07dea2f33e47198ba952b3800d70e
This commit is contained in:
committed by
Copybara-Service
parent
66406fdf15
commit
1285ca4b4f
@@ -26,6 +26,8 @@ namespace cctz {
|
||||
std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
|
||||
// Support "libc:localtime" and "libc:*" to access the legacy
|
||||
// localtime and UTC support respectively from the C library.
|
||||
// NOTE: The "libc:*" zones are internal, test-only interfaces, and
|
||||
// are subject to change/removal without notice. Do not use them.
|
||||
if (name.compare(0, 5, "libc:") == 0) {
|
||||
return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
|
||||
}
|
||||
|
||||
@@ -125,31 +125,30 @@ inline std::tm* local_time(const std::time_t* timep, std::tm* result) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Converts a civil second and "dst" flag into a time_t and UTC offset.
|
||||
// Converts a civil second and "dst" flag into a time_t and a struct tm.
|
||||
// Returns false if time_t cannot represent the requested civil second.
|
||||
// Caller must have already checked that cs.year() will fit into a tm_year.
|
||||
bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
|
||||
std::tm tm;
|
||||
tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
|
||||
tm.tm_mon = cs.month() - 1;
|
||||
tm.tm_mday = cs.day();
|
||||
tm.tm_hour = cs.hour();
|
||||
tm.tm_min = cs.minute();
|
||||
tm.tm_sec = cs.second();
|
||||
tm.tm_isdst = is_dst;
|
||||
*t = std::mktime(&tm);
|
||||
bool make_time(const civil_second& cs, int is_dst, std::time_t* t,
|
||||
std::tm* tm) {
|
||||
tm->tm_year = static_cast<int>(cs.year() - year_t{1900});
|
||||
tm->tm_mon = cs.month() - 1;
|
||||
tm->tm_mday = cs.day();
|
||||
tm->tm_hour = cs.hour();
|
||||
tm->tm_min = cs.minute();
|
||||
tm->tm_sec = cs.second();
|
||||
tm->tm_isdst = is_dst;
|
||||
*t = std::mktime(tm);
|
||||
if (*t == std::time_t{-1}) {
|
||||
std::tm tm2;
|
||||
const std::tm* tmp = local_time(t, &tm2);
|
||||
if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
|
||||
tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
|
||||
tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
|
||||
tmp->tm_sec != tm.tm_sec) {
|
||||
if (tmp == nullptr || tmp->tm_year != tm->tm_year ||
|
||||
tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday ||
|
||||
tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min ||
|
||||
tmp->tm_sec != tm->tm_sec) {
|
||||
// A true error (not just one second before the epoch).
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*off = static_cast<int>(tm_gmtoff(tm));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -254,33 +253,37 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
|
||||
// We probe with "is_dst" values of 0 and 1 to try to distinguish unique
|
||||
// civil seconds from skipped or repeated ones. This is not always possible
|
||||
// however, as the "dst" flag does not change over some offset transitions.
|
||||
// We are also subject to the vagaries of mktime() implementations.
|
||||
// We are also subject to the vagaries of mktime() implementations. For
|
||||
// example, some implementations treat "tm_isdst" as a demand (useless),
|
||||
// and some as a disambiguator (useful).
|
||||
std::time_t t0, t1;
|
||||
int offset0, offset1;
|
||||
if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
|
||||
if (t0 == t1) {
|
||||
std::tm tm0, tm1;
|
||||
if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) {
|
||||
if (tm0.tm_isdst == tm1.tm_isdst) {
|
||||
// The civil time was singular (pre == trans == post).
|
||||
const time_point<seconds> tp = FromUnixSeconds(t0);
|
||||
const time_point<seconds> tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0);
|
||||
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
|
||||
}
|
||||
|
||||
if (t0 > t1) {
|
||||
int offset = tm_gmtoff(tm0);
|
||||
if (t0 < t1) { // negative DST
|
||||
std::swap(t0, t1);
|
||||
std::swap(offset0, offset1);
|
||||
offset = tm_gmtoff(tm1);
|
||||
}
|
||||
const std::time_t tt = find_trans(t0, t1, offset1);
|
||||
|
||||
const std::time_t tt = find_trans(t1, t0, offset);
|
||||
const time_point<seconds> trans = FromUnixSeconds(tt);
|
||||
|
||||
if (offset0 < offset1) {
|
||||
if (tm0.tm_isdst) {
|
||||
// The civil time did not exist (pre >= trans > post).
|
||||
const time_point<seconds> pre = FromUnixSeconds(t1);
|
||||
const time_point<seconds> post = FromUnixSeconds(t0);
|
||||
const time_point<seconds> pre = FromUnixSeconds(t0);
|
||||
const time_point<seconds> post = FromUnixSeconds(t1);
|
||||
return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
|
||||
}
|
||||
|
||||
// The civil time was ambiguous (pre < trans <= post).
|
||||
const time_point<seconds> pre = FromUnixSeconds(t0);
|
||||
const time_point<seconds> post = FromUnixSeconds(t1);
|
||||
const time_point<seconds> pre = FromUnixSeconds(t1);
|
||||
const time_point<seconds> post = FromUnixSeconds(t0);
|
||||
return {time_zone::civil_lookup::REPEATED, pre, trans, post};
|
||||
}
|
||||
|
||||
|
||||
@@ -1034,16 +1034,16 @@ TEST(MakeTime, SysSecondsLimits) {
|
||||
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), cut);
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
// The BSD gmtime_r() fails on extreme positive tm_year values.
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
|
||||
// Some gmtime_r() impls fail on extreme positive values.
|
||||
#else
|
||||
EXPECT_EQ("2147485547-12-31T23:59:59+00:00",
|
||||
absl::time_internal::cctz::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), cut);
|
||||
#if defined(__Fuchsia__)
|
||||
// Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527).
|
||||
#if defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
|
||||
// Some gmtime_r() impls fail on extreme negative values (fxbug.dev/78527).
|
||||
#else
|
||||
EXPECT_EQ("-2147481748-01-01T00:00:00+00:00",
|
||||
absl::time_internal::cctz::format(RFC3339, tp, cut));
|
||||
@@ -1072,7 +1072,7 @@ TEST(MakeTime, LocalTimeLibC) {
|
||||
tp = zi.lookup(transition.to).trans) {
|
||||
const auto fcl = zi.lookup(transition.from);
|
||||
const auto tcl = zi.lookup(transition.to);
|
||||
civil_second cs; // compare cs in zi and lc
|
||||
civil_second cs, us; // compare cs and us in zi and lc
|
||||
if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
|
||||
if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
|
||||
// Both unique; must be an is_dst or abbr change.
|
||||
@@ -1088,12 +1088,14 @@ TEST(MakeTime, LocalTimeLibC) {
|
||||
}
|
||||
ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
|
||||
cs = transition.to;
|
||||
us = transition.from;
|
||||
} else {
|
||||
ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
|
||||
ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
|
||||
cs = transition.from;
|
||||
us = transition.to;
|
||||
}
|
||||
if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
|
||||
if (us.year() > 2037) break; // limit test time (and to 32-bit time_t)
|
||||
const auto cl_zi = zi.lookup(cs);
|
||||
if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
|
||||
// The "libc" implementation cannot correctly classify transitions
|
||||
@@ -1125,6 +1127,13 @@ TEST(MakeTime, LocalTimeLibC) {
|
||||
EXPECT_EQ(cl_zi.pre, cl_lc.pre);
|
||||
EXPECT_EQ(cl_zi.trans, cl_lc.trans);
|
||||
EXPECT_EQ(cl_zi.post, cl_lc.post);
|
||||
const auto ucl_zi = zi.lookup(us);
|
||||
const auto ucl_lc = lc.lookup(us);
|
||||
SCOPED_TRACE(testing::Message() << "For " << us << " in " << *np);
|
||||
EXPECT_EQ(ucl_zi.kind, ucl_lc.kind);
|
||||
EXPECT_EQ(ucl_zi.pre, ucl_lc.pre);
|
||||
EXPECT_EQ(ucl_zi.trans, ucl_lc.trans);
|
||||
EXPECT_EQ(ucl_zi.post, ucl_lc.post);
|
||||
}
|
||||
}
|
||||
if (ep == nullptr) {
|
||||
|
||||
Reference in New Issue
Block a user