Export of internal Abseil changes.

--
f4e870453d02106c2685e0461816469a4704ad25 by Abseil Team <absl-team@google.com>:

Expose TimeZone::NextTransition() and PrevTransition() now that
we have absl::CivilSecond support in time.h.  Note that these are
for informational purposes only.  General time code should not
care when offset changes occur.

PiperOrigin-RevId: 217177292

--
cfadd275c7333f7c27c4d682b9d167010d874e69 by Abseil Team <absl-team@google.com>:

Import of CCTZ from GitHub.

PiperOrigin-RevId: 217153577

--
6ff5b8c61a1239b9c0478a7c62bcd2844b310307 by Jon Cohen <cohenjon@google.com>:

Fix code examples in hash_testing.h.  Includes random clang-format changes.

PiperOrigin-RevId: 216898995

--
de124129d27f4627dabe193a10bf106a11783fba by Shaindel Schwartz <shaindel@google.com>:

Add contribution guidelines describing how we decide whether to include an API in Abseil.

PiperOrigin-RevId: 216886943
GitOrigin-RevId: f4e870453d02106c2685e0461816469a4704ad25
Change-Id: Ib9c6706f5bf931b71c0357bf1342053a3bee8ff7
This commit is contained in:
Abseil Team 2018-10-15 11:30:24 -07:00 committed by Xiaoyi Zhang
parent a00bdd176d
commit 5b70a8910b
6 changed files with 193 additions and 19 deletions

View file

@ -90,7 +90,7 @@ namespace absl {
// template <typename H>
// friend H AbslHashValue(H state, Bad2 x) {
// // Uses a and b.
// return H::combine(x.a, x.b);
// return H::combine(std::move(state), x.a, x.b);
// }
// friend bool operator==(Bad2 x, Bad2 y) {
// // Only uses a.
@ -107,7 +107,7 @@ namespace absl {
// template <typename H>
// friend H AbslHashValue(H state, Bad3 x) {
// // Only uses a.
// return H::combine(x.a);
// return H::combine(std::move(state), x.a);
// }
// friend bool operator==(Bad3 x, Bad3 y) {
// // Uses a and b.
@ -123,19 +123,21 @@ namespace absl {
// int *p, size;
// template <typename H>
// friend H AbslHashValue(H state, Bad4 x) {
// return H::combine_range(x.p, x.p + x.size);
// return H::combine_contiguous(std::move(state), x.p, x.p + x.size);
// }
// friend bool operator==(Bad4 x, Bad4 y) {
// return std::equal(x.p, x.p + x.size, y.p, y.p + y.size);
// // Compare two ranges for equality. C++14 code can instead use std::equal.
// return absl::equal(x.p, x.p + x.size, y.p, y.p + y.size);
// }
// };
//
// An easy solution to this is to combine the size after combining the range,
// like so:
// template <typename H>
// friend H AbslHashValue(H state, Bad4 x) {
// return H::combine(H::combine_range(x.p, x.p + x.size), x.size);
// }
// template <typename H>
// friend H AbslHashValue(H state, Bad4 x) {
// return H::combine(
// H::combine_contiguous(std::move(state), x.p, x.p + x.size), x.size);
// }
//
template <int&... ExplicitBarrier, typename Container>
ABSL_MUST_USE_RESULT testing::AssertionResult
@ -227,7 +229,8 @@ VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
// Now we verify that AbslHashValue is also correctly implemented.
for (const auto& c : classes) {
// All elements of the equivalence class must have the same hash expansion.
// All elements of the equivalence class must have the same hash
// expansion.
const SpyHashState expected = c[0].expand();
for (const Info& v : c) {
if (v.expand() != v.expand()) {
@ -285,7 +288,7 @@ struct TypeSet {
};
template <typename... T>
struct MakeTypeSet : TypeSet<>{};
struct MakeTypeSet : TypeSet<> {};
template <typename T, typename... Ts>
struct MakeTypeSet<T, Ts...> : MakeTypeSet<Ts...>::template Insert<T>::type {};
@ -346,8 +349,7 @@ template <int&..., typename Container, typename Eq>
ABSL_MUST_USE_RESULT testing::AssertionResult
VerifyTypeImplementsAbslHashCorrectly(const Container& values, Eq equals) {
return hash_internal::VerifyTypeImplementsAbslHashCorrectly(
hash_internal::ContainerAsVector<Container>::Do(values),
equals);
hash_internal::ContainerAsVector<Container>::Do(values), equals);
}
template <int&..., typename T>

View file

@ -991,15 +991,17 @@ TEST(MakeTime, SysSecondsLimits) {
tp = convert(civil_second::min(), west);
EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp);
// Checks that "tm_year + 1900", as used by the "libc" implementation,
// can produce year values beyond the range on an int without overflow.
if (sizeof(std::time_t) >= 8) {
// Checks that "tm_year + 1900", as used by the "libc" implementation,
// can produce year values beyond the range on an int without overflow.
#if defined(_WIN32) || defined(_WIN64)
// localtime_s() and gmtime_s() don't believe in years past 3000.
// localtime_s() and gmtime_s() don't believe in years past 3000.
#else
const time_zone libc_utc = LoadZone("libc:UTC");
tp = convert(civil_year(year_t{2147483648}), libc_utc);
EXPECT_EQ("2147483648-01-01T00:00:00+00:00", format(RFC3339, tp, libc_utc));
const time_zone libc_utc = LoadZone("libc:UTC");
tp = convert(civil_year(year_t{2147483648}), libc_utc);
EXPECT_EQ("2147483648-01-01T00:00:00+00:00", format(RFC3339, tp, libc_utc));
#endif
}
}
TEST(NextTransition, UTC) {

View file

@ -176,6 +176,20 @@ inline int MapWeekday(const cctz::weekday& wd) {
return 1;
}
bool FindTransition(const cctz::time_zone& tz,
bool (cctz::time_zone::*find_transition)(
const cctz::time_point<cctz::seconds>& tp,
cctz::time_zone::civil_transition* trans) const,
Time t, TimeZone::CivilTransition* trans) {
// Transitions are second-aligned, so we can discard any fractional part.
const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
cctz::time_zone::civil_transition tr;
if (!(tz.*find_transition)(tp, &tr)) return false;
trans->from = CivilSecond(tr.from);
trans->to = CivilSecond(tr.to);
return true;
}
} // namespace
//
@ -366,6 +380,14 @@ absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
return ti;
}
bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
}
bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
}
//
// Conversions involving time zones.
//

View file

@ -886,7 +886,7 @@ class TimeZone {
struct TimeInfo {
enum CivilKind {
UNIQUE, // the civil time was singular (pre == trans == post)
SKIPPED, // the civil time did not exist (pre => trans > post)
SKIPPED, // the civil time did not exist (pre >= trans > post)
REPEATED, // the civil time was ambiguous (pre < trans <= post)
} kind;
Time pre; // time calculated using the pre-transition offset
@ -925,6 +925,44 @@ class TimeZone {
// // nov06.post is 2011-11-06 01:15:00 -0800
TimeInfo At(CivilSecond ct) const;
// TimeZone::NextTransition()
// TimeZone::PrevTransition()
//
// Finds the time of the next/previous offset change in this time zone.
//
// By definition, `NextTransition(t, &trans)` returns false when `t` is
// `InfiniteFuture()`, and `PrevTransition(t, &trans)` returns false
// when `t` is `InfinitePast()`. If the zone has no transitions, the
// result will also be false no matter what the argument.
//
// Otherwise, when `t` is `InfinitePast()`, `NextTransition(t, &trans)`
// returns true and sets `trans` to the first recorded transition. Chains
// of calls to `NextTransition()/PrevTransition()` will eventually return
// false, but it is unspecified exactly when `NextTransition(t, &trans)`
// jumps to false, or what time is set by `PrevTransition(t, &trans)` for
// a very distant `t`.
//
// Note: Enumeration of time-zone transitions is for informational purposes
// only. Modern time-related code should not care about when offset changes
// occur.
//
// Example:
// absl::TimeZone nyc;
// if (!absl::LoadTimeZone("America/New_York", &nyc)) { ... }
// const auto now = absl::Now();
// auto t = absl::InfinitePast();
// absl::TimeZone::CivilTransition trans;
// while (t <= now && nyc.NextTransition(t, &trans)) {
// // transition: trans.from -> trans.to
// t = nyc.At(trans.to).trans;
// }
struct CivilTransition {
CivilSecond from; // the civil time we jump from
CivilSecond to; // the civil time we jump to
};
bool NextTransition(Time t, CivilTransition* trans) const;
bool PrevTransition(Time t, CivilTransition* trans) const;
template <typename H>
friend H AbslHashValue(H h, TimeZone tz) {
return H::combine(std::move(h), tz.cz_);

View file

@ -1135,4 +1135,67 @@ TEST(Time, LegacyDateTime) {
EXPECT_EQ("2014-10-29 22:58:59", absl::FormatTime(ymdhms, t, utc));
}
TEST(Time, NextTransitionUTC) {
const auto tz = absl::UTCTimeZone();
absl::TimeZone::CivilTransition trans;
auto t = absl::InfinitePast();
EXPECT_FALSE(tz.NextTransition(t, &trans));
t = absl::InfiniteFuture();
EXPECT_FALSE(tz.NextTransition(t, &trans));
}
TEST(Time, PrevTransitionUTC) {
const auto tz = absl::UTCTimeZone();
absl::TimeZone::CivilTransition trans;
auto t = absl::InfiniteFuture();
EXPECT_FALSE(tz.PrevTransition(t, &trans));
t = absl::InfinitePast();
EXPECT_FALSE(tz.PrevTransition(t, &trans));
}
TEST(Time, NextTransitionNYC) {
const auto tz = absl::time_internal::LoadTimeZone("America/New_York");
absl::TimeZone::CivilTransition trans;
auto t = absl::FromCivil(absl::CivilSecond(2018, 6, 30, 0, 0, 0), tz);
EXPECT_TRUE(tz.NextTransition(t, &trans));
EXPECT_EQ(absl::CivilSecond(2018, 11, 4, 2, 0, 0), trans.from);
EXPECT_EQ(absl::CivilSecond(2018, 11, 4, 1, 0, 0), trans.to);
t = absl::InfiniteFuture();
EXPECT_FALSE(tz.NextTransition(t, &trans));
t = absl::InfinitePast();
EXPECT_TRUE(tz.NextTransition(t, &trans));
if (trans.from == absl::CivilSecond(1918, 03, 31, 2, 0, 0)) {
// It looks like the tzdata is only 32 bit (probably macOS),
// which bottoms out at 1901-12-13T20:45:52+00:00.
EXPECT_EQ(absl::CivilSecond(1918, 3, 31, 3, 0, 0), trans.to);
} else {
EXPECT_EQ(absl::CivilSecond(1883, 11, 18, 12, 3, 58), trans.from);
EXPECT_EQ(absl::CivilSecond(1883, 11, 18, 12, 0, 0), trans.to);
}
}
TEST(Time, PrevTransitionNYC) {
const auto tz = absl::time_internal::LoadTimeZone("America/New_York");
absl::TimeZone::CivilTransition trans;
auto t = absl::FromCivil(absl::CivilSecond(2018, 6, 30, 0, 0, 0), tz);
EXPECT_TRUE(tz.PrevTransition(t, &trans));
EXPECT_EQ(absl::CivilSecond(2018, 3, 11, 2, 0, 0), trans.from);
EXPECT_EQ(absl::CivilSecond(2018, 3, 11, 3, 0, 0), trans.to);
t = absl::InfinitePast();
EXPECT_FALSE(tz.PrevTransition(t, &trans));
t = absl::InfiniteFuture();
EXPECT_TRUE(tz.PrevTransition(t, &trans));
// We have a transition but we don't know which one.
}
} // namespace