diff options
Diffstat (limited to 'third_party/abseil_cpp/absl/time')
651 files changed, 23032 insertions, 0 deletions
diff --git a/third_party/abseil_cpp/absl/time/BUILD.bazel b/third_party/abseil_cpp/absl/time/BUILD.bazel new file mode 100644 index 000000000000..991241a0df5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/BUILD.bazel @@ -0,0 +1,125 @@ +# +# Copyright 2017 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") +load( + "//absl:copts/configure_copts.bzl", + "ABSL_DEFAULT_COPTS", + "ABSL_DEFAULT_LINKOPTS", + "ABSL_TEST_COPTS", +) + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +cc_library( + name = "time", + srcs = [ + "civil_time.cc", + "clock.cc", + "duration.cc", + "format.cc", + "internal/get_current_time_chrono.inc", + "internal/get_current_time_posix.inc", + "time.cc", + ], + hdrs = [ + "civil_time.h", + "clock.h", + "time.h", + ], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + "//absl/base", + "//absl/base:core_headers", + "//absl/base:raw_logging_internal", + "//absl/numeric:int128", + "//absl/strings", + "//absl/time/internal/cctz:civil_time", + "//absl/time/internal/cctz:time_zone", + ], +) + +cc_library( + name = "test_util", + testonly = 1, + srcs = [ + "internal/test_util.cc", + "internal/zoneinfo.inc", + ], + hdrs = ["internal/test_util.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = [ + "//absl/time:__pkg__", + ], + deps = [ + ":time", + "//absl/base:config", + "//absl/base:raw_logging_internal", + "//absl/time/internal/cctz:time_zone", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "time_test", + srcs = [ + "civil_time_test.cc", + "clock_test.cc", + "duration_test.cc", + "format_test.cc", + "time_test.cc", + "time_zone_test.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":test_util", + ":time", + "//absl/base:config", + "//absl/base:core_headers", + "//absl/numeric:int128", + "//absl/time/internal/cctz:time_zone", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "time_benchmark", + srcs = [ + "civil_time_benchmark.cc", + "clock_benchmark.cc", + "duration_benchmark.cc", + "format_benchmark.cc", + "time_benchmark.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + tags = [ + "benchmark", + ], + deps = [ + ":test_util", + ":time", + "//absl/base", + "//absl/base:core_headers", + "//absl/hash", + "@com_github_google_benchmark//:benchmark_main", + ], +) diff --git a/third_party/abseil_cpp/absl/time/CMakeLists.txt b/third_party/abseil_cpp/absl/time/CMakeLists.txt new file mode 100644 index 000000000000..00bdd499c1f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/CMakeLists.txt @@ -0,0 +1,128 @@ +# +# Copyright 2017 The Abseil Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +absl_cc_library( + NAME + time + HDRS + "civil_time.h" + "clock.h" + "time.h" + SRCS + "civil_time.cc" + "clock.cc" + "duration.cc" + "format.cc" + "internal/get_current_time_chrono.inc" + "internal/get_current_time_posix.inc" + "time.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::base + absl::civil_time + absl::core_headers + absl::int128 + absl::raw_logging_internal + absl::strings + absl::time_zone + PUBLIC +) + +absl_cc_library( + NAME + civil_time + HDRS + "internal/cctz/include/cctz/civil_time.h" + "internal/cctz/include/cctz/civil_time_detail.h" + SRCS + "internal/cctz/src/civil_time_detail.cc" + COPTS + ${ABSL_DEFAULT_COPTS} +) + +if(APPLE) + find_library(CoreFoundation CoreFoundation) +endif() + +absl_cc_library( + NAME + time_zone + HDRS + "internal/cctz/include/cctz/time_zone.h" + "internal/cctz/include/cctz/zone_info_source.h" + SRCS + "internal/cctz/src/time_zone_fixed.cc" + "internal/cctz/src/time_zone_fixed.h" + "internal/cctz/src/time_zone_format.cc" + "internal/cctz/src/time_zone_if.cc" + "internal/cctz/src/time_zone_if.h" + "internal/cctz/src/time_zone_impl.cc" + "internal/cctz/src/time_zone_impl.h" + "internal/cctz/src/time_zone_info.cc" + "internal/cctz/src/time_zone_info.h" + "internal/cctz/src/time_zone_libc.cc" + "internal/cctz/src/time_zone_libc.h" + "internal/cctz/src/time_zone_lookup.cc" + "internal/cctz/src/time_zone_posix.cc" + "internal/cctz/src/time_zone_posix.h" + "internal/cctz/src/tzfile.h" + "internal/cctz/src/zone_info_source.cc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + $<$<PLATFORM_ID:Darwin>:${CoreFoundation}> +) + +absl_cc_library( + NAME + time_internal_test_util + HDRS + "internal/test_util.h" + SRCS + "internal/test_util.cc" + "internal/zoneinfo.inc" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::time + absl::config + absl::raw_logging_internal + absl::time_zone + gmock + TESTONLY +) + +absl_cc_test( + NAME + time_test + SRCS + "civil_time_test.cc" + "clock_test.cc" + "duration_test.cc" + "format_test.cc" + "time_test.cc" + "time_zone_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::time_internal_test_util + absl::time + absl::config + absl::core_headers + absl::time_zone + gmock_main +) diff --git a/third_party/abseil_cpp/absl/time/civil_time.cc b/third_party/abseil_cpp/absl/time/civil_time.cc new file mode 100644 index 000000000000..bdfe9ce0efb3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/civil_time.cc @@ -0,0 +1,175 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/civil_time.h" + +#include <cstdlib> +#include <string> + +#include "absl/strings/str_cat.h" +#include "absl/time/time.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace { + +// Since a civil time has a larger year range than absl::Time (64-bit years vs +// 64-bit seconds, respectively) we normalize years to roughly +/- 400 years +// around the year 2400, which will produce an equivalent year in a range that +// absl::Time can handle. +inline civil_year_t NormalizeYear(civil_year_t year) { + return 2400 + year % 400; +} + +// Formats the given CivilSecond according to the given format. +std::string FormatYearAnd(string_view fmt, CivilSecond cs) { + const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(), + cs.hour(), cs.minute(), cs.second()); + const TimeZone utc = UTCTimeZone(); + // TODO(absl-team): Avoid conversion of fmt string. + return StrCat(cs.year(), + FormatTime(std::string(fmt), FromCivil(ncs, utc), utc)); +} + +template <typename CivilT> +bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) { + // Civil times support a larger year range than absl::Time, so we need to + // parse the year separately, normalize it, then use absl::ParseTime on the + // normalized string. + const std::string ss = std::string(s); // TODO(absl-team): Avoid conversion. + const char* const np = ss.c_str(); + char* endp; + errno = 0; + const civil_year_t y = + std::strtoll(np, &endp, 10); // NOLINT(runtime/deprecated_fn) + if (endp == np || errno == ERANGE) return false; + const std::string norm = StrCat(NormalizeYear(y), endp); + + const TimeZone utc = UTCTimeZone(); + Time t; + if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) { + const auto cs = ToCivilSecond(t, utc); + *c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second()); + return true; + } + + return false; +} + +// Tries to parse the type as a CivilT1, but then assigns the result to the +// argument of type CivilT2. +template <typename CivilT1, typename CivilT2> +bool ParseAs(string_view s, CivilT2* c) { + CivilT1 t1; + if (ParseCivilTime(s, &t1)) { + *c = CivilT2(t1); + return true; + } + return false; +} + +template <typename CivilT> +bool ParseLenient(string_view s, CivilT* c) { + // A fastpath for when the given string data parses exactly into the given + // type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay). + if (ParseCivilTime(s, c)) return true; + // Try parsing as each of the 6 types, trying the most common types first + // (based on csearch results). + if (ParseAs<CivilDay>(s, c)) return true; + if (ParseAs<CivilSecond>(s, c)) return true; + if (ParseAs<CivilHour>(s, c)) return true; + if (ParseAs<CivilMonth>(s, c)) return true; + if (ParseAs<CivilMinute>(s, c)) return true; + if (ParseAs<CivilYear>(s, c)) return true; + return false; +} +} // namespace + +std::string FormatCivilTime(CivilSecond c) { + return FormatYearAnd("-%m-%d%ET%H:%M:%S", c); +} +std::string FormatCivilTime(CivilMinute c) { + return FormatYearAnd("-%m-%d%ET%H:%M", c); +} +std::string FormatCivilTime(CivilHour c) { + return FormatYearAnd("-%m-%d%ET%H", c); +} +std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); } +std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); } +std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); } + +bool ParseCivilTime(string_view s, CivilSecond* c) { + return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c); +} +bool ParseCivilTime(string_view s, CivilMinute* c) { + return ParseYearAnd("-%m-%d%ET%H:%M", s, c); +} +bool ParseCivilTime(string_view s, CivilHour* c) { + return ParseYearAnd("-%m-%d%ET%H", s, c); +} +bool ParseCivilTime(string_view s, CivilDay* c) { + return ParseYearAnd("-%m-%d", s, c); +} +bool ParseCivilTime(string_view s, CivilMonth* c) { + return ParseYearAnd("-%m", s, c); +} +bool ParseCivilTime(string_view s, CivilYear* c) { + return ParseYearAnd("", s, c); +} + +bool ParseLenientCivilTime(string_view s, CivilSecond* c) { + return ParseLenient(s, c); +} +bool ParseLenientCivilTime(string_view s, CivilMinute* c) { + return ParseLenient(s, c); +} +bool ParseLenientCivilTime(string_view s, CivilHour* c) { + return ParseLenient(s, c); +} +bool ParseLenientCivilTime(string_view s, CivilDay* c) { + return ParseLenient(s, c); +} +bool ParseLenientCivilTime(string_view s, CivilMonth* c) { + return ParseLenient(s, c); +} +bool ParseLenientCivilTime(string_view s, CivilYear* c) { + return ParseLenient(s, c); +} + +namespace time_internal { + +std::ostream& operator<<(std::ostream& os, CivilYear y) { + return os << FormatCivilTime(y); +} +std::ostream& operator<<(std::ostream& os, CivilMonth m) { + return os << FormatCivilTime(m); +} +std::ostream& operator<<(std::ostream& os, CivilDay d) { + return os << FormatCivilTime(d); +} +std::ostream& operator<<(std::ostream& os, CivilHour h) { + return os << FormatCivilTime(h); +} +std::ostream& operator<<(std::ostream& os, CivilMinute m) { + return os << FormatCivilTime(m); +} +std::ostream& operator<<(std::ostream& os, CivilSecond s) { + return os << FormatCivilTime(s); +} + +} // namespace time_internal + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/civil_time.h b/third_party/abseil_cpp/absl/time/civil_time.h new file mode 100644 index 000000000000..bb4600443445 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/civil_time.h @@ -0,0 +1,538 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: civil_time.h +// ----------------------------------------------------------------------------- +// +// This header file defines abstractions for computing with "civil time". +// The term "civil time" refers to the legally recognized human-scale time +// that is represented by the six fields `YYYY-MM-DD hh:mm:ss`. A "date" +// is perhaps the most common example of a civil time (represented here as +// an `absl::CivilDay`). +// +// Modern-day civil time follows the Gregorian Calendar and is a +// time-zone-independent concept: a civil time of "2015-06-01 12:00:00", for +// example, is not tied to a time zone. Put another way, a civil time does not +// map to a unique point in time; a civil time must be mapped to an absolute +// time *through* a time zone. +// +// Because a civil time is what most people think of as "time," it is common to +// map absolute times to civil times to present to users. +// +// Time zones define the relationship between absolute and civil times. Given an +// absolute or civil time and a time zone, you can compute the other time: +// +// Civil Time = F(Absolute Time, Time Zone) +// Absolute Time = G(Civil Time, Time Zone) +// +// The Abseil time library allows you to construct such civil times from +// absolute times; consult time.h for such functionality. +// +// This library provides six classes for constructing civil-time objects, and +// provides several helper functions for rounding, iterating, and performing +// arithmetic on civil-time objects, while avoiding complications like +// daylight-saving time (DST): +// +// * `absl::CivilSecond` +// * `absl::CivilMinute` +// * `absl::CivilHour` +// * `absl::CivilDay` +// * `absl::CivilMonth` +// * `absl::CivilYear` +// +// Example: +// +// // Construct a civil-time object for a specific day +// const absl::CivilDay cd(1969, 07, 20); +// +// // Construct a civil-time object for a specific second +// const absl::CivilSecond cd(2018, 8, 1, 12, 0, 1); +// +// Note: In C++14 and later, this library is usable in a constexpr context. +// +// Example: +// +// // Valid in C++14 +// constexpr absl::CivilDay cd(1969, 07, 20); + +#ifndef ABSL_TIME_CIVIL_TIME_H_ +#define ABSL_TIME_CIVIL_TIME_H_ + +#include <string> + +#include "absl/strings/string_view.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace time_internal { +struct second_tag : cctz::detail::second_tag {}; +struct minute_tag : second_tag, cctz::detail::minute_tag {}; +struct hour_tag : minute_tag, cctz::detail::hour_tag {}; +struct day_tag : hour_tag, cctz::detail::day_tag {}; +struct month_tag : day_tag, cctz::detail::month_tag {}; +struct year_tag : month_tag, cctz::detail::year_tag {}; +} // namespace time_internal + +// ----------------------------------------------------------------------------- +// CivilSecond, CivilMinute, CivilHour, CivilDay, CivilMonth, CivilYear +// ----------------------------------------------------------------------------- +// +// Each of these civil-time types is a simple value type with the same +// interface for construction and the same six accessors for each of the civil +// time fields (year, month, day, hour, minute, and second, aka YMDHMS). These +// classes differ only in their alignment, which is indicated by the type name +// and specifies the field on which arithmetic operates. +// +// CONSTRUCTION +// +// Each of the civil-time types can be constructed in two ways: by directly +// passing to the constructor up to six integers representing the YMDHMS fields, +// or by copying the YMDHMS fields from a differently aligned civil-time type. +// Omitted fields are assigned their minimum valid value. Hours, minutes, and +// seconds will be set to 0, month and day will be set to 1. Since there is no +// minimum year, the default is 1970. +// +// Examples: +// +// absl::CivilDay default_value; // 1970-01-01 00:00:00 +// +// absl::CivilDay a(2015, 2, 3); // 2015-02-03 00:00:00 +// absl::CivilDay b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00 +// absl::CivilDay c(2015); // 2015-01-01 00:00:00 +// +// absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06 +// absl::CivilMinute mm(ss); // 2015-02-03 04:05:00 +// absl::CivilHour hh(mm); // 2015-02-03 04:00:00 +// absl::CivilDay d(hh); // 2015-02-03 00:00:00 +// absl::CivilMonth m(d); // 2015-02-01 00:00:00 +// absl::CivilYear y(m); // 2015-01-01 00:00:00 +// +// m = absl::CivilMonth(y); // 2015-01-01 00:00:00 +// d = absl::CivilDay(m); // 2015-01-01 00:00:00 +// hh = absl::CivilHour(d); // 2015-01-01 00:00:00 +// mm = absl::CivilMinute(hh); // 2015-01-01 00:00:00 +// ss = absl::CivilSecond(mm); // 2015-01-01 00:00:00 +// +// Each civil-time class is aligned to the civil-time field indicated in the +// class's name after normalization. Alignment is performed by setting all the +// inferior fields to their minimum valid value (as described above). The +// following are examples of how each of the six types would align the fields +// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the +// string format used here is not important; it's just a shorthand way of +// showing the six YMDHMS fields.) +// +// absl::CivilSecond : 2015-11-22 12:34:56 +// absl::CivilMinute : 2015-11-22 12:34:00 +// absl::CivilHour : 2015-11-22 12:00:00 +// absl::CivilDay : 2015-11-22 00:00:00 +// absl::CivilMonth : 2015-11-01 00:00:00 +// absl::CivilYear : 2015-01-01 00:00:00 +// +// Each civil-time type performs arithmetic on the field to which it is +// aligned. This means that adding 1 to an absl::CivilDay increments the day +// field (normalizing as necessary), and subtracting 7 from an absl::CivilMonth +// operates on the month field (normalizing as necessary). All arithmetic +// produces a valid civil time. Difference requires two similarly aligned +// civil-time objects and returns the scalar answer in units of the objects' +// alignment. For example, the difference between two absl::CivilHour objects +// will give an answer in units of civil hours. +// +// ALIGNMENT CONVERSION +// +// The alignment of a civil-time object cannot change, but the object may be +// used to construct a new object with a different alignment. This is referred +// to as "realigning". When realigning to a type with the same or more +// precision (e.g., absl::CivilDay -> absl::CivilSecond), the conversion may be +// performed implicitly since no information is lost. However, if information +// could be discarded (e.g., CivilSecond -> CivilDay), the conversion must +// be explicit at the call site. +// +// Examples: +// +// void UseDay(absl::CivilDay day); +// +// absl::CivilSecond cs; +// UseDay(cs); // Won't compile because data may be discarded +// UseDay(absl::CivilDay(cs)); // OK: explicit conversion +// +// absl::CivilDay cd; +// UseDay(cd); // OK: no conversion needed +// +// absl::CivilMonth cm; +// UseDay(cm); // OK: implicit conversion to absl::CivilDay +// +// NORMALIZATION +// +// Normalization takes invalid values and adjusts them to produce valid values. +// Within the civil-time library, integer arguments passed to the Civil* +// constructors may be out-of-range, in which case they are normalized by +// carrying overflow into a field of courser granularity to produce valid +// civil-time objects. This normalization enables natural arithmetic on +// constructor arguments without worrying about the field's range. +// +// Examples: +// +// // Out-of-range; normalized to 2016-11-01 +// absl::CivilDay d(2016, 10, 32); +// // Out-of-range, negative: normalized to 2016-10-30T23 +// absl::CivilHour h1(2016, 10, 31, -1); +// // Normalization is cumulative: normalized to 2016-10-30T23 +// absl::CivilHour h2(2016, 10, 32, -25); +// +// Note: If normalization is undesired, you can signal an error by comparing +// the constructor arguments to the normalized values returned by the YMDHMS +// properties. +// +// COMPARISON +// +// Comparison between civil-time objects considers all six YMDHMS fields, +// regardless of the type's alignment. Comparison between differently aligned +// civil-time types is allowed. +// +// Examples: +// +// absl::CivilDay feb_3(2015, 2, 3); // 2015-02-03 00:00:00 +// absl::CivilDay mar_4(2015, 3, 4); // 2015-03-04 00:00:00 +// // feb_3 < mar_4 +// // absl::CivilYear(feb_3) == absl::CivilYear(mar_4) +// +// absl::CivilSecond feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00 +// // feb_3 < feb_3_noon +// // feb_3 == absl::CivilDay(feb_3_noon) +// +// // Iterates all the days of February 2015. +// for (absl::CivilDay d(2015, 2, 1); d < absl::CivilMonth(2015, 3); ++d) { +// // ... +// } +// +// ARITHMETIC +// +// Civil-time types support natural arithmetic operators such as addition, +// subtraction, and difference. Arithmetic operates on the civil-time field +// indicated in the type's name. Difference operators require arguments with +// the same alignment and return the answer in units of the alignment. +// +// Example: +// +// absl::CivilDay a(2015, 2, 3); +// ++a; // 2015-02-04 00:00:00 +// --a; // 2015-02-03 00:00:00 +// absl::CivilDay b = a + 1; // 2015-02-04 00:00:00 +// absl::CivilDay c = 1 + b; // 2015-02-05 00:00:00 +// int n = c - a; // n = 2 (civil days) +// int m = c - absl::CivilMonth(c); // Won't compile: different types. +// +// ACCESSORS +// +// Each civil-time type has accessors for all six of the civil-time fields: +// year, month, day, hour, minute, and second. +// +// civil_year_t year() +// int month() +// int day() +// int hour() +// int minute() +// int second() +// +// Recall that fields inferior to the type's alignment will be set to their +// minimum valid value. +// +// Example: +// +// absl::CivilDay d(2015, 6, 28); +// // d.year() == 2015 +// // d.month() == 6 +// // d.day() == 28 +// // d.hour() == 0 +// // d.minute() == 0 +// // d.second() == 0 +// +// CASE STUDY: Adding a month to January 31. +// +// One of the classic questions that arises when considering a civil time +// library (or a date library or a date/time library) is this: +// "What is the result of adding a month to January 31?" +// This is an interesting question because it is unclear what is meant by a +// "month", and several different answers are possible, depending on context: +// +// 1. March 3 (or 2 if a leap year), if "add a month" means to add a month to +// the current month, and adjust the date to overflow the extra days into +// March. In this case the result of "February 31" would be normalized as +// within the civil-time library. +// 2. February 28 (or 29 if a leap year), if "add a month" means to add a +// month, and adjust the date while holding the resulting month constant. +// In this case, the result of "February 31" would be truncated to the last +// day in February. +// 3. An error. The caller may get some error, an exception, an invalid date +// object, or perhaps return `false`. This may make sense because there is +// no single unambiguously correct answer to the question. +// +// Practically speaking, any answer that is not what the programmer intended +// is the wrong answer. +// +// The Abseil time library avoids this problem by making it impossible to +// ask ambiguous questions. All civil-time objects are aligned to a particular +// civil-field boundary (such as aligned to a year, month, day, hour, minute, +// or second), and arithmetic operates on the field to which the object is +// aligned. This means that in order to "add a month" the object must first be +// aligned to a month boundary, which is equivalent to the first day of that +// month. +// +// Of course, there are ways to compute an answer the question at hand using +// this Abseil time library, but they require the programmer to be explicit +// about the answer they expect. To illustrate, let's see how to compute all +// three of the above possible answers to the question of "Jan 31 plus 1 +// month": +// +// Example: +// +// const absl::CivilDay d(2015, 1, 31); +// +// // Answer 1: +// // Add 1 to the month field in the constructor, and rely on normalization. +// const auto normalized = absl::CivilDay(d.year(), d.month() + 1, d.day()); +// // normalized == 2015-03-03 (aka Feb 31) +// +// // Answer 2: +// // Add 1 to month field, capping to the end of next month. +// const auto next_month = absl::CivilMonth(d) + 1; +// const auto last_day_of_next_month = absl::CivilDay(next_month + 1) - 1; +// const auto capped = std::min(normalized, last_day_of_next_month); +// // capped == 2015-02-28 +// +// // Answer 3: +// // Signal an error if the normalized answer is not in next month. +// if (absl::CivilMonth(normalized) != next_month) { +// // error, month overflow +// } +// +using CivilSecond = + time_internal::cctz::detail::civil_time<time_internal::second_tag>; +using CivilMinute = + time_internal::cctz::detail::civil_time<time_internal::minute_tag>; +using CivilHour = + time_internal::cctz::detail::civil_time<time_internal::hour_tag>; +using CivilDay = + time_internal::cctz::detail::civil_time<time_internal::day_tag>; +using CivilMonth = + time_internal::cctz::detail::civil_time<time_internal::month_tag>; +using CivilYear = + time_internal::cctz::detail::civil_time<time_internal::year_tag>; + +// civil_year_t +// +// Type alias of a civil-time year value. This type is guaranteed to (at least) +// support any year value supported by `time_t`. +// +// Example: +// +// absl::CivilSecond cs = ...; +// absl::civil_year_t y = cs.year(); +// cs = absl::CivilSecond(y, 1, 1, 0, 0, 0); // CivilSecond(CivilYear(cs)) +// +using civil_year_t = time_internal::cctz::year_t; + +// civil_diff_t +// +// Type alias of the difference between two civil-time values. +// This type is used to indicate arguments that are not +// normalized (such as parameters to the civil-time constructors), the results +// of civil-time subtraction, or the operand to civil-time addition. +// +// Example: +// +// absl::civil_diff_t n_sec = cs1 - cs2; // cs1 == cs2 + n_sec; +// +using civil_diff_t = time_internal::cctz::diff_t; + +// Weekday::monday, Weekday::tuesday, Weekday::wednesday, Weekday::thursday, +// Weekday::friday, Weekday::saturday, Weekday::sunday +// +// The Weekday enum class represents the civil-time concept of a "weekday" with +// members for all days of the week. +// +// absl::Weekday wd = absl::Weekday::thursday; +// +using Weekday = time_internal::cctz::weekday; + +// GetWeekday() +// +// Returns the absl::Weekday for the given (realigned) civil-time value. +// +// Example: +// +// absl::CivilDay a(2015, 8, 13); +// absl::Weekday wd = absl::GetWeekday(a); // wd == absl::Weekday::thursday +// +inline Weekday GetWeekday(CivilSecond cs) { + return time_internal::cctz::get_weekday(cs); +} + +// NextWeekday() +// PrevWeekday() +// +// Returns the absl::CivilDay that strictly follows or precedes a given +// absl::CivilDay, and that falls on the given absl::Weekday. +// +// Example, given the following month: +// +// August 2015 +// Su Mo Tu We Th Fr Sa +// 1 +// 2 3 4 5 6 7 8 +// 9 10 11 12 13 14 15 +// 16 17 18 19 20 21 22 +// 23 24 25 26 27 28 29 +// 30 31 +// +// absl::CivilDay a(2015, 8, 13); +// // absl::GetWeekday(a) == absl::Weekday::thursday +// absl::CivilDay b = absl::NextWeekday(a, absl::Weekday::thursday); +// // b = 2015-08-20 +// absl::CivilDay c = absl::PrevWeekday(a, absl::Weekday::thursday); +// // c = 2015-08-06 +// +// absl::CivilDay d = ... +// // Gets the following Thursday if d is not already Thursday +// absl::CivilDay thurs1 = absl::NextWeekday(d - 1, absl::Weekday::thursday); +// // Gets the previous Thursday if d is not already Thursday +// absl::CivilDay thurs2 = absl::PrevWeekday(d + 1, absl::Weekday::thursday); +// +inline CivilDay NextWeekday(CivilDay cd, Weekday wd) { + return CivilDay(time_internal::cctz::next_weekday(cd, wd)); +} +inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) { + return CivilDay(time_internal::cctz::prev_weekday(cd, wd)); +} + +// GetYearDay() +// +// Returns the day-of-year for the given (realigned) civil-time value. +// +// Example: +// +// absl::CivilDay a(2015, 1, 1); +// int yd_jan_1 = absl::GetYearDay(a); // yd_jan_1 = 1 +// absl::CivilDay b(2015, 12, 31); +// int yd_dec_31 = absl::GetYearDay(b); // yd_dec_31 = 365 +// +inline int GetYearDay(CivilSecond cs) { + return time_internal::cctz::get_yearday(cs); +} + +// FormatCivilTime() +// +// Formats the given civil-time value into a string value of the following +// format: +// +// Type | Format +// --------------------------------- +// CivilSecond | YYYY-MM-DDTHH:MM:SS +// CivilMinute | YYYY-MM-DDTHH:MM +// CivilHour | YYYY-MM-DDTHH +// CivilDay | YYYY-MM-DD +// CivilMonth | YYYY-MM +// CivilYear | YYYY +// +// Example: +// +// absl::CivilDay d = absl::CivilDay(1969, 7, 20); +// std::string day_string = absl::FormatCivilTime(d); // "1969-07-20" +// +std::string FormatCivilTime(CivilSecond c); +std::string FormatCivilTime(CivilMinute c); +std::string FormatCivilTime(CivilHour c); +std::string FormatCivilTime(CivilDay c); +std::string FormatCivilTime(CivilMonth c); +std::string FormatCivilTime(CivilYear c); + +// absl::ParseCivilTime() +// +// Parses a civil-time value from the specified `absl::string_view` into the +// passed output parameter. Returns `true` upon successful parsing. +// +// The expected form of the input string is as follows: +// +// Type | Format +// --------------------------------- +// CivilSecond | YYYY-MM-DDTHH:MM:SS +// CivilMinute | YYYY-MM-DDTHH:MM +// CivilHour | YYYY-MM-DDTHH +// CivilDay | YYYY-MM-DD +// CivilMonth | YYYY-MM +// CivilYear | YYYY +// +// Example: +// +// absl::CivilDay d; +// bool ok = absl::ParseCivilTime("2018-01-02", &d); // OK +// +// Note that parsing will fail if the string's format does not match the +// expected type exactly. `ParseLenientCivilTime()` below is more lenient. +// +bool ParseCivilTime(absl::string_view s, CivilSecond* c); +bool ParseCivilTime(absl::string_view s, CivilMinute* c); +bool ParseCivilTime(absl::string_view s, CivilHour* c); +bool ParseCivilTime(absl::string_view s, CivilDay* c); +bool ParseCivilTime(absl::string_view s, CivilMonth* c); +bool ParseCivilTime(absl::string_view s, CivilYear* c); + +// ParseLenientCivilTime() +// +// Parses any of the formats accepted by `absl::ParseCivilTime()`, but is more +// lenient if the format of the string does not exactly match the associated +// type. +// +// Example: +// +// absl::CivilDay d; +// bool ok = absl::ParseLenientCivilTime("1969-07-20", &d); // OK +// ok = absl::ParseLenientCivilTime("1969-07-20T10", &d); // OK: T10 floored +// ok = absl::ParseLenientCivilTime("1969-07", &d); // OK: day defaults to 1 +// +bool ParseLenientCivilTime(absl::string_view s, CivilSecond* c); +bool ParseLenientCivilTime(absl::string_view s, CivilMinute* c); +bool ParseLenientCivilTime(absl::string_view s, CivilHour* c); +bool ParseLenientCivilTime(absl::string_view s, CivilDay* c); +bool ParseLenientCivilTime(absl::string_view s, CivilMonth* c); +bool ParseLenientCivilTime(absl::string_view s, CivilYear* c); + +namespace time_internal { // For functions found via ADL on civil-time tags. + +// Streaming Operators +// +// Each civil-time type may be sent to an output stream using operator<<(). +// The result matches the string produced by `FormatCivilTime()`. +// +// Example: +// +// absl::CivilDay d = absl::CivilDay(1969, 7, 20); +// std::cout << "Date is: " << d << "\n"; +// +std::ostream& operator<<(std::ostream& os, CivilYear y); +std::ostream& operator<<(std::ostream& os, CivilMonth m); +std::ostream& operator<<(std::ostream& os, CivilDay d); +std::ostream& operator<<(std::ostream& os, CivilHour h); +std::ostream& operator<<(std::ostream& os, CivilMinute m); +std::ostream& operator<<(std::ostream& os, CivilSecond s); + +} // namespace time_internal + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_CIVIL_TIME_H_ diff --git a/third_party/abseil_cpp/absl/time/civil_time_benchmark.cc b/third_party/abseil_cpp/absl/time/civil_time_benchmark.cc new file mode 100644 index 000000000000..f04dbe200ed2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/civil_time_benchmark.cc @@ -0,0 +1,127 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/civil_time.h" + +#include <numeric> +#include <vector> + +#include "absl/hash/hash.h" +#include "benchmark/benchmark.h" + +namespace { + +// Run on (12 X 3492 MHz CPUs); 2018-11-05T13:44:29.814239103-08:00 +// CPU: Intel Haswell with HyperThreading (6 cores) dL1:32KB dL2:256KB dL3:15MB +// Benchmark Time(ns) CPU(ns) Iterations +// ---------------------------------------------------------------- +// BM_Difference_Days 14.5 14.5 48531105 +// BM_Step_Days 12.6 12.6 54876006 +// BM_Format 587 587 1000000 +// BM_Parse 692 692 1000000 +// BM_RoundTripFormatParse 1309 1309 532075 +// BM_CivilYearAbslHash 0.710 0.710 976400000 +// BM_CivilMonthAbslHash 1.13 1.13 619500000 +// BM_CivilDayAbslHash 1.70 1.70 426000000 +// BM_CivilHourAbslHash 2.45 2.45 287600000 +// BM_CivilMinuteAbslHash 3.21 3.21 226200000 +// BM_CivilSecondAbslHash 4.10 4.10 171800000 + +void BM_Difference_Days(benchmark::State& state) { + const absl::CivilDay c(2014, 8, 22); + const absl::CivilDay epoch(1970, 1, 1); + while (state.KeepRunning()) { + const absl::civil_diff_t n = c - epoch; + benchmark::DoNotOptimize(n); + } +} +BENCHMARK(BM_Difference_Days); + +void BM_Step_Days(benchmark::State& state) { + const absl::CivilDay kStart(2014, 8, 22); + absl::CivilDay c = kStart; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(++c); + } +} +BENCHMARK(BM_Step_Days); + +void BM_Format(benchmark::State& state) { + const absl::CivilSecond c(2014, 1, 2, 3, 4, 5); + while (state.KeepRunning()) { + const std::string s = absl::FormatCivilTime(c); + benchmark::DoNotOptimize(s); + } +} +BENCHMARK(BM_Format); + +void BM_Parse(benchmark::State& state) { + const std::string f = "2014-01-02T03:04:05"; + absl::CivilSecond c; + while (state.KeepRunning()) { + const bool b = absl::ParseCivilTime(f, &c); + benchmark::DoNotOptimize(b); + } +} +BENCHMARK(BM_Parse); + +void BM_RoundTripFormatParse(benchmark::State& state) { + const absl::CivilSecond c(2014, 1, 2, 3, 4, 5); + absl::CivilSecond out; + while (state.KeepRunning()) { + const bool b = absl::ParseCivilTime(absl::FormatCivilTime(c), &out); + benchmark::DoNotOptimize(b); + } +} +BENCHMARK(BM_RoundTripFormatParse); + +template <typename T> +void BM_CivilTimeAbslHash(benchmark::State& state) { + const int kSize = 100000; + std::vector<T> civil_times(kSize); + std::iota(civil_times.begin(), civil_times.end(), T(2018)); + + absl::Hash<T> absl_hasher; + while (state.KeepRunningBatch(kSize)) { + for (const T civil_time : civil_times) { + benchmark::DoNotOptimize(absl_hasher(civil_time)); + } + } +} +void BM_CivilYearAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilYear>(state); +} +void BM_CivilMonthAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilMonth>(state); +} +void BM_CivilDayAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilDay>(state); +} +void BM_CivilHourAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilHour>(state); +} +void BM_CivilMinuteAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilMinute>(state); +} +void BM_CivilSecondAbslHash(benchmark::State& state) { + BM_CivilTimeAbslHash<absl::CivilSecond>(state); +} +BENCHMARK(BM_CivilYearAbslHash); +BENCHMARK(BM_CivilMonthAbslHash); +BENCHMARK(BM_CivilDayAbslHash); +BENCHMARK(BM_CivilHourAbslHash); +BENCHMARK(BM_CivilMinuteAbslHash); +BENCHMARK(BM_CivilSecondAbslHash); + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/civil_time_test.cc b/third_party/abseil_cpp/absl/time/civil_time_test.cc new file mode 100644 index 000000000000..0ebd97adbc56 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/civil_time_test.cc @@ -0,0 +1,1243 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/civil_time.h" + +#include <limits> +#include <sstream> +#include <type_traits> + +#include "absl/base/macros.h" +#include "gtest/gtest.h" + +namespace { + +TEST(CivilTime, DefaultConstruction) { + absl::CivilSecond ss; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_EQ("1970-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_EQ("1970", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, StructMember) { + struct S { + absl::CivilDay day; + }; + S s = {}; + EXPECT_EQ(absl::CivilDay{}, s.day); +} + +TEST(CivilTime, FieldsConstruction) { + EXPECT_EQ("2015-01-02T03:04:05", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03:04:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015, 1))); + EXPECT_EQ("2015-01-01T00:00:00", + absl::FormatCivilTime(absl::CivilSecond(2015))); + + EXPECT_EQ("2015-01-02T03:04", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03:04", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03:00", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00:00", + absl::FormatCivilTime(absl::CivilMinute(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00:00", + absl::FormatCivilTime(absl::CivilMinute(2015, 1))); + EXPECT_EQ("2015-01-01T00:00", + absl::FormatCivilTime(absl::CivilMinute(2015))); + + EXPECT_EQ("2015-01-02T03", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00", + absl::FormatCivilTime(absl::CivilHour(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00", + absl::FormatCivilTime(absl::CivilHour(2015, 1))); + EXPECT_EQ("2015-01-01T00", + absl::FormatCivilTime(absl::CivilHour(2015))); + + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02", + absl::FormatCivilTime(absl::CivilDay(2015, 1, 2))); + EXPECT_EQ("2015-01-01", + absl::FormatCivilTime(absl::CivilDay(2015, 1))); + EXPECT_EQ("2015-01-01", + absl::FormatCivilTime(absl::CivilDay(2015))); + + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2, 3))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1, 2))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015, 1))); + EXPECT_EQ("2015-01", + absl::FormatCivilTime(absl::CivilMonth(2015))); + + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2, 3))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1, 2))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015, 1))); + EXPECT_EQ("2015", + absl::FormatCivilTime(absl::CivilYear(2015))); +} + +TEST(CivilTime, FieldsConstructionLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + EXPECT_EQ("2038-01-19T03:14:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, 0, kIntMax))); + EXPECT_EQ("6121-02-11T05:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, kIntMax, kIntMax))); + EXPECT_EQ("251104-11-20T12:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, kIntMax, kIntMax, kIntMax))); + EXPECT_EQ("6130715-05-30T12:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, kIntMax, kIntMax, kIntMax, kIntMax))); + EXPECT_EQ("185087685-11-26T12:21:07", + absl::FormatCivilTime(absl::CivilSecond( + 1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax))); + + const int kIntMin = std::numeric_limits<int>::min(); + EXPECT_EQ("1901-12-13T20:45:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, 0, kIntMin))); + EXPECT_EQ("-2182-11-20T18:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, 0, kIntMin, kIntMin))); + EXPECT_EQ("-247165-02-11T10:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, 1, kIntMin, kIntMin, kIntMin))); + EXPECT_EQ("-6126776-08-01T10:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, 1, kIntMin, kIntMin, kIntMin, kIntMin))); + EXPECT_EQ("-185083747-10-31T10:37:52", + absl::FormatCivilTime(absl::CivilSecond( + 1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin))); +} + +TEST(CivilTime, RangeLimits) { + const absl::civil_year_t kYearMax = + std::numeric_limits<absl::civil_year_t>::max(); + EXPECT_EQ(absl::CivilYear(kYearMax), + absl::CivilYear::max()); + EXPECT_EQ(absl::CivilMonth(kYearMax, 12), + absl::CivilMonth::max()); + EXPECT_EQ(absl::CivilDay(kYearMax, 12, 31), + absl::CivilDay::max()); + EXPECT_EQ(absl::CivilHour(kYearMax, 12, 31, 23), + absl::CivilHour::max()); + EXPECT_EQ(absl::CivilMinute(kYearMax, 12, 31, 23, 59), + absl::CivilMinute::max()); + EXPECT_EQ(absl::CivilSecond(kYearMax, 12, 31, 23, 59, 59), + absl::CivilSecond::max()); + + const absl::civil_year_t kYearMin = + std::numeric_limits<absl::civil_year_t>::min(); + EXPECT_EQ(absl::CivilYear(kYearMin), + absl::CivilYear::min()); + EXPECT_EQ(absl::CivilMonth(kYearMin, 1), + absl::CivilMonth::min()); + EXPECT_EQ(absl::CivilDay(kYearMin, 1, 1), + absl::CivilDay::min()); + EXPECT_EQ(absl::CivilHour(kYearMin, 1, 1, 0), + absl::CivilHour::min()); + EXPECT_EQ(absl::CivilMinute(kYearMin, 1, 1, 0, 0), + absl::CivilMinute::min()); + EXPECT_EQ(absl::CivilSecond(kYearMin, 1, 1, 0, 0, 0), + absl::CivilSecond::min()); +} + +TEST(CivilTime, ImplicitCrossAlignment) { + absl::CivilYear year(2015); + absl::CivilMonth month = year; + absl::CivilDay day = month; + absl::CivilHour hour = day; + absl::CivilMinute minute = hour; + absl::CivilSecond second = minute; + + second = year; + EXPECT_EQ(second, year); + second = month; + EXPECT_EQ(second, month); + second = day; + EXPECT_EQ(second, day); + second = hour; + EXPECT_EQ(second, hour); + second = minute; + EXPECT_EQ(second, minute); + + minute = year; + EXPECT_EQ(minute, year); + minute = month; + EXPECT_EQ(minute, month); + minute = day; + EXPECT_EQ(minute, day); + minute = hour; + EXPECT_EQ(minute, hour); + + hour = year; + EXPECT_EQ(hour, year); + hour = month; + EXPECT_EQ(hour, month); + hour = day; + EXPECT_EQ(hour, day); + + day = year; + EXPECT_EQ(day, year); + day = month; + EXPECT_EQ(day, month); + + month = year; + EXPECT_EQ(month, year); + + // Ensures unsafe conversions are not allowed. + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilMinute>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilHour>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilDay>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilSecond, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilHour>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilDay>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilMinute, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilHour, absl::CivilDay>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilHour, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilHour, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilDay, absl::CivilMonth>::value)); + EXPECT_FALSE( + (std::is_convertible<absl::CivilDay, absl::CivilYear>::value)); + + EXPECT_FALSE( + (std::is_convertible<absl::CivilMonth, absl::CivilYear>::value)); +} + +TEST(CivilTime, ExplicitCrossAlignment) { + // + // Assign from smaller units -> larger units + // + + absl::CivilSecond second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second)); + + absl::CivilMinute minute(second); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute)); + + absl::CivilHour hour(minute); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour)); + + absl::CivilDay day(hour); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day)); + + absl::CivilMonth month(day); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month)); + + absl::CivilYear year(month); + EXPECT_EQ("2015", absl::FormatCivilTime(year)); + + // + // Now assign from larger units -> smaller units + // + + month = absl::CivilMonth(year); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month)); + + day = absl::CivilDay(month); + EXPECT_EQ("2015-01-01", absl::FormatCivilTime(day)); + + hour = absl::CivilHour(day); + EXPECT_EQ("2015-01-01T00", absl::FormatCivilTime(hour)); + + minute = absl::CivilMinute(hour); + EXPECT_EQ("2015-01-01T00:00", absl::FormatCivilTime(minute)); + + second = absl::CivilSecond(minute); + EXPECT_EQ("2015-01-01T00:00:00", absl::FormatCivilTime(second)); +} + +// Metafunction to test whether difference is allowed between two types. +template <typename T1, typename T2> +struct HasDiff { + template <typename U1, typename U2> + static std::false_type test(...); + template <typename U1, typename U2> + static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>())); + static constexpr bool value = decltype(test<T1, T2>(0))::value; +}; + +TEST(CivilTime, DisallowCrossAlignedDifference) { + // Difference is allowed between types with the same alignment. + static_assert(HasDiff<absl::CivilSecond, absl::CivilSecond>::value, ""); + static_assert(HasDiff<absl::CivilMinute, absl::CivilMinute>::value, ""); + static_assert(HasDiff<absl::CivilHour, absl::CivilHour>::value, ""); + static_assert(HasDiff<absl::CivilDay, absl::CivilDay>::value, ""); + static_assert(HasDiff<absl::CivilMonth, absl::CivilMonth>::value, ""); + static_assert(HasDiff<absl::CivilYear, absl::CivilYear>::value, ""); + + // Difference is disallowed between types with different alignments. + static_assert(!HasDiff<absl::CivilSecond, absl::CivilMinute>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilHour>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilDay>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilSecond, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilMinute, absl::CivilHour>::value, ""); + static_assert(!HasDiff<absl::CivilMinute, absl::CivilDay>::value, ""); + static_assert(!HasDiff<absl::CivilMinute, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilMinute, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilHour, absl::CivilDay>::value, ""); + static_assert(!HasDiff<absl::CivilHour, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilHour, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilDay, absl::CivilMonth>::value, ""); + static_assert(!HasDiff<absl::CivilDay, absl::CivilYear>::value, ""); + + static_assert(!HasDiff<absl::CivilMonth, absl::CivilYear>::value, ""); +} + +TEST(CivilTime, ValueSemantics) { + const absl::CivilHour a(2015, 1, 2, 3); + const absl::CivilHour b = a; + const absl::CivilHour c(b); + absl::CivilHour d; + d = c; + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(d)); +} + +TEST(CivilTime, Relational) { + // Tests that the alignment unit is ignored in comparison. + const absl::CivilYear year(2014); + const absl::CivilMonth month(year); + EXPECT_EQ(year, month); + +#define TEST_RELATIONAL(OLDER, YOUNGER) \ + do { \ + EXPECT_FALSE(OLDER < OLDER); \ + EXPECT_FALSE(OLDER > OLDER); \ + EXPECT_TRUE(OLDER >= OLDER); \ + EXPECT_TRUE(OLDER <= OLDER); \ + EXPECT_FALSE(YOUNGER < YOUNGER); \ + EXPECT_FALSE(YOUNGER > YOUNGER); \ + EXPECT_TRUE(YOUNGER >= YOUNGER); \ + EXPECT_TRUE(YOUNGER <= YOUNGER); \ + EXPECT_EQ(OLDER, OLDER); \ + EXPECT_NE(OLDER, YOUNGER); \ + EXPECT_LT(OLDER, YOUNGER); \ + EXPECT_LE(OLDER, YOUNGER); \ + EXPECT_GT(YOUNGER, OLDER); \ + EXPECT_GE(YOUNGER, OLDER); \ + } while (0) + + // Alignment is ignored in comparison (verified above), so CivilSecond is + // used to test comparison in all field positions. + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2015, 1, 1, 0, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2014, 2, 1, 0, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2014, 1, 2, 0, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 0, 0, 0), + absl::CivilSecond(2014, 1, 1, 1, 0, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 1, 0, 0), + absl::CivilSecond(2014, 1, 1, 1, 1, 0)); + TEST_RELATIONAL(absl::CivilSecond(2014, 1, 1, 1, 1, 0), + absl::CivilSecond(2014, 1, 1, 1, 1, 1)); + + // Tests the relational operators of two different civil-time types. + TEST_RELATIONAL(absl::CivilDay(2014, 1, 1), + absl::CivilMinute(2014, 1, 1, 1, 1)); + TEST_RELATIONAL(absl::CivilDay(2014, 1, 1), + absl::CivilMonth(2014, 2)); + +#undef TEST_RELATIONAL +} + +TEST(CivilTime, Arithmetic) { + absl::CivilSecond second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ("2015-01-02T03:04:06", absl::FormatCivilTime(second += 1)); + EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(second + 1)); + EXPECT_EQ("2015-01-02T03:04:08", absl::FormatCivilTime(2 + second)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second - 1)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second -= 1)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(second++)); + EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(++second)); + EXPECT_EQ("2015-01-02T03:04:07", absl::FormatCivilTime(second--)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(--second)); + + absl::CivilMinute minute(2015, 1, 2, 3, 4); + EXPECT_EQ("2015-01-02T03:05", absl::FormatCivilTime(minute += 1)); + EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(minute + 1)); + EXPECT_EQ("2015-01-02T03:07", absl::FormatCivilTime(2 + minute)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute - 1)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute -= 1)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(minute++)); + EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(++minute)); + EXPECT_EQ("2015-01-02T03:06", absl::FormatCivilTime(minute--)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(--minute)); + + absl::CivilHour hour(2015, 1, 2, 3); + EXPECT_EQ("2015-01-02T04", absl::FormatCivilTime(hour += 1)); + EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(hour + 1)); + EXPECT_EQ("2015-01-02T06", absl::FormatCivilTime(2 + hour)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour - 1)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour -= 1)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hour++)); + EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(++hour)); + EXPECT_EQ("2015-01-02T05", absl::FormatCivilTime(hour--)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(--hour)); + + absl::CivilDay day(2015, 1, 2); + EXPECT_EQ("2015-01-03", absl::FormatCivilTime(day += 1)); + EXPECT_EQ("2015-01-04", absl::FormatCivilTime(day + 1)); + EXPECT_EQ("2015-01-05", absl::FormatCivilTime(2 + day)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day - 1)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day -= 1)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(day++)); + EXPECT_EQ("2015-01-04", absl::FormatCivilTime(++day)); + EXPECT_EQ("2015-01-04", absl::FormatCivilTime(day--)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(--day)); + + absl::CivilMonth month(2015, 1); + EXPECT_EQ("2015-02", absl::FormatCivilTime(month += 1)); + EXPECT_EQ("2015-03", absl::FormatCivilTime(month + 1)); + EXPECT_EQ("2015-04", absl::FormatCivilTime(2 + month)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month - 1)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month -= 1)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(month++)); + EXPECT_EQ("2015-03", absl::FormatCivilTime(++month)); + EXPECT_EQ("2015-03", absl::FormatCivilTime(month--)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(--month)); + + absl::CivilYear year(2015); + EXPECT_EQ("2016", absl::FormatCivilTime(year += 1)); + EXPECT_EQ("2017", absl::FormatCivilTime(year + 1)); + EXPECT_EQ("2018", absl::FormatCivilTime(2 + year)); + EXPECT_EQ("2015", absl::FormatCivilTime(year - 1)); + EXPECT_EQ("2015", absl::FormatCivilTime(year -= 1)); + EXPECT_EQ("2015", absl::FormatCivilTime(year++)); + EXPECT_EQ("2017", absl::FormatCivilTime(++year)); + EXPECT_EQ("2017", absl::FormatCivilTime(year--)); + EXPECT_EQ("2015", absl::FormatCivilTime(--year)); +} + +TEST(CivilTime, ArithmeticLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + const int kIntMin = std::numeric_limits<int>::min(); + + absl::CivilSecond second(1970, 1, 1, 0, 0, 0); + second += kIntMax; + EXPECT_EQ("2038-01-19T03:14:07", absl::FormatCivilTime(second)); + second -= kIntMax; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(second)); + second += kIntMin; + EXPECT_EQ("1901-12-13T20:45:52", absl::FormatCivilTime(second)); + second -= kIntMin; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(second)); + + absl::CivilMinute minute(1970, 1, 1, 0, 0); + minute += kIntMax; + EXPECT_EQ("6053-01-23T02:07", absl::FormatCivilTime(minute)); + minute -= kIntMax; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(minute)); + minute += kIntMin; + EXPECT_EQ("-2114-12-08T21:52", absl::FormatCivilTime(minute)); + minute -= kIntMin; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(minute)); + + absl::CivilHour hour(1970, 1, 1, 0); + hour += kIntMax; + EXPECT_EQ("246953-10-09T07", absl::FormatCivilTime(hour)); + hour -= kIntMax; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hour)); + hour += kIntMin; + EXPECT_EQ("-243014-03-24T16", absl::FormatCivilTime(hour)); + hour -= kIntMin; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hour)); + + absl::CivilDay day(1970, 1, 1); + day += kIntMax; + EXPECT_EQ("5881580-07-11", absl::FormatCivilTime(day)); + day -= kIntMax; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(day)); + day += kIntMin; + EXPECT_EQ("-5877641-06-23", absl::FormatCivilTime(day)); + day -= kIntMin; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(day)); + + absl::CivilMonth month(1970, 1); + month += kIntMax; + EXPECT_EQ("178958940-08", absl::FormatCivilTime(month)); + month -= kIntMax; + EXPECT_EQ("1970-01", absl::FormatCivilTime(month)); + month += kIntMin; + EXPECT_EQ("-178955001-05", absl::FormatCivilTime(month)); + month -= kIntMin; + EXPECT_EQ("1970-01", absl::FormatCivilTime(month)); + + absl::CivilYear year(0); + year += kIntMax; + EXPECT_EQ("2147483647", absl::FormatCivilTime(year)); + year -= kIntMax; + EXPECT_EQ("0", absl::FormatCivilTime(year)); + year += kIntMin; + EXPECT_EQ("-2147483648", absl::FormatCivilTime(year)); + year -= kIntMin; + EXPECT_EQ("0", absl::FormatCivilTime(year)); +} + +TEST(CivilTime, Difference) { + absl::CivilSecond second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ(0, second - second); + EXPECT_EQ(10, (second + 10) - second); + EXPECT_EQ(-10, (second - 10) - second); + + absl::CivilMinute minute(2015, 1, 2, 3, 4); + EXPECT_EQ(0, minute - minute); + EXPECT_EQ(10, (minute + 10) - minute); + EXPECT_EQ(-10, (minute - 10) - minute); + + absl::CivilHour hour(2015, 1, 2, 3); + EXPECT_EQ(0, hour - hour); + EXPECT_EQ(10, (hour + 10) - hour); + EXPECT_EQ(-10, (hour - 10) - hour); + + absl::CivilDay day(2015, 1, 2); + EXPECT_EQ(0, day - day); + EXPECT_EQ(10, (day + 10) - day); + EXPECT_EQ(-10, (day - 10) - day); + + absl::CivilMonth month(2015, 1); + EXPECT_EQ(0, month - month); + EXPECT_EQ(10, (month + 10) - month); + EXPECT_EQ(-10, (month - 10) - month); + + absl::CivilYear year(2015); + EXPECT_EQ(0, year - year); + EXPECT_EQ(10, (year + 10) - year); + EXPECT_EQ(-10, (year - 10) - year); +} + +TEST(CivilTime, DifferenceLimits) { + const absl::civil_diff_t kDiffMax = + std::numeric_limits<absl::civil_diff_t>::max(); + const absl::civil_diff_t kDiffMin = + std::numeric_limits<absl::civil_diff_t>::min(); + + // Check day arithmetic at the end of the year range. + const absl::CivilDay max_day(kDiffMax, 12, 31); + EXPECT_EQ(1, max_day - (max_day - 1)); + EXPECT_EQ(-1, (max_day - 1) - max_day); + + // Check day arithmetic at the start of the year range. + const absl::CivilDay min_day(kDiffMin, 1, 1); + EXPECT_EQ(1, (min_day + 1) - min_day); + EXPECT_EQ(-1, min_day - (min_day + 1)); + + // Check the limits of the return value. + const absl::CivilDay d1(1970, 1, 1); + const absl::CivilDay d2(25252734927768524, 7, 27); + EXPECT_EQ(kDiffMax, d2 - d1); + EXPECT_EQ(kDiffMin, d1 - (d2 + 1)); +} + +TEST(CivilTime, Properties) { + absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, ss.year()); + EXPECT_EQ(2, ss.month()); + EXPECT_EQ(3, ss.day()); + EXPECT_EQ(4, ss.hour()); + EXPECT_EQ(5, ss.minute()); + EXPECT_EQ(6, ss.second()); + EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(ss)); + EXPECT_EQ(34, absl::GetYearDay(ss)); + + absl::CivilMinute mm(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, mm.year()); + EXPECT_EQ(2, mm.month()); + EXPECT_EQ(3, mm.day()); + EXPECT_EQ(4, mm.hour()); + EXPECT_EQ(5, mm.minute()); + EXPECT_EQ(0, mm.second()); + EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(mm)); + EXPECT_EQ(34, absl::GetYearDay(mm)); + + absl::CivilHour hh(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, hh.year()); + EXPECT_EQ(2, hh.month()); + EXPECT_EQ(3, hh.day()); + EXPECT_EQ(4, hh.hour()); + EXPECT_EQ(0, hh.minute()); + EXPECT_EQ(0, hh.second()); + EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(hh)); + EXPECT_EQ(34, absl::GetYearDay(hh)); + + absl::CivilDay d(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, d.year()); + EXPECT_EQ(2, d.month()); + EXPECT_EQ(3, d.day()); + EXPECT_EQ(0, d.hour()); + EXPECT_EQ(0, d.minute()); + EXPECT_EQ(0, d.second()); + EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(d)); + EXPECT_EQ(34, absl::GetYearDay(d)); + + absl::CivilMonth m(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, m.year()); + EXPECT_EQ(2, m.month()); + EXPECT_EQ(1, m.day()); + EXPECT_EQ(0, m.hour()); + EXPECT_EQ(0, m.minute()); + EXPECT_EQ(0, m.second()); + EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(m)); + EXPECT_EQ(32, absl::GetYearDay(m)); + + absl::CivilYear y(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, y.year()); + EXPECT_EQ(1, y.month()); + EXPECT_EQ(1, y.day()); + EXPECT_EQ(0, y.hour()); + EXPECT_EQ(0, y.minute()); + EXPECT_EQ(0, y.second()); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(y)); + EXPECT_EQ(1, absl::GetYearDay(y)); +} + +TEST(CivilTime, Format) { + absl::CivilSecond ss; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_EQ("1970-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_EQ("1970", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, Parse) { + absl::CivilSecond ss; + absl::CivilMinute mm; + absl::CivilHour hh; + absl::CivilDay d; + absl::CivilMonth m; + absl::CivilYear y; + + // CivilSecond OK; others fail + EXPECT_TRUE(absl::ParseCivilTime("2015-01-02T03:04:05", &ss)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(ss)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &mm)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &hh)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &d)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &m)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04:05", &y)); + + // CivilMinute OK; others fail + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &ss)); + EXPECT_TRUE(absl::ParseCivilTime("2015-01-02T03:04", &mm)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(mm)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &hh)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &d)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &m)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03:04", &y)); + + // CivilHour OK; others fail + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &ss)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &mm)); + EXPECT_TRUE(absl::ParseCivilTime("2015-01-02T03", &hh)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hh)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &d)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &m)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02T03", &y)); + + // CivilDay OK; others fail + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &ss)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &mm)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &hh)); + EXPECT_TRUE(absl::ParseCivilTime("2015-01-02", &d)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(d)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &m)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01-02", &y)); + + // CivilMonth OK; others fail + EXPECT_FALSE(absl::ParseCivilTime("2015-01", &ss)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01", &mm)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01", &hh)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01", &d)); + EXPECT_TRUE(absl::ParseCivilTime("2015-01", &m)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(m)); + EXPECT_FALSE(absl::ParseCivilTime("2015-01", &y)); + + // CivilYear OK; others fail + EXPECT_FALSE(absl::ParseCivilTime("2015", &ss)); + EXPECT_FALSE(absl::ParseCivilTime("2015", &mm)); + EXPECT_FALSE(absl::ParseCivilTime("2015", &hh)); + EXPECT_FALSE(absl::ParseCivilTime("2015", &d)); + EXPECT_FALSE(absl::ParseCivilTime("2015", &m)); + EXPECT_TRUE(absl::ParseCivilTime("2015", &y)); + EXPECT_EQ("2015", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, FormatAndParseLenient) { + absl::CivilSecond ss; + EXPECT_EQ("1970-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_EQ("1970-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_EQ("1970-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_EQ("1970-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_EQ("1970-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_EQ("1970", absl::FormatCivilTime(y)); + + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &ss)); + EXPECT_EQ("2015-01-02T03:04:05", absl::FormatCivilTime(ss)); + + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &mm)); + EXPECT_EQ("2015-01-02T03:04", absl::FormatCivilTime(mm)); + + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &hh)); + EXPECT_EQ("2015-01-02T03", absl::FormatCivilTime(hh)); + + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &d)); + EXPECT_EQ("2015-01-02", absl::FormatCivilTime(d)); + + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &m)); + EXPECT_EQ("2015-01", absl::FormatCivilTime(m)); + + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-01-02T03:04:05", &y)); + EXPECT_EQ("2015", absl::FormatCivilTime(y)); +} + +TEST(CivilTime, ParseEdgeCases) { + absl::CivilSecond ss; + EXPECT_TRUE( + absl::ParseLenientCivilTime("9223372036854775807-12-31T23:59:59", &ss)); + EXPECT_EQ("9223372036854775807-12-31T23:59:59", absl::FormatCivilTime(ss)); + EXPECT_TRUE( + absl::ParseLenientCivilTime("-9223372036854775808-01-01T00:00:00", &ss)); + EXPECT_EQ("-9223372036854775808-01-01T00:00:00", absl::FormatCivilTime(ss)); + + absl::CivilMinute mm; + EXPECT_TRUE( + absl::ParseLenientCivilTime("9223372036854775807-12-31T23:59", &mm)); + EXPECT_EQ("9223372036854775807-12-31T23:59", absl::FormatCivilTime(mm)); + EXPECT_TRUE( + absl::ParseLenientCivilTime("-9223372036854775808-01-01T00:00", &mm)); + EXPECT_EQ("-9223372036854775808-01-01T00:00", absl::FormatCivilTime(mm)); + + absl::CivilHour hh; + EXPECT_TRUE( + absl::ParseLenientCivilTime("9223372036854775807-12-31T23", &hh)); + EXPECT_EQ("9223372036854775807-12-31T23", absl::FormatCivilTime(hh)); + EXPECT_TRUE( + absl::ParseLenientCivilTime("-9223372036854775808-01-01T00", &hh)); + EXPECT_EQ("-9223372036854775808-01-01T00", absl::FormatCivilTime(hh)); + + absl::CivilDay d; + EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807-12-31", &d)); + EXPECT_EQ("9223372036854775807-12-31", absl::FormatCivilTime(d)); + EXPECT_TRUE(absl::ParseLenientCivilTime("-9223372036854775808-01-01", &d)); + EXPECT_EQ("-9223372036854775808-01-01", absl::FormatCivilTime(d)); + + absl::CivilMonth m; + EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807-12", &m)); + EXPECT_EQ("9223372036854775807-12", absl::FormatCivilTime(m)); + EXPECT_TRUE(absl::ParseLenientCivilTime("-9223372036854775808-01", &m)); + EXPECT_EQ("-9223372036854775808-01", absl::FormatCivilTime(m)); + + absl::CivilYear y; + EXPECT_TRUE(absl::ParseLenientCivilTime("9223372036854775807", &y)); + EXPECT_EQ("9223372036854775807", absl::FormatCivilTime(y)); + EXPECT_TRUE(absl::ParseLenientCivilTime("-9223372036854775808", &y)); + EXPECT_EQ("-9223372036854775808", absl::FormatCivilTime(y)); + + // Tests some valid, but interesting, cases + EXPECT_TRUE(absl::ParseLenientCivilTime("0", &ss)) << ss; + EXPECT_EQ(absl::CivilYear(0), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime("0-1", &ss)) << ss; + EXPECT_EQ(absl::CivilMonth(0, 1), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015 ", &ss)) << ss; + EXPECT_EQ(absl::CivilYear(2015), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015-6 ", &ss)) << ss; + EXPECT_EQ(absl::CivilMonth(2015, 6), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-6-7", &ss)) << ss; + EXPECT_EQ(absl::CivilDay(2015, 6, 7), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015-6-7 ", &ss)) << ss; + EXPECT_EQ(absl::CivilDay(2015, 6, 7), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime("2015-06-07T10:11:12 ", &ss)) << ss; + EXPECT_EQ(absl::CivilSecond(2015, 6, 7, 10, 11, 12), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime(" 2015-06-07T10:11:12 ", &ss)) << ss; + EXPECT_EQ(absl::CivilSecond(2015, 6, 7, 10, 11, 12), ss); + EXPECT_TRUE(absl::ParseLenientCivilTime("-01-01", &ss)) << ss; + EXPECT_EQ(absl::CivilMonth(-1, 1), ss); + + // Tests some invalid cases + EXPECT_FALSE(absl::ParseLenientCivilTime("01-01-2015", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015-", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("0xff-01", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-30T04:05:06", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-03T04:05:96", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("X2015-02-03T04:05:06", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-03T04:05:003", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015 -02-03T04:05:06", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015-02-03-04:05:06", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("2015:02:03T04-05-06", &ss)) << ss; + EXPECT_FALSE(absl::ParseLenientCivilTime("9223372036854775808", &y)) << y; +} + +TEST(CivilTime, OutputStream) { + absl::CivilSecond cs(2016, 2, 3, 4, 5, 6); + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilYear(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016.................X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilMonth(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02..............X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilDay(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03...........X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilHour(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04........X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilMinute(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::CivilSecond(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << absl::Weekday::wednesday; + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..Wednesday............X..", ss.str()); + } +} + +TEST(CivilTime, Weekday) { + absl::CivilDay d(1970, 1, 1); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(d)) << d; + + // We used to get this wrong for years < -30. + d = absl::CivilDay(-31, 12, 24); + EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(d)) << d; +} + +TEST(CivilTime, NextPrevWeekday) { + // Jan 1, 1970 was a Thursday. + const absl::CivilDay thursday(1970, 1, 1); + + // Thursday -> Thursday + absl::CivilDay d = absl::NextWeekday(thursday, absl::Weekday::thursday); + EXPECT_EQ(7, d - thursday) << d; + EXPECT_EQ(d - 14, absl::PrevWeekday(thursday, absl::Weekday::thursday)); + + // Thursday -> Friday + d = absl::NextWeekday(thursday, absl::Weekday::friday); + EXPECT_EQ(1, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::friday)); + + // Thursday -> Saturday + d = absl::NextWeekday(thursday, absl::Weekday::saturday); + EXPECT_EQ(2, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::saturday)); + + // Thursday -> Sunday + d = absl::NextWeekday(thursday, absl::Weekday::sunday); + EXPECT_EQ(3, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::sunday)); + + // Thursday -> Monday + d = absl::NextWeekday(thursday, absl::Weekday::monday); + EXPECT_EQ(4, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::monday)); + + // Thursday -> Tuesday + d = absl::NextWeekday(thursday, absl::Weekday::tuesday); + EXPECT_EQ(5, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::tuesday)); + + // Thursday -> Wednesday + d = absl::NextWeekday(thursday, absl::Weekday::wednesday); + EXPECT_EQ(6, d - thursday) << d; + EXPECT_EQ(d - 7, absl::PrevWeekday(thursday, absl::Weekday::wednesday)); +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, DifferenceWithHugeYear) { + absl::CivilDay d1(9223372036854775807, 1, 1); + absl::CivilDay d2(9223372036854775807, 12, 31); + EXPECT_EQ(364, d2 - d1); + + d1 = absl::CivilDay(-9223372036854775807 - 1, 1, 1); + d2 = absl::CivilDay(-9223372036854775807 - 1, 12, 31); + EXPECT_EQ(365, d2 - d1); + + // Check the limits of the return value at the end of the year range. + d1 = absl::CivilDay(9223372036854775807, 1, 1); + d2 = absl::CivilDay(9198119301927009252, 6, 6); + EXPECT_EQ(9223372036854775807, d1 - d2); + d2 = d2 - 1; + EXPECT_EQ(-9223372036854775807 - 1, d2 - d1); + + // Check the limits of the return value at the start of the year range. + d1 = absl::CivilDay(-9223372036854775807 - 1, 1, 1); + d2 = absl::CivilDay(-9198119301927009254, 7, 28); + EXPECT_EQ(9223372036854775807, d2 - d1); + d2 = d2 + 1; + EXPECT_EQ(-9223372036854775807 - 1, d1 - d2); + + // Check the limits of the return value from either side of year 0. + d1 = absl::CivilDay(-12626367463883278, 9, 3); + d2 = absl::CivilDay(12626367463883277, 3, 28); + EXPECT_EQ(9223372036854775807, d2 - d1); + d2 = d2 + 1; + EXPECT_EQ(-9223372036854775807 - 1, d1 - d2); +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, DifferenceNoIntermediateOverflow) { + // The difference up to the minute field would be below the minimum + // int64_t, but the 52 extra seconds brings us back to the minimum. + absl::CivilSecond s1(-292277022657, 1, 27, 8, 29 - 1, 52); + absl::CivilSecond s2(1970, 1, 1, 0, 0 - 1, 0); + EXPECT_EQ(-9223372036854775807 - 1, s1 - s2); + + // The difference up to the minute field would be above the maximum + // int64_t, but the -53 extra seconds brings us back to the maximum. + s1 = absl::CivilSecond(292277026596, 12, 4, 15, 30, 7 - 7); + s2 = absl::CivilSecond(1970, 1, 1, 0, 0, 0 - 7); + EXPECT_EQ(9223372036854775807, s1 - s2); +} + +TEST(CivilTime, NormalizeSimpleOverflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 59 + 1); + EXPECT_EQ("2013-11-15T16:33:00", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 59 + 1, 14); + EXPECT_EQ("2013-11-15T17:00:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 23 + 1, 32, 14); + EXPECT_EQ("2013-11-16T00:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 30 + 1, 16, 32, 14); + EXPECT_EQ("2013-12-01T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 12 + 1, 15, 16, 32, 14); + EXPECT_EQ("2014-01-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeSimpleUnderflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 0 - 1); + EXPECT_EQ("2013-11-15T16:31:59", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 0 - 1, 14); + EXPECT_EQ("2013-11-15T15:59:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 0 - 1, 32, 14); + EXPECT_EQ("2013-11-14T23:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 1 - 1, 16, 32, 14); + EXPECT_EQ("2013-10-31T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 1 - 1, 15, 16, 32, 14); + EXPECT_EQ("2012-12-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeMultipleOverflow) { + absl::CivilSecond cs(2013, 12, 31, 23, 59, 59 + 1); + EXPECT_EQ("2014-01-01T00:00:00", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeMultipleUnderflow) { + absl::CivilSecond cs(2014, 1, 1, 0, 0, 0 - 1); + EXPECT_EQ("2013-12-31T23:59:59", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeOverflowLimits) { + absl::CivilSecond cs; + + const int kintmax = std::numeric_limits<int>::max(); + cs = absl::CivilSecond(0, kintmax, kintmax, kintmax, kintmax, kintmax); + EXPECT_EQ("185085715-11-27T12:21:07", absl::FormatCivilTime(cs)); + + const int kintmin = std::numeric_limits<int>::min(); + cs = absl::CivilSecond(0, kintmin, kintmin, kintmin, kintmin, kintmin); + EXPECT_EQ("-185085717-10-31T10:37:52", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeComplexOverflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 14 + 123456789); + EXPECT_EQ("2017-10-14T14:05:23", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 32 + 1234567, 14); + EXPECT_EQ("2016-03-22T00:39:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16 + 123456, 32, 14); + EXPECT_EQ("2027-12-16T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15 + 1234, 16, 32, 14); + EXPECT_EQ("2017-04-02T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 + 123, 15, 16, 32, 14); + EXPECT_EQ("2024-02-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeComplexUnderflow) { + absl::CivilSecond cs; + cs = absl::CivilSecond(1999, 3, 0, 0, 0, 0); // year 400 + EXPECT_EQ("1999-02-28T00:00:00", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 32, 14 - 123456789); + EXPECT_EQ("2009-12-17T18:59:05", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16, 32 - 1234567, 14); + EXPECT_EQ("2011-07-12T08:25:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15, 16 - 123456, 32, 14); + EXPECT_EQ("1999-10-16T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11, 15 - 1234, 16, 32, 14); + EXPECT_EQ("2010-06-30T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 - 123, 15, 16, 32, 14); + EXPECT_EQ("2003-08-15T16:32:14", absl::FormatCivilTime(cs)); +} + +TEST(CivilTime, NormalizeMishmash) { + absl::CivilSecond cs; + cs = absl::CivilSecond(2013, 11 - 123, 15 + 1234, 16 - 123456, 32 + 1234567, + 14 - 123456789); + EXPECT_EQ("1991-05-09T03:06:05", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 + 123, 15 - 1234, 16 + 123456, 32 - 1234567, + 14 + 123456789); + EXPECT_EQ("2036-05-24T05:58:23", absl::FormatCivilTime(cs)); + + cs = absl::CivilSecond(2013, 11, -146097 + 1, 16, 32, 14); + EXPECT_EQ("1613-11-01T16:32:14", absl::FormatCivilTime(cs)); + cs = absl::CivilSecond(2013, 11 + 400 * 12, -146097 + 1, 16, 32, 14); + EXPECT_EQ("2013-11-01T16:32:14", absl::FormatCivilTime(cs)); +} + +// Convert all the days from 1970-1-1 to 1970-1-146097 (aka 2369-12-31) +// and check that they normalize to the expected time. 146097 days span +// the 400-year Gregorian cycle used during normalization. +TEST(CivilTime, NormalizeAllTheDays) { + absl::CivilDay expected(1970, 1, 1); + for (int day = 1; day <= 146097; ++day) { + absl::CivilSecond cs(1970, 1, day, 0, 0, 0); + EXPECT_EQ(expected, cs); + ++expected; + } +} + +TEST(CivilTime, NormalizeWithHugeYear) { + absl::CivilMonth c(9223372036854775807, 1); + EXPECT_EQ("9223372036854775807-01", absl::FormatCivilTime(c)); + c = c - 1; // Causes normalization + EXPECT_EQ("9223372036854775806-12", absl::FormatCivilTime(c)); + + c = absl::CivilMonth(-9223372036854775807 - 1, 1); + EXPECT_EQ("-9223372036854775808-01", absl::FormatCivilTime(c)); + c = c + 12; // Causes normalization + EXPECT_EQ("-9223372036854775807-01", absl::FormatCivilTime(c)); +} + +TEST(CivilTime, LeapYears) { + const absl::CivilSecond s1(2013, 2, 28 + 1, 0, 0, 0); + EXPECT_EQ("2013-03-01T00:00:00", absl::FormatCivilTime(s1)); + + const absl::CivilSecond s2(2012, 2, 28 + 1, 0, 0, 0); + EXPECT_EQ("2012-02-29T00:00:00", absl::FormatCivilTime(s2)); + + const absl::CivilSecond s3(1900, 2, 28 + 1, 0, 0, 0); + EXPECT_EQ("1900-03-01T00:00:00", absl::FormatCivilTime(s3)); + + const struct { + int year; + int days; + struct { + int month; + int day; + } leap_day; // The date of the day after Feb 28. + } kLeapYearTable[]{ + {1900, 365, {3, 1}}, + {1999, 365, {3, 1}}, + {2000, 366, {2, 29}}, // leap year + {2001, 365, {3, 1}}, + {2002, 365, {3, 1}}, + {2003, 365, {3, 1}}, + {2004, 366, {2, 29}}, // leap year + {2005, 365, {3, 1}}, + {2006, 365, {3, 1}}, + {2007, 365, {3, 1}}, + {2008, 366, {2, 29}}, // leap year + {2009, 365, {3, 1}}, + {2100, 365, {3, 1}}, + }; + + for (int i = 0; i < ABSL_ARRAYSIZE(kLeapYearTable); ++i) { + const int y = kLeapYearTable[i].year; + const int m = kLeapYearTable[i].leap_day.month; + const int d = kLeapYearTable[i].leap_day.day; + const int n = kLeapYearTable[i].days; + + // Tests incrementing through the leap day. + const absl::CivilDay feb28(y, 2, 28); + const absl::CivilDay next_day = feb28 + 1; + EXPECT_EQ(m, next_day.month()); + EXPECT_EQ(d, next_day.day()); + + // Tests difference in days of leap years. + const absl::CivilYear year(feb28); + const absl::CivilYear next_year = year + 1; + EXPECT_EQ(n, absl::CivilDay(next_year) - absl::CivilDay(year)); + } +} + +TEST(CivilTime, FirstThursdayInMonth) { + const absl::CivilDay nov1(2014, 11, 1); + const absl::CivilDay thursday = + absl::NextWeekday(nov1 - 1, absl::Weekday::thursday); + EXPECT_EQ("2014-11-06", absl::FormatCivilTime(thursday)); + + // Bonus: Date of Thanksgiving in the United States + // Rule: Fourth Thursday of November + const absl::CivilDay thanksgiving = thursday + 7 * 3; + EXPECT_EQ("2014-11-27", absl::FormatCivilTime(thanksgiving)); +} + +TEST(CivilTime, DocumentationExample) { + absl::CivilSecond second(2015, 6, 28, 1, 2, 3); // 2015-06-28 01:02:03 + absl::CivilMinute minute(second); // 2015-06-28 01:02:00 + absl::CivilDay day(minute); // 2015-06-28 00:00:00 + + second -= 1; // 2015-06-28 01:02:02 + --second; // 2015-06-28 01:02:01 + EXPECT_EQ(minute, second - 1); // Comparison between types + EXPECT_LT(minute, second); + + // int diff = second - minute; // ERROR: Mixed types, won't compile + + absl::CivilDay june_1(2015, 6, 1); // Pass fields to c'tor. + int diff = day - june_1; // Num days between 'day' and June 1 + EXPECT_EQ(27, diff); + + // Fields smaller than alignment are floored to their minimum value. + absl::CivilDay day_floor(2015, 1, 2, 9, 9, 9); + EXPECT_EQ(0, day_floor.hour()); // 09:09:09 is floored + EXPECT_EQ(absl::CivilDay(2015, 1, 2), day_floor); + + // Unspecified fields default to their minium value + absl::CivilDay day_default(2015); // Defaults to Jan 1 + EXPECT_EQ(absl::CivilDay(2015, 1, 1), day_default); + + // Iterates all the days of June. + absl::CivilMonth june(day); // CivilDay -> CivilMonth + absl::CivilMonth july = june + 1; + for (absl::CivilDay day = june_1; day < july; ++day) { + // ... + } +} + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/clock.cc b/third_party/abseil_cpp/absl/time/clock.cc new file mode 100644 index 000000000000..6862e011be1f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/clock.cc @@ -0,0 +1,567 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/clock.h" + +#include "absl/base/attributes.h" + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <algorithm> +#include <atomic> +#include <cerrno> +#include <cstdint> +#include <ctime> +#include <limits> + +#include "absl/base/internal/spinlock.h" +#include "absl/base/internal/unscaledcycleclock.h" +#include "absl/base/macros.h" +#include "absl/base/port.h" +#include "absl/base/thread_annotations.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +Time Now() { + // TODO(bww): Get a timespec instead so we don't have to divide. + int64_t n = absl::GetCurrentTimeNanos(); + if (n >= 0) { + return time_internal::FromUnixDuration( + time_internal::MakeDuration(n / 1000000000, n % 1000000000 * 4)); + } + return time_internal::FromUnixDuration(absl::Nanoseconds(n)); +} +ABSL_NAMESPACE_END +} // namespace absl + +// Decide if we should use the fast GetCurrentTimeNanos() algorithm +// based on the cyclecounter, otherwise just get the time directly +// from the OS on every call. This can be chosen at compile-time via +// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1] +#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS +#if ABSL_USE_UNSCALED_CYCLECLOCK +#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 1 +#else +#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0 +#endif +#endif + +#if defined(__APPLE__) || defined(_WIN32) +#include "absl/time/internal/get_current_time_chrono.inc" +#else +#include "absl/time/internal/get_current_time_posix.inc" +#endif + +// Allows override by test. +#ifndef GET_CURRENT_TIME_NANOS_FROM_SYSTEM +#define GET_CURRENT_TIME_NANOS_FROM_SYSTEM() \ + ::absl::time_internal::GetCurrentTimeNanosFromSystem() +#endif + +#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS +namespace absl { +ABSL_NAMESPACE_BEGIN +int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); } +ABSL_NAMESPACE_END +} // namespace absl +#else // Use the cyclecounter-based implementation below. + +// Allows override by test. +#ifndef GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW +#define GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW() \ + ::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now() +#endif + +// The following counters are used only by the test code. +static int64_t stats_initializations; +static int64_t stats_reinitializations; +static int64_t stats_calibrations; +static int64_t stats_slow_paths; +static int64_t stats_fast_slow_paths; + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +// This is a friend wrapper around UnscaledCycleClock::Now() +// (needed to access UnscaledCycleClock). +class UnscaledCycleClockWrapperForGetCurrentTime { + public: + static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); } +}; +} // namespace time_internal + +// uint64_t is used in this module to provide an extra bit in multiplications + +// Return the time in ns as told by the kernel interface. Place in *cycleclock +// the value of the cycleclock at about the time of the syscall. +// This call represents the time base that this module synchronizes to. +// Ensures that *cycleclock does not step back by up to (1 << 16) from +// last_cycleclock, to discard small backward counter steps. (Larger steps are +// assumed to be complete resyncs, which shouldn't happen. If they do, a full +// reinitialization of the outer algorithm should occur.) +static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock, + uint64_t *cycleclock) { + // We try to read clock values at about the same time as the kernel clock. + // This value gets adjusted up or down as estimate of how long that should + // take, so we can reject attempts that take unusually long. + static std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000}; + + uint64_t local_approx_syscall_time_in_cycles = // local copy + approx_syscall_time_in_cycles.load(std::memory_order_relaxed); + + int64_t current_time_nanos_from_system; + uint64_t before_cycles; + uint64_t after_cycles; + uint64_t elapsed_cycles; + int loops = 0; + do { + before_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW(); + current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); + after_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW(); + // elapsed_cycles is unsigned, so is large on overflow + elapsed_cycles = after_cycles - before_cycles; + if (elapsed_cycles >= local_approx_syscall_time_in_cycles && + ++loops == 20) { // clock changed frequencies? Back off. + loops = 0; + if (local_approx_syscall_time_in_cycles < 1000 * 1000) { + local_approx_syscall_time_in_cycles = + (local_approx_syscall_time_in_cycles + 1) << 1; + } + approx_syscall_time_in_cycles.store( + local_approx_syscall_time_in_cycles, + std::memory_order_relaxed); + } + } while (elapsed_cycles >= local_approx_syscall_time_in_cycles || + last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16)); + + // Number of times in a row we've seen a kernel time call take substantially + // less than approx_syscall_time_in_cycles. + static std::atomic<uint32_t> seen_smaller{ 0 }; + + // Adjust approx_syscall_time_in_cycles to be within a factor of 2 + // of the typical time to execute one iteration of the loop above. + if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) { + // measured time is no smaller than half current approximation + seen_smaller.store(0, std::memory_order_relaxed); + } else if (seen_smaller.fetch_add(1, std::memory_order_relaxed) >= 3) { + // smaller delays several times in a row; reduce approximation by 12.5% + const uint64_t new_approximation = + local_approx_syscall_time_in_cycles - + (local_approx_syscall_time_in_cycles >> 3); + approx_syscall_time_in_cycles.store(new_approximation, + std::memory_order_relaxed); + seen_smaller.store(0, std::memory_order_relaxed); + } + + *cycleclock = after_cycles; + return current_time_nanos_from_system; +} + + +// --------------------------------------------------------------------- +// An implementation of reader-write locks that use no atomic ops in the read +// case. This is a generalization of Lamport's method for reading a multiword +// clock. Increment a word on each write acquisition, using the low-order bit +// as a spinlock; the word is the high word of the "clock". Readers read the +// high word, then all other data, then the high word again, and repeat the +// read if the reads of the high words yields different answers, or an odd +// value (either case suggests possible interference from a writer). +// Here we use a spinlock to ensure only one writer at a time, rather than +// spinning on the bottom bit of the word to benefit from SpinLock +// spin-delay tuning. + +// Acquire seqlock (*seq) and return the value to be written to unlock. +static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) { + uint64_t x = seq->fetch_add(1, std::memory_order_relaxed); + + // We put a release fence between update to *seq and writes to shared data. + // Thus all stores to shared data are effectively release operations and + // update to *seq above cannot be re-ordered past any of them. Note that + // this barrier is not for the fetch_add above. A release barrier for the + // fetch_add would be before it, not after. + std::atomic_thread_fence(std::memory_order_release); + + return x + 2; // original word plus 2 +} + +// Release seqlock (*seq) by writing x to it---a value previously returned by +// SeqAcquire. +static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) { + // The unlock store to *seq must have release ordering so that all + // updates to shared data must finish before this store. + seq->store(x, std::memory_order_release); // release lock for readers +} + +// --------------------------------------------------------------------- + +// "nsscaled" is unit of time equal to a (2**kScale)th of a nanosecond. +enum { kScale = 30 }; + +// The minimum interval between samples of the time base. +// We pick enough time to amortize the cost of the sample, +// to get a reasonably accurate cycle counter rate reading, +// and not so much that calculations will overflow 64-bits. +static const uint64_t kMinNSBetweenSamples = 2000 << 20; + +// We require that kMinNSBetweenSamples shifted by kScale +// have at least a bit left over for 64-bit calculations. +static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) == + kMinNSBetweenSamples, + "cannot represent kMaxBetweenSamplesNSScaled"); + +// A reader-writer lock protecting the static locations below. +// See SeqAcquire() and SeqRelease() above. +ABSL_CONST_INIT static absl::base_internal::SpinLock lock( + absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY); +ABSL_CONST_INIT static std::atomic<uint64_t> seq(0); + +// data from a sample of the kernel's time value +struct TimeSampleAtomic { + std::atomic<uint64_t> raw_ns; // raw kernel time + std::atomic<uint64_t> base_ns; // our estimate of time + std::atomic<uint64_t> base_cycles; // cycle counter reading + std::atomic<uint64_t> nsscaled_per_cycle; // cycle period + // cycles before we'll sample again (a scaled reciprocal of the period, + // to avoid a division on the fast path). + std::atomic<uint64_t> min_cycles_per_sample; +}; +// Same again, but with non-atomic types +struct TimeSample { + uint64_t raw_ns; // raw kernel time + uint64_t base_ns; // our estimate of time + uint64_t base_cycles; // cycle counter reading + uint64_t nsscaled_per_cycle; // cycle period + uint64_t min_cycles_per_sample; // approx cycles before next sample +}; + +static struct TimeSampleAtomic last_sample; // the last sample; under seq + +static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD; + +// Read the contents of *atomic into *sample. +// Each field is read atomically, but to maintain atomicity between fields, +// the access must be done under a lock. +static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic, + struct TimeSample *sample) { + sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed); + sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed); + sample->nsscaled_per_cycle = + atomic->nsscaled_per_cycle.load(std::memory_order_relaxed); + sample->min_cycles_per_sample = + atomic->min_cycles_per_sample.load(std::memory_order_relaxed); + sample->raw_ns = atomic->raw_ns.load(std::memory_order_relaxed); +} + +// Public routine. +// Algorithm: We wish to compute real time from a cycle counter. In normal +// operation, we construct a piecewise linear approximation to the kernel time +// source, using the cycle counter value. The start of each line segment is at +// the same point as the end of the last, but may have a different slope (that +// is, a different idea of the cycle counter frequency). Every couple of +// seconds, the kernel time source is sampled and compared with the current +// approximation. A new slope is chosen that, if followed for another couple +// of seconds, will correct the error at the current position. The information +// for a sample is in the "last_sample" struct. The linear approximation is +// estimated_time = last_sample.base_ns + +// last_sample.ns_per_cycle * (counter_reading - last_sample.base_cycles) +// (ns_per_cycle is actually stored in different units and scaled, to avoid +// overflow). The base_ns of the next linear approximation is the +// estimated_time using the last approximation; the base_cycles is the cycle +// counter value at that time; the ns_per_cycle is the number of ns per cycle +// measured since the last sample, but adjusted so that most of the difference +// between the estimated_time and the kernel time will be corrected by the +// estimated time to the next sample. In normal operation, this algorithm +// relies on: +// - the cycle counter and kernel time rates not changing a lot in a few +// seconds. +// - the client calling into the code often compared to a couple of seconds, so +// the time to the next correction can be estimated. +// Any time ns_per_cycle is not known, a major error is detected, or the +// assumption about frequent calls is violated, the implementation returns the +// kernel time. It records sufficient data that a linear approximation can +// resume a little later. + +int64_t GetCurrentTimeNanos() { + // read the data from the "last_sample" struct (but don't need raw_ns yet) + // The reads of "seq" and test of the values emulate a reader lock. + uint64_t base_ns; + uint64_t base_cycles; + uint64_t nsscaled_per_cycle; + uint64_t min_cycles_per_sample; + uint64_t seq_read0; + uint64_t seq_read1; + + // If we have enough information to interpolate, the value returned will be + // derived from this cycleclock-derived time estimate. On some platforms + // (POWER) the function to retrieve this value has enough complexity to + // contribute to register pressure - reading it early before initializing + // the other pieces of the calculation minimizes spill/restore instructions, + // minimizing icache cost. + uint64_t now_cycles = GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW(); + + // Acquire pairs with the barrier in SeqRelease - if this load sees that + // store, the shared-data reads necessarily see that SeqRelease's updates + // to the same shared data. + seq_read0 = seq.load(std::memory_order_acquire); + + base_ns = last_sample.base_ns.load(std::memory_order_relaxed); + base_cycles = last_sample.base_cycles.load(std::memory_order_relaxed); + nsscaled_per_cycle = + last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed); + min_cycles_per_sample = + last_sample.min_cycles_per_sample.load(std::memory_order_relaxed); + + // This acquire fence pairs with the release fence in SeqAcquire. Since it + // is sequenced between reads of shared data and seq_read1, the reads of + // shared data are effectively acquiring. + std::atomic_thread_fence(std::memory_order_acquire); + + // The shared-data reads are effectively acquire ordered, and the + // shared-data writes are effectively release ordered. Therefore if our + // shared-data reads see any of a particular update's shared-data writes, + // seq_read1 is guaranteed to see that update's SeqAcquire. + seq_read1 = seq.load(std::memory_order_relaxed); + + // Fast path. Return if min_cycles_per_sample has not yet elapsed since the + // last sample, and we read a consistent sample. The fast path activates + // only when min_cycles_per_sample is non-zero, which happens when we get an + // estimate for the cycle time. The predicate will fail if now_cycles < + // base_cycles, or if some other thread is in the slow path. + // + // Since we now read now_cycles before base_ns, it is possible for now_cycles + // to be less than base_cycles (if we were interrupted between those loads and + // last_sample was updated). This is harmless, because delta_cycles will wrap + // and report a time much much bigger than min_cycles_per_sample. In that case + // we will take the slow path. + uint64_t delta_cycles = now_cycles - base_cycles; + if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 && + delta_cycles < min_cycles_per_sample) { + return base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale); + } + return GetCurrentTimeNanosSlowPath(); +} + +// Return (a << kScale)/b. +// Zero is returned if b==0. Scaling is performed internally to +// preserve precision without overflow. +static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) { + // Find maximum safe_shift so that + // 0 <= safe_shift <= kScale and (a << safe_shift) does not overflow. + int safe_shift = kScale; + while (((a << safe_shift) >> safe_shift) != a) { + safe_shift--; + } + uint64_t scaled_b = b >> (kScale - safe_shift); + uint64_t quotient = 0; + if (scaled_b != 0) { + quotient = (a << safe_shift) / scaled_b; + } + return quotient; +} + +static uint64_t UpdateLastSample( + uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles, + const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD; + +// The slow path of GetCurrentTimeNanos(). This is taken while gathering +// initial samples, when enough time has elapsed since the last sample, and if +// any other thread is writing to last_sample. +// +// Manually mark this 'noinline' to minimize stack frame size of the fast +// path. Without this, sometimes a compiler may inline this big block of code +// into the fast path. That causes lots of register spills and reloads that +// are unnecessary unless the slow path is taken. +// +// TODO(absl-team): Remove this attribute when our compiler is smart enough +// to do the right thing. +ABSL_ATTRIBUTE_NOINLINE +static int64_t GetCurrentTimeNanosSlowPath() ABSL_LOCKS_EXCLUDED(lock) { + // Serialize access to slow-path. Fast-path readers are not blocked yet, and + // code below must not modify last_sample until the seqlock is acquired. + lock.Lock(); + + // Sample the kernel time base. This is the definition of + // "now" if we take the slow path. + static uint64_t last_now_cycles; // protected by lock + uint64_t now_cycles; + uint64_t now_ns = GetCurrentTimeNanosFromKernel(last_now_cycles, &now_cycles); + last_now_cycles = now_cycles; + + uint64_t estimated_base_ns; + + // ---------- + // Read the "last_sample" values again; this time holding the write lock. + struct TimeSample sample; + ReadTimeSampleAtomic(&last_sample, &sample); + + // ---------- + // Try running the fast path again; another thread may have updated the + // sample between our run of the fast path and the sample we just read. + uint64_t delta_cycles = now_cycles - sample.base_cycles; + if (delta_cycles < sample.min_cycles_per_sample) { + // Another thread updated the sample. This path does not take the seqlock + // so that blocked readers can make progress without blocking new readers. + estimated_base_ns = sample.base_ns + + ((delta_cycles * sample.nsscaled_per_cycle) >> kScale); + stats_fast_slow_paths++; + } else { + estimated_base_ns = + UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample); + } + + lock.Unlock(); + + return estimated_base_ns; +} + +// Main part of the algorithm. Locks out readers, updates the approximation +// using the new sample from the kernel, and stores the result in last_sample +// for readers. Returns the new estimated time. +static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns, + uint64_t delta_cycles, + const struct TimeSample *sample) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) { + uint64_t estimated_base_ns = now_ns; + uint64_t lock_value = SeqAcquire(&seq); // acquire seqlock to block readers + + // The 5s in the next if-statement limits the time for which we will trust + // the cycle counter and our last sample to give a reasonable result. + // Errors in the rate of the source clock can be multiplied by the ratio + // between this limit and kMinNSBetweenSamples. + if (sample->raw_ns == 0 || // no recent sample, or clock went backwards + sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns || + now_ns < sample->raw_ns || now_cycles < sample->base_cycles) { + // record this sample, and forget any previously known slope. + last_sample.raw_ns.store(now_ns, std::memory_order_relaxed); + last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed); + last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed); + last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed); + last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed); + stats_initializations++; + } else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns && + sample->base_cycles + 50 < now_cycles) { + // Enough time has passed to compute the cycle time. + if (sample->nsscaled_per_cycle != 0) { // Have a cycle time estimate. + // Compute time from counter reading, but avoiding overflow + // delta_cycles may be larger than on the fast path. + uint64_t estimated_scaled_ns; + int s = -1; + do { + s++; + estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle; + } while (estimated_scaled_ns / sample->nsscaled_per_cycle != + (delta_cycles >> s)); + estimated_base_ns = sample->base_ns + + (estimated_scaled_ns >> (kScale - s)); + } + + // Compute the assumed cycle time kMinNSBetweenSamples ns into the future + // assuming the cycle counter rate stays the same as the last interval. + uint64_t ns = now_ns - sample->raw_ns; + uint64_t measured_nsscaled_per_cycle = SafeDivideAndScale(ns, delta_cycles); + + uint64_t assumed_next_sample_delta_cycles = + SafeDivideAndScale(kMinNSBetweenSamples, measured_nsscaled_per_cycle); + + int64_t diff_ns = now_ns - estimated_base_ns; // estimate low by this much + + // We want to set nsscaled_per_cycle so that our estimate of the ns time + // at the assumed cycle time is the assumed ns time. + // That is, we want to set nsscaled_per_cycle so: + // kMinNSBetweenSamples + diff_ns == + // (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale + // But we wish to damp oscillations, so instead correct only most + // of our current error, by solving: + // kMinNSBetweenSamples + diff_ns - (diff_ns / 16) == + // (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale + ns = kMinNSBetweenSamples + diff_ns - (diff_ns / 16); + uint64_t new_nsscaled_per_cycle = + SafeDivideAndScale(ns, assumed_next_sample_delta_cycles); + if (new_nsscaled_per_cycle != 0 && + diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) { + // record the cycle time measurement + last_sample.nsscaled_per_cycle.store( + new_nsscaled_per_cycle, std::memory_order_relaxed); + uint64_t new_min_cycles_per_sample = + SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle); + last_sample.min_cycles_per_sample.store( + new_min_cycles_per_sample, std::memory_order_relaxed); + stats_calibrations++; + } else { // something went wrong; forget the slope + last_sample.nsscaled_per_cycle.store(0, std::memory_order_relaxed); + last_sample.min_cycles_per_sample.store(0, std::memory_order_relaxed); + estimated_base_ns = now_ns; + stats_reinitializations++; + } + last_sample.raw_ns.store(now_ns, std::memory_order_relaxed); + last_sample.base_ns.store(estimated_base_ns, std::memory_order_relaxed); + last_sample.base_cycles.store(now_cycles, std::memory_order_relaxed); + } else { + // have a sample, but no slope; waiting for enough time for a calibration + stats_slow_paths++; + } + + SeqRelease(&seq, lock_value); // release the readers + + return estimated_base_ns; +} +ABSL_NAMESPACE_END +} // namespace absl +#endif // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace { + +// Returns the maximum duration that SleepOnce() can sleep for. +constexpr absl::Duration MaxSleep() { +#ifdef _WIN32 + // Windows Sleep() takes unsigned long argument in milliseconds. + return absl::Milliseconds( + std::numeric_limits<unsigned long>::max()); // NOLINT(runtime/int) +#else + return absl::Seconds(std::numeric_limits<time_t>::max()); +#endif +} + +// Sleeps for the given duration. +// REQUIRES: to_sleep <= MaxSleep(). +void SleepOnce(absl::Duration to_sleep) { +#ifdef _WIN32 + Sleep(to_sleep / absl::Milliseconds(1)); +#else + struct timespec sleep_time = absl::ToTimespec(to_sleep); + while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) { + // Ignore signals and wait for the full interval to elapse. + } +#endif +} + +} // namespace +ABSL_NAMESPACE_END +} // namespace absl + +extern "C" { + +ABSL_ATTRIBUTE_WEAK void AbslInternalSleepFor(absl::Duration duration) { + while (duration > absl::ZeroDuration()) { + absl::Duration to_sleep = std::min(duration, absl::MaxSleep()); + absl::SleepOnce(to_sleep); + duration -= to_sleep; + } +} + +} // extern "C" diff --git a/third_party/abseil_cpp/absl/time/clock.h b/third_party/abseil_cpp/absl/time/clock.h new file mode 100644 index 000000000000..27764a922d5e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/clock.h @@ -0,0 +1,74 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: clock.h +// ----------------------------------------------------------------------------- +// +// This header file contains utility functions for working with the system-wide +// realtime clock. For descriptions of the main time abstractions used within +// this header file, consult the time.h header file. +#ifndef ABSL_TIME_CLOCK_H_ +#define ABSL_TIME_CLOCK_H_ + +#include "absl/base/macros.h" +#include "absl/time/time.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +// Now() +// +// Returns the current time, expressed as an `absl::Time` absolute time value. +absl::Time Now(); + +// GetCurrentTimeNanos() +// +// Returns the current time, expressed as a count of nanoseconds since the Unix +// Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead +// for all but the most performance-sensitive cases (i.e. when you are calling +// this function hundreds of thousands of times per second). +int64_t GetCurrentTimeNanos(); + +// SleepFor() +// +// Sleeps for the specified duration, expressed as an `absl::Duration`. +// +// Notes: +// * Signal interruptions will not reduce the sleep duration. +// * Returns immediately when passed a nonpositive duration. +void SleepFor(absl::Duration duration); + +ABSL_NAMESPACE_END +} // namespace absl + +// ----------------------------------------------------------------------------- +// Implementation Details +// ----------------------------------------------------------------------------- + +// In some build configurations we pass --detect-odr-violations to the +// gold linker. This causes it to flag weak symbol overrides as ODR +// violations. Because ODR only applies to C++ and not C, +// --detect-odr-violations ignores symbols not mangled with C++ names. +// By changing our extension points to be extern "C", we dodge this +// check. +extern "C" { +void AbslInternalSleepFor(absl::Duration duration); +} // extern "C" + +inline void absl::SleepFor(absl::Duration duration) { + AbslInternalSleepFor(duration); +} + +#endif // ABSL_TIME_CLOCK_H_ diff --git a/third_party/abseil_cpp/absl/time/clock_benchmark.cc b/third_party/abseil_cpp/absl/time/clock_benchmark.cc new file mode 100644 index 000000000000..c5c795ecbd23 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/clock_benchmark.cc @@ -0,0 +1,74 @@ +// Copyright 2018 The Abseil Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/clock.h" + +#if !defined(_WIN32) +#include <sys/time.h> +#else +#include <winsock2.h> +#endif // _WIN32 +#include <cstdio> + +#include "absl/base/internal/cycleclock.h" +#include "benchmark/benchmark.h" + +namespace { + +void BM_Clock_Now_AbslTime(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Now()); + } +} +BENCHMARK(BM_Clock_Now_AbslTime); + +void BM_Clock_Now_GetCurrentTimeNanos(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::GetCurrentTimeNanos()); + } +} +BENCHMARK(BM_Clock_Now_GetCurrentTimeNanos); + +void BM_Clock_Now_AbslTime_ToUnixNanos(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToUnixNanos(absl::Now())); + } +} +BENCHMARK(BM_Clock_Now_AbslTime_ToUnixNanos); + +void BM_Clock_Now_CycleClock(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::base_internal::CycleClock::Now()); + } +} +BENCHMARK(BM_Clock_Now_CycleClock); + +#if !defined(_WIN32) +static void BM_Clock_Now_gettimeofday(benchmark::State& state) { + struct timeval tv; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(gettimeofday(&tv, nullptr)); + } +} +BENCHMARK(BM_Clock_Now_gettimeofday); + +static void BM_Clock_Now_clock_gettime(benchmark::State& state) { + struct timespec ts; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(clock_gettime(CLOCK_REALTIME, &ts)); + } +} +BENCHMARK(BM_Clock_Now_clock_gettime); +#endif // _WIN32 + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/clock_test.cc b/third_party/abseil_cpp/absl/time/clock_test.cc new file mode 100644 index 000000000000..4bcfc6bc7272 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/clock_test.cc @@ -0,0 +1,118 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/clock.h" + +#include "absl/base/config.h" +#if defined(ABSL_HAVE_ALARM) +#include <signal.h> +#include <unistd.h> +#elif defined(__linux__) || defined(__APPLE__) +#error all known Linux and Apple targets have alarm +#endif + +#include "gtest/gtest.h" +#include "absl/time/time.h" + +namespace { + +TEST(Time, Now) { + const absl::Time before = absl::FromUnixNanos(absl::GetCurrentTimeNanos()); + const absl::Time now = absl::Now(); + const absl::Time after = absl::FromUnixNanos(absl::GetCurrentTimeNanos()); + EXPECT_GE(now, before); + EXPECT_GE(after, now); +} + +enum class AlarmPolicy { kWithoutAlarm, kWithAlarm }; + +#if defined(ABSL_HAVE_ALARM) +bool alarm_handler_invoked = false; + +void AlarmHandler(int signo) { + ASSERT_EQ(signo, SIGALRM); + alarm_handler_invoked = true; +} +#endif + +// Does SleepFor(d) take between lower_bound and upper_bound at least +// once between now and (now + timeout)? If requested (and supported), +// add an alarm for the middle of the sleep period and expect it to fire. +bool SleepForBounded(absl::Duration d, absl::Duration lower_bound, + absl::Duration upper_bound, absl::Duration timeout, + AlarmPolicy alarm_policy, int* attempts) { + const absl::Time deadline = absl::Now() + timeout; + while (absl::Now() < deadline) { +#if defined(ABSL_HAVE_ALARM) + sig_t old_alarm = SIG_DFL; + if (alarm_policy == AlarmPolicy::kWithAlarm) { + alarm_handler_invoked = false; + old_alarm = signal(SIGALRM, AlarmHandler); + alarm(absl::ToInt64Seconds(d / 2)); + } +#else + EXPECT_EQ(alarm_policy, AlarmPolicy::kWithoutAlarm); +#endif + ++*attempts; + absl::Time start = absl::Now(); + absl::SleepFor(d); + absl::Duration actual = absl::Now() - start; +#if defined(ABSL_HAVE_ALARM) + if (alarm_policy == AlarmPolicy::kWithAlarm) { + signal(SIGALRM, old_alarm); + if (!alarm_handler_invoked) continue; + } +#endif + if (lower_bound <= actual && actual <= upper_bound) { + return true; // yes, the SleepFor() was correctly bounded + } + } + return false; +} + +testing::AssertionResult AssertSleepForBounded(absl::Duration d, + absl::Duration early, + absl::Duration late, + absl::Duration timeout, + AlarmPolicy alarm_policy) { + const absl::Duration lower_bound = d - early; + const absl::Duration upper_bound = d + late; + int attempts = 0; + if (SleepForBounded(d, lower_bound, upper_bound, timeout, alarm_policy, + &attempts)) { + return testing::AssertionSuccess(); + } + return testing::AssertionFailure() + << "SleepFor(" << d << ") did not return within [" << lower_bound + << ":" << upper_bound << "] in " << attempts << " attempt" + << (attempts == 1 ? "" : "s") << " over " << timeout + << (alarm_policy == AlarmPolicy::kWithAlarm ? " with" : " without") + << " an alarm"; +} + +// Tests that SleepFor() returns neither too early nor too late. +TEST(SleepFor, Bounded) { + const absl::Duration d = absl::Milliseconds(2500); + const absl::Duration early = absl::Milliseconds(100); + const absl::Duration late = absl::Milliseconds(300); + const absl::Duration timeout = 48 * d; + EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout, + AlarmPolicy::kWithoutAlarm)); +#if defined(ABSL_HAVE_ALARM) + EXPECT_TRUE(AssertSleepForBounded(d, early, late, timeout, + AlarmPolicy::kWithAlarm)); +#endif +} + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/duration.cc b/third_party/abseil_cpp/absl/time/duration.cc new file mode 100644 index 000000000000..4443109a5121 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/duration.cc @@ -0,0 +1,954 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The implementation of the absl::Duration class, which is declared in +// //absl/time.h. This class behaves like a numeric type; it has no public +// methods and is used only through the operators defined here. +// +// Implementation notes: +// +// An absl::Duration is represented as +// +// rep_hi_ : (int64_t) Whole seconds +// rep_lo_ : (uint32_t) Fractions of a second +// +// The seconds value (rep_hi_) may be positive or negative as appropriate. +// The fractional seconds (rep_lo_) is always a positive offset from rep_hi_. +// The API for Duration guarantees at least nanosecond resolution, which +// means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds. +// However, to utilize more of the available 32 bits of space in rep_lo_, +// we instead store quarters of a nanosecond in rep_lo_ resulting in a max +// value of 4B - 1. This allows us to correctly handle calculations like +// 0.5 nanos + 0.5 nanos = 1 nano. The following example shows the actual +// Duration rep using quarters of a nanosecond. +// +// 2.5 sec = {rep_hi_=2, rep_lo_=2000000000} // lo = 4 * 500000000 +// -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000} +// +// Infinite durations are represented as Durations with the rep_lo_ field set +// to all 1s. +// +// +InfiniteDuration: +// rep_hi_ : kint64max +// rep_lo_ : ~0U +// +// -InfiniteDuration: +// rep_hi_ : kint64min +// rep_lo_ : ~0U +// +// Arithmetic overflows/underflows to +/- infinity and saturates. + +#if defined(_MSC_VER) +#include <winsock2.h> // for timeval +#endif + +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cerrno> +#include <cmath> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <ctime> +#include <functional> +#include <limits> +#include <string> + +#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" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace { + +using time_internal::kTicksPerNanosecond; +using time_internal::kTicksPerSecond; + +constexpr int64_t kint64max = std::numeric_limits<int64_t>::max(); +constexpr int64_t kint64min = std::numeric_limits<int64_t>::min(); + +// Can't use std::isinfinite() because it doesn't exist on windows. +inline bool IsFinite(double d) { + if (std::isnan(d)) return false; + return d != std::numeric_limits<double>::infinity() && + d != -std::numeric_limits<double>::infinity(); +} + +inline bool IsValidDivisor(double d) { + if (std::isnan(d)) return false; + return d != 0.0; +} + +// Can't use std::round() because it is only available in C++11. +// Note that we ignore the possibility of floating-point over/underflow. +template <typename Double> +inline double Round(Double d) { + return d < 0 ? std::ceil(d - 0.5) : std::floor(d + 0.5); +} + +// *sec may be positive or negative. *ticks must be in the range +// -kTicksPerSecond < *ticks < kTicksPerSecond. If *ticks is negative it +// will be normalized to a positive value by adjusting *sec accordingly. +inline void NormalizeTicks(int64_t* sec, int64_t* ticks) { + if (*ticks < 0) { + --*sec; + *ticks += kTicksPerSecond; + } +} + +// Makes a uint128 from the absolute value of the given scalar. +inline uint128 MakeU128(int64_t a) { + uint128 u128 = 0; + if (a < 0) { + ++u128; + ++a; // Makes it safe to negate 'a' + a = -a; + } + u128 += static_cast<uint64_t>(a); + return u128; +} + +// Makes a uint128 count of ticks out of the absolute value of the Duration. +inline uint128 MakeU128Ticks(Duration d) { + int64_t rep_hi = time_internal::GetRepHi(d); + uint32_t rep_lo = time_internal::GetRepLo(d); + if (rep_hi < 0) { + ++rep_hi; + rep_hi = -rep_hi; + rep_lo = kTicksPerSecond - rep_lo; + } + uint128 u128 = static_cast<uint64_t>(rep_hi); + u128 *= static_cast<uint64_t>(kTicksPerSecond); + u128 += rep_lo; + return u128; +} + +// Breaks a uint128 of ticks into a Duration. +inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) { + int64_t rep_hi; + uint32_t rep_lo; + const uint64_t h64 = Uint128High64(u128); + const uint64_t l64 = Uint128Low64(u128); + if (h64 == 0) { // fastpath + const uint64_t hi = l64 / kTicksPerSecond; + rep_hi = static_cast<int64_t>(hi); + rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond); + } else { + // kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond). + // Any positive tick count whose high 64 bits are >= kMaxRepHi64 + // is not representable as a Duration. A negative tick count can + // have its high 64 bits == kMaxRepHi64 but only when the low 64 + // bits are all zero, otherwise it is not representable either. + const uint64_t kMaxRepHi64 = 0x77359400UL; + if (h64 >= kMaxRepHi64) { + if (is_neg && h64 == kMaxRepHi64 && l64 == 0) { + // Avoid trying to represent -kint64min below. + return time_internal::MakeDuration(kint64min); + } + return is_neg ? -InfiniteDuration() : InfiniteDuration(); + } + const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond); + const uint128 hi = u128 / kTicksPerSecond128; + rep_hi = static_cast<int64_t>(Uint128Low64(hi)); + rep_lo = + static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128)); + } + if (is_neg) { + rep_hi = -rep_hi; + if (rep_lo != 0) { + --rep_hi; + rep_lo = kTicksPerSecond - rep_lo; + } + } + return time_internal::MakeDuration(rep_hi, rep_lo); +} + +// Convert between int64_t and uint64_t, preserving representation. This +// allows us to do arithmetic in the unsigned domain, where overflow has +// well-defined behavior. See operator+=() and operator-=(). +// +// C99 7.20.1.1.1, as referenced by C++11 18.4.1.2, says, "The typedef +// name intN_t designates a signed integer type with width N, no padding +// bits, and a two's complement representation." So, we can convert to +// and from the corresponding uint64_t value using a bit cast. +inline uint64_t EncodeTwosComp(int64_t v) { + return absl::bit_cast<uint64_t>(v); +} +inline int64_t DecodeTwosComp(uint64_t v) { return absl::bit_cast<int64_t>(v); } + +// Note: The overflow detection in this function is done using greater/less *or +// equal* because kint64max/min is too large to be represented exactly in a +// double (which only has 53 bits of precision). In order to avoid assigning to +// rep->hi a double value that is too large for an int64_t (and therefore is +// undefined), we must consider computations that equal kint64max/min as a +// double as overflow cases. +inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) { + double c = a_hi + b_hi; + if (c >= static_cast<double>(kint64max)) { + *d = InfiniteDuration(); + return false; + } + if (c <= static_cast<double>(kint64min)) { + *d = -InfiniteDuration(); + return false; + } + *d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d)); + return true; +} + +// A functor that's similar to std::multiplies<T>, except this returns the max +// T value instead of overflowing. This is only defined for uint128. +template <typename Ignored> +struct SafeMultiply { + uint128 operator()(uint128 a, uint128 b) const { + // b hi is always zero because it originated as an int64_t. + assert(Uint128High64(b) == 0); + // Fastpath to avoid the expensive overflow check with division. + if (Uint128High64(a) == 0) { + return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0) + ? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b)) + : a * b; + } + return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b; + } +}; + +// Scales (i.e., multiplies or divides, depending on the Operation template) +// the Duration d by the int64_t r. +template <template <typename> class Operation> +inline Duration ScaleFixed(Duration d, int64_t r) { + const uint128 a = MakeU128Ticks(d); + const uint128 b = MakeU128(r); + const uint128 q = Operation<uint128>()(a, b); + const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0); + return MakeDurationFromU128(q, is_neg); +} + +// Scales (i.e., multiplies or divides, depending on the Operation template) +// the Duration d by the double r. +template <template <typename> class Operation> +inline Duration ScaleDouble(Duration d, double r) { + Operation<double> op; + double hi_doub = op(time_internal::GetRepHi(d), r); + double lo_doub = op(time_internal::GetRepLo(d), r); + + double hi_int = 0; + double hi_frac = std::modf(hi_doub, &hi_int); + + // Moves hi's fractional bits to lo. + lo_doub /= kTicksPerSecond; + lo_doub += hi_frac; + + double lo_int = 0; + double lo_frac = std::modf(lo_doub, &lo_int); + + // Rolls lo into hi if necessary. + int64_t lo64 = Round(lo_frac * kTicksPerSecond); + + Duration ans; + if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans; + int64_t hi64 = time_internal::GetRepHi(ans); + if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans; + hi64 = time_internal::GetRepHi(ans); + lo64 %= kTicksPerSecond; + NormalizeTicks(&hi64, &lo64); + return time_internal::MakeDuration(hi64, lo64); +} + +// Tries to divide num by den as fast as possible by looking for common, easy +// cases. If the division was done, the quotient is in *q and the remainder is +// in *rem and true will be returned. +inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q, + Duration* rem) { + // Bail if num or den is an infinity. + if (time_internal::IsInfiniteDuration(num) || + time_internal::IsInfiniteDuration(den)) + return false; + + int64_t num_hi = time_internal::GetRepHi(num); + uint32_t num_lo = time_internal::GetRepLo(num); + int64_t den_hi = time_internal::GetRepHi(den); + uint32_t den_lo = time_internal::GetRepLo(den); + + if (den_hi == 0 && den_lo == kTicksPerNanosecond) { + // Dividing by 1ns + if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) { + *q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond; + *rem = time_internal::MakeDuration(0, num_lo % den_lo); + return true; + } + } else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) { + // Dividing by 100ns (common when converting to Universal time) + if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) { + *q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond); + *rem = time_internal::MakeDuration(0, num_lo % den_lo); + return true; + } + } else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) { + // Dividing by 1us + if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) { + *q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond); + *rem = time_internal::MakeDuration(0, num_lo % den_lo); + return true; + } + } else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) { + // Dividing by 1ms + if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) { + *q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond); + *rem = time_internal::MakeDuration(0, num_lo % den_lo); + return true; + } + } else if (den_hi > 0 && den_lo == 0) { + // Dividing by positive multiple of 1s + if (num_hi >= 0) { + if (den_hi == 1) { + *q = num_hi; + *rem = time_internal::MakeDuration(0, num_lo); + return true; + } + *q = num_hi / den_hi; + *rem = time_internal::MakeDuration(num_hi % den_hi, num_lo); + return true; + } + if (num_lo != 0) { + num_hi += 1; + } + int64_t quotient = num_hi / den_hi; + int64_t rem_sec = num_hi % den_hi; + if (rem_sec > 0) { + rem_sec -= den_hi; + quotient += 1; + } + if (num_lo != 0) { + rem_sec -= 1; + } + *q = quotient; + *rem = time_internal::MakeDuration(rem_sec, num_lo); + return true; + } + + return false; +} + +} // namespace + +namespace time_internal { + +// The 'satq' argument indicates whether the quotient should saturate at the +// bounds of int64_t. If it does saturate, the difference will spill over to +// 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) { + int64_t q = 0; + if (IDivFastPath(num, den, &q, rem)) { + return q; + } + + const bool num_neg = num < ZeroDuration(); + const bool den_neg = den < ZeroDuration(); + const bool quotient_neg = num_neg != den_neg; + + if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) { + *rem = num_neg ? -InfiniteDuration() : InfiniteDuration(); + return quotient_neg ? kint64min : kint64max; + } + if (time_internal::IsInfiniteDuration(den)) { + *rem = num; + return 0; + } + + const uint128 a = MakeU128Ticks(num); + const uint128 b = MakeU128Ticks(den); + uint128 quotient128 = a / b; + + if (satq) { + // Limits the quotient to the range of int64_t. + if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) { + quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min)) + : uint128(static_cast<uint64_t>(kint64max)); + } + } + + const uint128 remainder128 = a - quotient128 * b; + *rem = MakeDurationFromU128(remainder128, num_neg); + + if (!quotient_neg || quotient128 == 0) { + return Uint128Low64(quotient128) & kint64max; + } + // The quotient needs to be negated, but we need to carefully handle + // quotient128s with the top bit on. + return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1; +} + +} // namespace time_internal + +// +// Additive operators. +// + +Duration& Duration::operator+=(Duration rhs) { + if (time_internal::IsInfiniteDuration(*this)) return *this; + if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs; + const int64_t orig_rep_hi = rep_hi_; + rep_hi_ = + DecodeTwosComp(EncodeTwosComp(rep_hi_) + EncodeTwosComp(rhs.rep_hi_)); + if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) { + rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) + 1); + rep_lo_ -= kTicksPerSecond; + } + rep_lo_ += rhs.rep_lo_; + if (rhs.rep_hi_ < 0 ? rep_hi_ > orig_rep_hi : rep_hi_ < orig_rep_hi) { + return *this = rhs.rep_hi_ < 0 ? -InfiniteDuration() : InfiniteDuration(); + } + return *this; +} + +Duration& Duration::operator-=(Duration rhs) { + if (time_internal::IsInfiniteDuration(*this)) return *this; + if (time_internal::IsInfiniteDuration(rhs)) { + return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration(); + } + const int64_t orig_rep_hi = rep_hi_; + rep_hi_ = + DecodeTwosComp(EncodeTwosComp(rep_hi_) - EncodeTwosComp(rhs.rep_hi_)); + if (rep_lo_ < rhs.rep_lo_) { + rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_) - 1); + rep_lo_ += kTicksPerSecond; + } + rep_lo_ -= rhs.rep_lo_; + if (rhs.rep_hi_ < 0 ? rep_hi_ < orig_rep_hi : rep_hi_ > orig_rep_hi) { + return *this = rhs.rep_hi_ >= 0 ? -InfiniteDuration() : InfiniteDuration(); + } + return *this; +} + +// +// Multiplicative operators. +// + +Duration& Duration::operator*=(int64_t r) { + if (time_internal::IsInfiniteDuration(*this)) { + const bool is_neg = (r < 0) != (rep_hi_ < 0); + return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); + } + return *this = ScaleFixed<SafeMultiply>(*this, r); +} + +Duration& Duration::operator*=(double r) { + if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) { + const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0); + return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); + } + return *this = ScaleDouble<std::multiplies>(*this, r); +} + +Duration& Duration::operator/=(int64_t r) { + if (time_internal::IsInfiniteDuration(*this) || r == 0) { + const bool is_neg = (r < 0) != (rep_hi_ < 0); + return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); + } + return *this = ScaleFixed<std::divides>(*this, r); +} + +Duration& Duration::operator/=(double r) { + if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) { + const bool is_neg = (std::signbit(r) != 0) != (rep_hi_ < 0); + return *this = is_neg ? -InfiniteDuration() : InfiniteDuration(); + } + return *this = ScaleDouble<std::divides>(*this, r); +} + +Duration& Duration::operator%=(Duration rhs) { + time_internal::IDivDuration(false, *this, rhs, this); + return *this; +} + +double FDivDuration(Duration num, Duration den) { + // Arithmetic with infinity is sticky. + if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) { + return (num < ZeroDuration()) == (den < ZeroDuration()) + ? std::numeric_limits<double>::infinity() + : -std::numeric_limits<double>::infinity(); + } + if (time_internal::IsInfiniteDuration(den)) return 0.0; + + double a = + static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond + + time_internal::GetRepLo(num); + double b = + static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond + + time_internal::GetRepLo(den); + return a / b; +} + +// +// Trunc/Floor/Ceil. +// + +Duration Trunc(Duration d, Duration unit) { + return d - (d % unit); +} + +Duration Floor(const Duration d, const Duration unit) { + const absl::Duration td = Trunc(d, unit); + return td <= d ? td : td - AbsDuration(unit); +} + +Duration Ceil(const Duration d, const Duration unit) { + const absl::Duration td = Trunc(d, unit); + return td >= d ? td : td + AbsDuration(unit); +} + +// +// Factory functions. +// + +Duration DurationFromTimespec(timespec ts) { + if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) { + int64_t ticks = ts.tv_nsec * kTicksPerNanosecond; + return time_internal::MakeDuration(ts.tv_sec, ticks); + } + return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec); +} + +Duration DurationFromTimeval(timeval tv) { + if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) { + int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond; + return time_internal::MakeDuration(tv.tv_sec, ticks); + } + return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec); +} + +// +// Conversion to other duration types. +// + +int64_t ToInt64Nanoseconds(Duration d) { + if (time_internal::GetRepHi(d) >= 0 && + time_internal::GetRepHi(d) >> 33 == 0) { + return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) + + (time_internal::GetRepLo(d) / kTicksPerNanosecond); + } + return d / Nanoseconds(1); +} +int64_t ToInt64Microseconds(Duration d) { + if (time_internal::GetRepHi(d) >= 0 && + time_internal::GetRepHi(d) >> 43 == 0) { + return (time_internal::GetRepHi(d) * 1000 * 1000) + + (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000)); + } + return d / Microseconds(1); +} +int64_t ToInt64Milliseconds(Duration d) { + if (time_internal::GetRepHi(d) >= 0 && + time_internal::GetRepHi(d) >> 53 == 0) { + return (time_internal::GetRepHi(d) * 1000) + + (time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000)); + } + return d / Milliseconds(1); +} +int64_t ToInt64Seconds(Duration d) { + int64_t hi = time_internal::GetRepHi(d); + if (time_internal::IsInfiniteDuration(d)) return hi; + if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; + return hi; +} +int64_t ToInt64Minutes(Duration d) { + int64_t hi = time_internal::GetRepHi(d); + if (time_internal::IsInfiniteDuration(d)) return hi; + if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; + return hi / 60; +} +int64_t ToInt64Hours(Duration d) { + int64_t hi = time_internal::GetRepHi(d); + if (time_internal::IsInfiniteDuration(d)) return hi; + if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi; + return hi / (60 * 60); +} + +double ToDoubleNanoseconds(Duration d) { + return FDivDuration(d, Nanoseconds(1)); +} +double ToDoubleMicroseconds(Duration d) { + return FDivDuration(d, Microseconds(1)); +} +double ToDoubleMilliseconds(Duration d) { + return FDivDuration(d, Milliseconds(1)); +} +double ToDoubleSeconds(Duration d) { + return FDivDuration(d, Seconds(1)); +} +double ToDoubleMinutes(Duration d) { + return FDivDuration(d, Minutes(1)); +} +double ToDoubleHours(Duration d) { + return FDivDuration(d, Hours(1)); +} + +timespec ToTimespec(Duration d) { + timespec ts; + if (!time_internal::IsInfiniteDuration(d)) { + int64_t rep_hi = time_internal::GetRepHi(d); + uint32_t rep_lo = time_internal::GetRepLo(d); + if (rep_hi < 0) { + // Tweak the fields so that unsigned division of rep_lo + // maps to truncation (towards zero) for the timespec. + rep_lo += kTicksPerNanosecond - 1; + if (rep_lo >= kTicksPerSecond) { + rep_hi += 1; + rep_lo -= kTicksPerSecond; + } + } + ts.tv_sec = rep_hi; + if (ts.tv_sec == rep_hi) { // no time_t narrowing + ts.tv_nsec = rep_lo / kTicksPerNanosecond; + return ts; + } + } + if (d >= ZeroDuration()) { + ts.tv_sec = std::numeric_limits<time_t>::max(); + ts.tv_nsec = 1000 * 1000 * 1000 - 1; + } else { + ts.tv_sec = std::numeric_limits<time_t>::min(); + ts.tv_nsec = 0; + } + return ts; +} + +timeval ToTimeval(Duration d) { + timeval tv; + timespec ts = ToTimespec(d); + if (ts.tv_sec < 0) { + // Tweak the fields so that positive division of tv_nsec + // maps to truncation (towards zero) for the timeval. + ts.tv_nsec += 1000 - 1; + if (ts.tv_nsec >= 1000 * 1000 * 1000) { + ts.tv_sec += 1; + ts.tv_nsec -= 1000 * 1000 * 1000; + } + } + tv.tv_sec = ts.tv_sec; + if (tv.tv_sec != ts.tv_sec) { // narrowing + if (ts.tv_sec < 0) { + tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min(); + tv.tv_usec = 0; + } else { + tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max(); + tv.tv_usec = 1000 * 1000 - 1; + } + return tv; + } + tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t + return tv; +} + +std::chrono::nanoseconds ToChronoNanoseconds(Duration d) { + return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d); +} +std::chrono::microseconds ToChronoMicroseconds(Duration d) { + return time_internal::ToChronoDuration<std::chrono::microseconds>(d); +} +std::chrono::milliseconds ToChronoMilliseconds(Duration d) { + return time_internal::ToChronoDuration<std::chrono::milliseconds>(d); +} +std::chrono::seconds ToChronoSeconds(Duration d) { + return time_internal::ToChronoDuration<std::chrono::seconds>(d); +} +std::chrono::minutes ToChronoMinutes(Duration d) { + return time_internal::ToChronoDuration<std::chrono::minutes>(d); +} +std::chrono::hours ToChronoHours(Duration d) { + return time_internal::ToChronoDuration<std::chrono::hours>(d); +} + +// +// To/From string formatting. +// + +namespace { + +// Formats a positive 64-bit integer in the given field width. Note that +// it is up to the caller of Format64() to ensure that there is sufficient +// space before ep to hold the conversion. +char* Format64(char* ep, int width, int64_t v) { + do { + --width; + *--ep = '0' + (v % 10); // contiguous digits + } while (v /= 10); + while (--width >= 0) *--ep = '0'; // zero pad + return ep; +} + +// Helpers for FormatDuration() that format 'n' and append it to 'out' +// followed by the given 'unit'. If 'n' formats to "0", nothing is +// appended (not even the unit). + +// A type that encapsulates how to display a value of a particular unit. For +// values that are displayed with fractional parts, the precision indicates +// where to round the value. The precision varies with the display unit because +// a Duration can hold only quarters of a nanosecond, so displaying information +// beyond that is just noise. +// +// For example, a microsecond value of 42.00025xxxxx should not display beyond 5 +// fractional digits, because it is in the noise of what a Duration can +// represent. +struct DisplayUnit { + absl::string_view abbr; + int prec; + double pow10; +}; +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 + char* const ep = buf + sizeof(buf); + char* bp = Format64(ep, 0, n); + if (*bp != '0' || bp + 1 != ep) { + out->append(bp, ep - bp); + out->append(unit.abbr.data(), unit.abbr.size()); + } +} + +// Note: unit.prec is limited to double's digits10 value (typically 15) so it +// always fits in buf[]. +void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) { + constexpr int kBufferSize = std::numeric_limits<double>::digits10; + const int prec = std::min(kBufferSize, unit.prec); + char buf[kBufferSize]; // also large enough to hold integer part + char* ep = buf + sizeof(buf); + double d = 0; + int64_t frac_part = Round(std::modf(n, &d) * unit.pow10); + int64_t int_part = d; + if (int_part != 0 || frac_part != 0) { + char* bp = Format64(ep, 0, int_part); // always < 1000 + out->append(bp, ep - bp); + if (frac_part != 0) { + out->push_back('.'); + bp = Format64(ep, prec, frac_part); + while (ep[-1] == '0') --ep; + out->append(bp, ep - bp); + } + out->append(unit.abbr.data(), unit.abbr.size()); + } +} + +} // namespace + +// From Go's doc at https://golang.org/pkg/time/#Duration.String +// [FormatDuration] returns a string representing the duration in the +// 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. +// 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) { + // Avoid needing to negate kint64min by directly returning what the + // following code should produce in that case. + return "-2562047788015215h30m8s"; + } + std::string s; + if (d < ZeroDuration()) { + s.append("-"); + d = -d; + } + if (d == InfiniteDuration()) { + s.append("inf"); + } else if (d < Seconds(1)) { + // Special case for durations with a magnitude < 1 second. The duration + // is printed as a fraction of a single unit, e.g., "1.2ms". + if (d < Microseconds(1)) { + AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano); + } else if (d < Milliseconds(1)) { + AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro); + } else { + AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli); + } + } else { + AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour); + AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin); + AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec); + } + if (s.empty() || s == "-") { + s = "0"; + } + return s; +} + +namespace { + +// A helper for ParseDuration() that parses a leading number from the given +// string and stores the result in *int_part/*frac_part/*frac_scale. The +// given string pointer is modified to point to the first unconsumed char. +bool ConsumeDurationNumber(const char** dpp, const char* ep, int64_t* int_part, + int64_t* frac_part, int64_t* frac_scale) { + *int_part = 0; + *frac_part = 0; + *frac_scale = 1; // invariant: *frac_part < *frac_scale + const char* start = *dpp; + for (; *dpp != ep; *dpp += 1) { + const int d = **dpp - '0'; // contiguous digits + if (d < 0 || 10 <= d) break; + + if (*int_part > kint64max / 10) return false; + *int_part *= 10; + if (*int_part > kint64max - d) return false; + *int_part += d; + } + const bool int_part_empty = (*dpp == start); + if (*dpp == ep || **dpp != '.') return !int_part_empty; + + for (*dpp += 1; *dpp != ep; *dpp += 1) { + const int d = **dpp - '0'; // contiguous digits + if (d < 0 || 10 <= d) break; + if (*frac_scale <= kint64max / 10) { + *frac_part *= 10; + *frac_part += d; + *frac_scale *= 10; + } + } + return !int_part_empty || *frac_scale != 1; +} + +// A helper for ParseDuration() that parses a leading unit designator (e.g., +// ns, us, ms, s, m, h) from the given string and stores the resulting unit +// in "*unit". The given string pointer is modified to point to the first +// unconsumed char. +bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) { + size_t size = end - *start; + switch (size) { + case 0: + return false; + default: + switch (**start) { + case 'n': + if (*(*start + 1) == 's') { + *start += 2; + *unit = Nanoseconds(1); + return true; + } + break; + case 'u': + if (*(*start + 1) == 's') { + *start += 2; + *unit = Microseconds(1); + return true; + } + break; + case 'm': + if (*(*start + 1) == 's') { + *start += 2; + *unit = Milliseconds(1); + return true; + } + break; + default: + break; + } + ABSL_FALLTHROUGH_INTENDED; + case 1: + switch (**start) { + case 's': + *unit = Seconds(1); + *start += 1; + return true; + case 'm': + *unit = Minutes(1); + *start += 1; + return true; + case 'h': + *unit = Hours(1); + *start += 1; + return true; + default: + return false; + } + } +} + +} // namespace + +// From Go's doc at https://golang.org/pkg/time/#ParseDuration +// [ParseDuration] parses a duration string. A duration string is +// a possibly signed sequence of decimal numbers, each with optional +// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". +// Valid time units are "ns", "us" "ms", "s", "m", "h". +bool ParseDuration(absl::string_view dur_sv, Duration* d) { + int sign = 1; + if (absl::ConsumePrefix(&dur_sv, "-")) { + sign = -1; + } else { + absl::ConsumePrefix(&dur_sv, "+"); + } + if (dur_sv.empty()) return false; + + // Special case for a string of "0". + if (dur_sv == "0") { + *d = ZeroDuration(); + return true; + } + + if (dur_sv == "inf") { + *d = sign * InfiniteDuration(); + return true; + } + + const char* start = dur_sv.data(); + const char* end = start + dur_sv.size(); + + Duration dur; + while (start != end) { + int64_t int_part; + int64_t frac_part; + int64_t frac_scale; + Duration unit; + if (!ConsumeDurationNumber(&start, end, &int_part, &frac_part, + &frac_scale) || + !ConsumeDurationUnit(&start, end, &unit)) { + return false; + } + if (int_part != 0) dur += sign * int_part * unit; + if (frac_part != 0) dur += sign * frac_part * unit / frac_scale; + } + *d = dur; + return true; +} + +bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) { + return ParseDuration(text, dst); +} + +std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); } +bool ParseFlag(const std::string& text, Duration* dst, std::string* ) { + return ParseDuration(text, dst); +} + +std::string UnparseFlag(Duration d) { return FormatDuration(d); } + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/duration_benchmark.cc b/third_party/abseil_cpp/absl/time/duration_benchmark.cc new file mode 100644 index 000000000000..83a836c8c8a2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/duration_benchmark.cc @@ -0,0 +1,428 @@ +// Copyright 2018 The Abseil Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cmath> +#include <cstddef> +#include <cstdint> +#include <ctime> +#include <string> + +#include "absl/base/attributes.h" +#include "absl/time/time.h" +#include "benchmark/benchmark.h" + +namespace { + +// +// Factory functions +// + +void BM_Duration_Factory_Nanoseconds(benchmark::State& state) { + int64_t i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Nanoseconds(i)); + i += 314159; + } +} +BENCHMARK(BM_Duration_Factory_Nanoseconds); + +void BM_Duration_Factory_Microseconds(benchmark::State& state) { + int64_t i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Microseconds(i)); + i += 314; + } +} +BENCHMARK(BM_Duration_Factory_Microseconds); + +void BM_Duration_Factory_Milliseconds(benchmark::State& state) { + int64_t i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Milliseconds(i)); + i += 1; + } +} +BENCHMARK(BM_Duration_Factory_Milliseconds); + +void BM_Duration_Factory_Seconds(benchmark::State& state) { + int64_t i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Seconds(i)); + i += 1; + } +} +BENCHMARK(BM_Duration_Factory_Seconds); + +void BM_Duration_Factory_Minutes(benchmark::State& state) { + int64_t i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Minutes(i)); + i += 1; + } +} +BENCHMARK(BM_Duration_Factory_Minutes); + +void BM_Duration_Factory_Hours(benchmark::State& state) { + int64_t i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Hours(i)); + i += 1; + } +} +BENCHMARK(BM_Duration_Factory_Hours); + +void BM_Duration_Factory_DoubleNanoseconds(benchmark::State& state) { + double d = 1; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Nanoseconds(d)); + d = d * 1.00000001 + 1; + } +} +BENCHMARK(BM_Duration_Factory_DoubleNanoseconds); + +void BM_Duration_Factory_DoubleMicroseconds(benchmark::State& state) { + double d = 1e-3; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Microseconds(d)); + d = d * 1.00000001 + 1e-3; + } +} +BENCHMARK(BM_Duration_Factory_DoubleMicroseconds); + +void BM_Duration_Factory_DoubleMilliseconds(benchmark::State& state) { + double d = 1e-6; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Milliseconds(d)); + d = d * 1.00000001 + 1e-6; + } +} +BENCHMARK(BM_Duration_Factory_DoubleMilliseconds); + +void BM_Duration_Factory_DoubleSeconds(benchmark::State& state) { + double d = 1e-9; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Seconds(d)); + d = d * 1.00000001 + 1e-9; + } +} +BENCHMARK(BM_Duration_Factory_DoubleSeconds); + +void BM_Duration_Factory_DoubleMinutes(benchmark::State& state) { + double d = 1e-9; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Minutes(d)); + d = d * 1.00000001 + 1e-9; + } +} +BENCHMARK(BM_Duration_Factory_DoubleMinutes); + +void BM_Duration_Factory_DoubleHours(benchmark::State& state) { + double d = 1e-9; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::Hours(d)); + d = d * 1.00000001 + 1e-9; + } +} +BENCHMARK(BM_Duration_Factory_DoubleHours); + +// +// Arithmetic +// + +void BM_Duration_Addition(benchmark::State& state) { + absl::Duration d = absl::Nanoseconds(1); + absl::Duration step = absl::Milliseconds(1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(d += step); + } +} +BENCHMARK(BM_Duration_Addition); + +void BM_Duration_Subtraction(benchmark::State& state) { + absl::Duration d = absl::Seconds(std::numeric_limits<int64_t>::max()); + absl::Duration step = absl::Milliseconds(1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(d -= step); + } +} +BENCHMARK(BM_Duration_Subtraction); + +void BM_Duration_Multiplication_Fixed(benchmark::State& state) { + absl::Duration d = absl::Milliseconds(1); + absl::Duration s; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(s += d * (i + 1)); + ++i; + } +} +BENCHMARK(BM_Duration_Multiplication_Fixed); + +void BM_Duration_Multiplication_Double(benchmark::State& state) { + absl::Duration d = absl::Milliseconds(1); + absl::Duration s; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(s += d * (i + 1.0)); + ++i; + } +} +BENCHMARK(BM_Duration_Multiplication_Double); + +void BM_Duration_Division_Fixed(benchmark::State& state) { + absl::Duration d = absl::Seconds(1); + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(d /= i + 1); + ++i; + } +} +BENCHMARK(BM_Duration_Division_Fixed); + +void BM_Duration_Division_Double(benchmark::State& state) { + absl::Duration d = absl::Seconds(1); + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(d /= i + 1.0); + ++i; + } +} +BENCHMARK(BM_Duration_Division_Double); + +void BM_Duration_FDivDuration_Nanoseconds(benchmark::State& state) { + double d = 1; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize( + d += absl::FDivDuration(absl::Milliseconds(i), absl::Nanoseconds(1))); + ++i; + } +} +BENCHMARK(BM_Duration_FDivDuration_Nanoseconds); + +void BM_Duration_IDivDuration_Nanoseconds(benchmark::State& state) { + int64_t a = 1; + absl::Duration ignore; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(a += + absl::IDivDuration(absl::Nanoseconds(i), + absl::Nanoseconds(1), &ignore)); + ++i; + } +} +BENCHMARK(BM_Duration_IDivDuration_Nanoseconds); + +void BM_Duration_IDivDuration_Microseconds(benchmark::State& state) { + int64_t a = 1; + absl::Duration ignore; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Microseconds(i), + absl::Microseconds(1), + &ignore)); + ++i; + } +} +BENCHMARK(BM_Duration_IDivDuration_Microseconds); + +void BM_Duration_IDivDuration_Milliseconds(benchmark::State& state) { + int64_t a = 1; + absl::Duration ignore; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Milliseconds(i), + absl::Milliseconds(1), + &ignore)); + ++i; + } +} +BENCHMARK(BM_Duration_IDivDuration_Milliseconds); + +void BM_Duration_IDivDuration_Seconds(benchmark::State& state) { + int64_t a = 1; + absl::Duration ignore; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize( + a += absl::IDivDuration(absl::Seconds(i), absl::Seconds(1), &ignore)); + ++i; + } +} +BENCHMARK(BM_Duration_IDivDuration_Seconds); + +void BM_Duration_IDivDuration_Minutes(benchmark::State& state) { + int64_t a = 1; + absl::Duration ignore; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize( + a += absl::IDivDuration(absl::Minutes(i), absl::Minutes(1), &ignore)); + ++i; + } +} +BENCHMARK(BM_Duration_IDivDuration_Minutes); + +void BM_Duration_IDivDuration_Hours(benchmark::State& state) { + int64_t a = 1; + absl::Duration ignore; + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize( + a += absl::IDivDuration(absl::Hours(i), absl::Hours(1), &ignore)); + ++i; + } +} +BENCHMARK(BM_Duration_IDivDuration_Hours); + +void BM_Duration_ToInt64Nanoseconds(benchmark::State& state) { + absl::Duration d = absl::Seconds(100000); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToInt64Nanoseconds(d)); + } +} +BENCHMARK(BM_Duration_ToInt64Nanoseconds); + +void BM_Duration_ToInt64Microseconds(benchmark::State& state) { + absl::Duration d = absl::Seconds(100000); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToInt64Microseconds(d)); + } +} +BENCHMARK(BM_Duration_ToInt64Microseconds); + +void BM_Duration_ToInt64Milliseconds(benchmark::State& state) { + absl::Duration d = absl::Seconds(100000); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToInt64Milliseconds(d)); + } +} +BENCHMARK(BM_Duration_ToInt64Milliseconds); + +void BM_Duration_ToInt64Seconds(benchmark::State& state) { + absl::Duration d = absl::Seconds(100000); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToInt64Seconds(d)); + } +} +BENCHMARK(BM_Duration_ToInt64Seconds); + +void BM_Duration_ToInt64Minutes(benchmark::State& state) { + absl::Duration d = absl::Seconds(100000); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToInt64Minutes(d)); + } +} +BENCHMARK(BM_Duration_ToInt64Minutes); + +void BM_Duration_ToInt64Hours(benchmark::State& state) { + absl::Duration d = absl::Seconds(100000); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToInt64Hours(d)); + } +} +BENCHMARK(BM_Duration_ToInt64Hours); + +// +// To/FromTimespec +// + +void BM_Duration_ToTimespec_AbslTime(benchmark::State& state) { + absl::Duration d = absl::Seconds(1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToTimespec(d)); + } +} +BENCHMARK(BM_Duration_ToTimespec_AbslTime); + +ABSL_ATTRIBUTE_NOINLINE timespec DoubleToTimespec(double seconds) { + timespec ts; + ts.tv_sec = seconds; + ts.tv_nsec = (seconds - ts.tv_sec) * (1000 * 1000 * 1000); + return ts; +} + +void BM_Duration_ToTimespec_Double(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(DoubleToTimespec(1.0)); + } +} +BENCHMARK(BM_Duration_ToTimespec_Double); + +void BM_Duration_FromTimespec_AbslTime(benchmark::State& state) { + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + while (state.KeepRunning()) { + if (++ts.tv_nsec == 1000 * 1000 * 1000) { + ++ts.tv_sec; + ts.tv_nsec = 0; + } + benchmark::DoNotOptimize(absl::DurationFromTimespec(ts)); + } +} +BENCHMARK(BM_Duration_FromTimespec_AbslTime); + +ABSL_ATTRIBUTE_NOINLINE double TimespecToDouble(timespec ts) { + return ts.tv_sec + (ts.tv_nsec / (1000 * 1000 * 1000)); +} + +void BM_Duration_FromTimespec_Double(benchmark::State& state) { + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + while (state.KeepRunning()) { + if (++ts.tv_nsec == 1000 * 1000 * 1000) { + ++ts.tv_sec; + ts.tv_nsec = 0; + } + benchmark::DoNotOptimize(TimespecToDouble(ts)); + } +} +BENCHMARK(BM_Duration_FromTimespec_Double); + +// +// String conversions +// + +const char* const kDurations[] = { + "0", // 0 + "123ns", // 1 + "1h2m3s", // 2 + "-2h3m4.005006007s", // 3 + "2562047788015215h30m7.99999999975s", // 4 +}; +const int kNumDurations = sizeof(kDurations) / sizeof(kDurations[0]); + +void BM_Duration_FormatDuration(benchmark::State& state) { + const std::string s = kDurations[state.range(0)]; + state.SetLabel(s); + absl::Duration d; + absl::ParseDuration(kDurations[state.range(0)], &d); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::FormatDuration(d)); + } +} +BENCHMARK(BM_Duration_FormatDuration)->DenseRange(0, kNumDurations - 1); + +void BM_Duration_ParseDuration(benchmark::State& state) { + const std::string s = kDurations[state.range(0)]; + state.SetLabel(s); + absl::Duration d; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ParseDuration(s, &d)); + } +} +BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1); + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/duration_test.cc b/third_party/abseil_cpp/absl/time/duration_test.cc new file mode 100644 index 000000000000..4d85a2c4f455 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/duration_test.cc @@ -0,0 +1,1808 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if defined(_MSC_VER) +#include <winsock2.h> // for timeval +#endif + +#include <chrono> // NOLINT(build/c++11) +#include <cmath> +#include <cstdint> +#include <ctime> +#include <iomanip> +#include <limits> +#include <random> +#include <string> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/time/time.h" + +namespace { + +constexpr int64_t kint64max = std::numeric_limits<int64_t>::max(); +constexpr int64_t kint64min = std::numeric_limits<int64_t>::min(); + +// Approximates the given number of years. This is only used to make some test +// code more readable. +absl::Duration ApproxYears(int64_t n) { return absl::Hours(n) * 365 * 24; } + +// A gMock matcher to match timespec values. Use this matcher like: +// timespec ts1, ts2; +// EXPECT_THAT(ts1, TimespecMatcher(ts2)); +MATCHER_P(TimespecMatcher, ts, "") { + if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec) + return true; + *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} "; + *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}"; + return false; +} + +// A gMock matcher to match timeval values. Use this matcher like: +// timeval tv1, tv2; +// EXPECT_THAT(tv1, TimevalMatcher(tv2)); +MATCHER_P(TimevalMatcher, tv, "") { + if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec) + return true; + *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} "; + *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}"; + return false; +} + +TEST(Duration, ConstExpr) { + constexpr absl::Duration d0 = absl::ZeroDuration(); + static_assert(d0 == absl::ZeroDuration(), "ZeroDuration()"); + constexpr absl::Duration d1 = absl::Seconds(1); + static_assert(d1 == absl::Seconds(1), "Seconds(1)"); + static_assert(d1 != absl::ZeroDuration(), "Seconds(1)"); + constexpr absl::Duration d2 = absl::InfiniteDuration(); + static_assert(d2 == absl::InfiniteDuration(), "InfiniteDuration()"); + static_assert(d2 != absl::ZeroDuration(), "InfiniteDuration()"); +} + +TEST(Duration, ValueSemantics) { + // If this compiles, the test passes. + constexpr absl::Duration a; // Default construction + constexpr absl::Duration b = a; // Copy construction + constexpr absl::Duration c(b); // Copy construction (again) + + absl::Duration d; + d = c; // Assignment +} + +TEST(Duration, Factories) { + constexpr absl::Duration zero = absl::ZeroDuration(); + constexpr absl::Duration nano = absl::Nanoseconds(1); + constexpr absl::Duration micro = absl::Microseconds(1); + constexpr absl::Duration milli = absl::Milliseconds(1); + constexpr absl::Duration sec = absl::Seconds(1); + constexpr absl::Duration min = absl::Minutes(1); + constexpr absl::Duration hour = absl::Hours(1); + + EXPECT_EQ(zero, absl::Duration()); + EXPECT_EQ(zero, absl::Seconds(0)); + EXPECT_EQ(nano, absl::Nanoseconds(1)); + EXPECT_EQ(micro, absl::Nanoseconds(1000)); + EXPECT_EQ(milli, absl::Microseconds(1000)); + EXPECT_EQ(sec, absl::Milliseconds(1000)); + EXPECT_EQ(min, absl::Seconds(60)); + EXPECT_EQ(hour, absl::Minutes(60)); + + // Tests factory limits + const absl::Duration inf = absl::InfiniteDuration(); + + EXPECT_GT(inf, absl::Seconds(kint64max)); + EXPECT_LT(-inf, absl::Seconds(kint64min)); + EXPECT_LT(-inf, absl::Seconds(-kint64max)); + + EXPECT_EQ(inf, absl::Minutes(kint64max)); + EXPECT_EQ(-inf, absl::Minutes(kint64min)); + EXPECT_EQ(-inf, absl::Minutes(-kint64max)); + EXPECT_GT(inf, absl::Minutes(kint64max / 60)); + EXPECT_LT(-inf, absl::Minutes(kint64min / 60)); + EXPECT_LT(-inf, absl::Minutes(-kint64max / 60)); + + EXPECT_EQ(inf, absl::Hours(kint64max)); + EXPECT_EQ(-inf, absl::Hours(kint64min)); + EXPECT_EQ(-inf, absl::Hours(-kint64max)); + EXPECT_GT(inf, absl::Hours(kint64max / 3600)); + EXPECT_LT(-inf, absl::Hours(kint64min / 3600)); + EXPECT_LT(-inf, absl::Hours(-kint64max / 3600)); +} + +TEST(Duration, ToConversion) { +#define TEST_DURATION_CONVERSION(UNIT) \ + do { \ + const absl::Duration d = absl::UNIT(1.5); \ + constexpr absl::Duration z = absl::ZeroDuration(); \ + constexpr absl::Duration inf = absl::InfiniteDuration(); \ + constexpr double dbl_inf = std::numeric_limits<double>::infinity(); \ + EXPECT_EQ(kint64min, absl::ToInt64##UNIT(-inf)); \ + EXPECT_EQ(-1, absl::ToInt64##UNIT(-d)); \ + EXPECT_EQ(0, absl::ToInt64##UNIT(z)); \ + EXPECT_EQ(1, absl::ToInt64##UNIT(d)); \ + EXPECT_EQ(kint64max, absl::ToInt64##UNIT(inf)); \ + EXPECT_EQ(-dbl_inf, absl::ToDouble##UNIT(-inf)); \ + EXPECT_EQ(-1.5, absl::ToDouble##UNIT(-d)); \ + EXPECT_EQ(0, absl::ToDouble##UNIT(z)); \ + EXPECT_EQ(1.5, absl::ToDouble##UNIT(d)); \ + EXPECT_EQ(dbl_inf, absl::ToDouble##UNIT(inf)); \ + } while (0) + + TEST_DURATION_CONVERSION(Nanoseconds); + TEST_DURATION_CONVERSION(Microseconds); + TEST_DURATION_CONVERSION(Milliseconds); + TEST_DURATION_CONVERSION(Seconds); + TEST_DURATION_CONVERSION(Minutes); + TEST_DURATION_CONVERSION(Hours); + +#undef TEST_DURATION_CONVERSION +} + +template <int64_t N> +void TestToConversion() { + constexpr absl::Duration nano = absl::Nanoseconds(N); + EXPECT_EQ(N, absl::ToInt64Nanoseconds(nano)); + EXPECT_EQ(0, absl::ToInt64Microseconds(nano)); + EXPECT_EQ(0, absl::ToInt64Milliseconds(nano)); + EXPECT_EQ(0, absl::ToInt64Seconds(nano)); + EXPECT_EQ(0, absl::ToInt64Minutes(nano)); + EXPECT_EQ(0, absl::ToInt64Hours(nano)); + const absl::Duration micro = absl::Microseconds(N); + EXPECT_EQ(N * 1000, absl::ToInt64Nanoseconds(micro)); + EXPECT_EQ(N, absl::ToInt64Microseconds(micro)); + EXPECT_EQ(0, absl::ToInt64Milliseconds(micro)); + EXPECT_EQ(0, absl::ToInt64Seconds(micro)); + EXPECT_EQ(0, absl::ToInt64Minutes(micro)); + EXPECT_EQ(0, absl::ToInt64Hours(micro)); + const absl::Duration milli = absl::Milliseconds(N); + EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Nanoseconds(milli)); + EXPECT_EQ(N * 1000, absl::ToInt64Microseconds(milli)); + EXPECT_EQ(N, absl::ToInt64Milliseconds(milli)); + EXPECT_EQ(0, absl::ToInt64Seconds(milli)); + EXPECT_EQ(0, absl::ToInt64Minutes(milli)); + EXPECT_EQ(0, absl::ToInt64Hours(milli)); + const absl::Duration sec = absl::Seconds(N); + EXPECT_EQ(N * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(sec)); + EXPECT_EQ(N * 1000 * 1000, absl::ToInt64Microseconds(sec)); + EXPECT_EQ(N * 1000, absl::ToInt64Milliseconds(sec)); + EXPECT_EQ(N, absl::ToInt64Seconds(sec)); + EXPECT_EQ(0, absl::ToInt64Minutes(sec)); + EXPECT_EQ(0, absl::ToInt64Hours(sec)); + const absl::Duration min = absl::Minutes(N); + EXPECT_EQ(N * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(min)); + EXPECT_EQ(N * 60 * 1000 * 1000, absl::ToInt64Microseconds(min)); + EXPECT_EQ(N * 60 * 1000, absl::ToInt64Milliseconds(min)); + EXPECT_EQ(N * 60, absl::ToInt64Seconds(min)); + EXPECT_EQ(N, absl::ToInt64Minutes(min)); + EXPECT_EQ(0, absl::ToInt64Hours(min)); + const absl::Duration hour = absl::Hours(N); + EXPECT_EQ(N * 60 * 60 * 1000 * 1000 * 1000, absl::ToInt64Nanoseconds(hour)); + EXPECT_EQ(N * 60 * 60 * 1000 * 1000, absl::ToInt64Microseconds(hour)); + EXPECT_EQ(N * 60 * 60 * 1000, absl::ToInt64Milliseconds(hour)); + EXPECT_EQ(N * 60 * 60, absl::ToInt64Seconds(hour)); + EXPECT_EQ(N * 60, absl::ToInt64Minutes(hour)); + EXPECT_EQ(N, absl::ToInt64Hours(hour)); +} + +TEST(Duration, ToConversionDeprecated) { + TestToConversion<43>(); + TestToConversion<1>(); + TestToConversion<0>(); + TestToConversion<-1>(); + TestToConversion<-43>(); +} + +template <int64_t N> +void TestFromChronoBasicEquality() { + using std::chrono::nanoseconds; + using std::chrono::microseconds; + using std::chrono::milliseconds; + using std::chrono::seconds; + using std::chrono::minutes; + using std::chrono::hours; + + static_assert(absl::Nanoseconds(N) == absl::FromChrono(nanoseconds(N)), ""); + static_assert(absl::Microseconds(N) == absl::FromChrono(microseconds(N)), ""); + static_assert(absl::Milliseconds(N) == absl::FromChrono(milliseconds(N)), ""); + static_assert(absl::Seconds(N) == absl::FromChrono(seconds(N)), ""); + static_assert(absl::Minutes(N) == absl::FromChrono(minutes(N)), ""); + static_assert(absl::Hours(N) == absl::FromChrono(hours(N)), ""); +} + +TEST(Duration, FromChrono) { + TestFromChronoBasicEquality<-123>(); + TestFromChronoBasicEquality<-1>(); + TestFromChronoBasicEquality<0>(); + TestFromChronoBasicEquality<1>(); + TestFromChronoBasicEquality<123>(); + + // Minutes (might, depending on the platform) saturate at +inf. + const auto chrono_minutes_max = std::chrono::minutes::max(); + const auto minutes_max = absl::FromChrono(chrono_minutes_max); + const int64_t minutes_max_count = chrono_minutes_max.count(); + if (minutes_max_count > kint64max / 60) { + EXPECT_EQ(absl::InfiniteDuration(), minutes_max); + } else { + EXPECT_EQ(absl::Minutes(minutes_max_count), minutes_max); + } + + // Minutes (might, depending on the platform) saturate at -inf. + const auto chrono_minutes_min = std::chrono::minutes::min(); + const auto minutes_min = absl::FromChrono(chrono_minutes_min); + const int64_t minutes_min_count = chrono_minutes_min.count(); + if (minutes_min_count < kint64min / 60) { + EXPECT_EQ(-absl::InfiniteDuration(), minutes_min); + } else { + EXPECT_EQ(absl::Minutes(minutes_min_count), minutes_min); + } + + // Hours (might, depending on the platform) saturate at +inf. + const auto chrono_hours_max = std::chrono::hours::max(); + const auto hours_max = absl::FromChrono(chrono_hours_max); + const int64_t hours_max_count = chrono_hours_max.count(); + if (hours_max_count > kint64max / 3600) { + EXPECT_EQ(absl::InfiniteDuration(), hours_max); + } else { + EXPECT_EQ(absl::Hours(hours_max_count), hours_max); + } + + // Hours (might, depending on the platform) saturate at -inf. + const auto chrono_hours_min = std::chrono::hours::min(); + const auto hours_min = absl::FromChrono(chrono_hours_min); + const int64_t hours_min_count = chrono_hours_min.count(); + if (hours_min_count < kint64min / 3600) { + EXPECT_EQ(-absl::InfiniteDuration(), hours_min); + } else { + EXPECT_EQ(absl::Hours(hours_min_count), hours_min); + } +} + +template <int64_t N> +void TestToChrono() { + using std::chrono::nanoseconds; + using std::chrono::microseconds; + using std::chrono::milliseconds; + using std::chrono::seconds; + using std::chrono::minutes; + using std::chrono::hours; + + EXPECT_EQ(nanoseconds(N), absl::ToChronoNanoseconds(absl::Nanoseconds(N))); + EXPECT_EQ(microseconds(N), absl::ToChronoMicroseconds(absl::Microseconds(N))); + EXPECT_EQ(milliseconds(N), absl::ToChronoMilliseconds(absl::Milliseconds(N))); + EXPECT_EQ(seconds(N), absl::ToChronoSeconds(absl::Seconds(N))); + + constexpr auto absl_minutes = absl::Minutes(N); + auto chrono_minutes = minutes(N); + if (absl_minutes == -absl::InfiniteDuration()) { + chrono_minutes = minutes::min(); + } else if (absl_minutes == absl::InfiniteDuration()) { + chrono_minutes = minutes::max(); + } + EXPECT_EQ(chrono_minutes, absl::ToChronoMinutes(absl_minutes)); + + constexpr auto absl_hours = absl::Hours(N); + auto chrono_hours = hours(N); + if (absl_hours == -absl::InfiniteDuration()) { + chrono_hours = hours::min(); + } else if (absl_hours == absl::InfiniteDuration()) { + chrono_hours = hours::max(); + } + EXPECT_EQ(chrono_hours, absl::ToChronoHours(absl_hours)); +} + +TEST(Duration, ToChrono) { + using std::chrono::nanoseconds; + using std::chrono::microseconds; + using std::chrono::milliseconds; + using std::chrono::seconds; + using std::chrono::minutes; + using std::chrono::hours; + + TestToChrono<kint64min>(); + TestToChrono<-1>(); + TestToChrono<0>(); + TestToChrono<1>(); + TestToChrono<kint64max>(); + + // Verify truncation toward zero. + const auto tick = absl::Nanoseconds(1) / 4; + EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(tick)); + EXPECT_EQ(nanoseconds(0), absl::ToChronoNanoseconds(-tick)); + EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(tick)); + EXPECT_EQ(microseconds(0), absl::ToChronoMicroseconds(-tick)); + EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(tick)); + EXPECT_EQ(milliseconds(0), absl::ToChronoMilliseconds(-tick)); + EXPECT_EQ(seconds(0), absl::ToChronoSeconds(tick)); + EXPECT_EQ(seconds(0), absl::ToChronoSeconds(-tick)); + EXPECT_EQ(minutes(0), absl::ToChronoMinutes(tick)); + EXPECT_EQ(minutes(0), absl::ToChronoMinutes(-tick)); + EXPECT_EQ(hours(0), absl::ToChronoHours(tick)); + EXPECT_EQ(hours(0), absl::ToChronoHours(-tick)); + + // Verifies +/- infinity saturation at max/min. + constexpr auto inf = absl::InfiniteDuration(); + EXPECT_EQ(nanoseconds::min(), absl::ToChronoNanoseconds(-inf)); + EXPECT_EQ(nanoseconds::max(), absl::ToChronoNanoseconds(inf)); + EXPECT_EQ(microseconds::min(), absl::ToChronoMicroseconds(-inf)); + EXPECT_EQ(microseconds::max(), absl::ToChronoMicroseconds(inf)); + EXPECT_EQ(milliseconds::min(), absl::ToChronoMilliseconds(-inf)); + EXPECT_EQ(milliseconds::max(), absl::ToChronoMilliseconds(inf)); + EXPECT_EQ(seconds::min(), absl::ToChronoSeconds(-inf)); + EXPECT_EQ(seconds::max(), absl::ToChronoSeconds(inf)); + EXPECT_EQ(minutes::min(), absl::ToChronoMinutes(-inf)); + EXPECT_EQ(minutes::max(), absl::ToChronoMinutes(inf)); + EXPECT_EQ(hours::min(), absl::ToChronoHours(-inf)); + EXPECT_EQ(hours::max(), absl::ToChronoHours(inf)); +} + +TEST(Duration, FactoryOverloads) { + enum E { kOne = 1 }; +#define TEST_FACTORY_OVERLOADS(NAME) \ + EXPECT_EQ(1, NAME(kOne) / NAME(kOne)); \ + EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<int64_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<uint8_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1)); \ + EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1)); \ + EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5))); \ + EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5))); \ + EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \ + EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<double>(1.5)), NAME(1))); + + TEST_FACTORY_OVERLOADS(absl::Nanoseconds); + TEST_FACTORY_OVERLOADS(absl::Microseconds); + TEST_FACTORY_OVERLOADS(absl::Milliseconds); + TEST_FACTORY_OVERLOADS(absl::Seconds); + TEST_FACTORY_OVERLOADS(absl::Minutes); + TEST_FACTORY_OVERLOADS(absl::Hours); + +#undef TEST_FACTORY_OVERLOADS + + EXPECT_EQ(absl::Milliseconds(1500), absl::Seconds(1.5)); + EXPECT_LT(absl::Nanoseconds(1), absl::Nanoseconds(1.5)); + EXPECT_GT(absl::Nanoseconds(2), absl::Nanoseconds(1.5)); + + const double dbl_inf = std::numeric_limits<double>::infinity(); + EXPECT_EQ(absl::InfiniteDuration(), absl::Nanoseconds(dbl_inf)); + EXPECT_EQ(absl::InfiniteDuration(), absl::Microseconds(dbl_inf)); + EXPECT_EQ(absl::InfiniteDuration(), absl::Milliseconds(dbl_inf)); + EXPECT_EQ(absl::InfiniteDuration(), absl::Seconds(dbl_inf)); + EXPECT_EQ(absl::InfiniteDuration(), absl::Minutes(dbl_inf)); + EXPECT_EQ(absl::InfiniteDuration(), absl::Hours(dbl_inf)); + EXPECT_EQ(-absl::InfiniteDuration(), absl::Nanoseconds(-dbl_inf)); + EXPECT_EQ(-absl::InfiniteDuration(), absl::Microseconds(-dbl_inf)); + EXPECT_EQ(-absl::InfiniteDuration(), absl::Milliseconds(-dbl_inf)); + EXPECT_EQ(-absl::InfiniteDuration(), absl::Seconds(-dbl_inf)); + EXPECT_EQ(-absl::InfiniteDuration(), absl::Minutes(-dbl_inf)); + EXPECT_EQ(-absl::InfiniteDuration(), absl::Hours(-dbl_inf)); +} + +TEST(Duration, InfinityExamples) { + // These examples are used in the documentation in time.h. They are + // written so that they can be copy-n-pasted easily. + + constexpr absl::Duration inf = absl::InfiniteDuration(); + constexpr absl::Duration d = absl::Seconds(1); // Any finite duration + + EXPECT_TRUE(inf == inf + inf); + EXPECT_TRUE(inf == inf + d); + EXPECT_TRUE(inf == inf - inf); + EXPECT_TRUE(-inf == d - inf); + + EXPECT_TRUE(inf == d * 1e100); + EXPECT_TRUE(0 == d / inf); // NOLINT(readability/check) + + // Division by zero returns infinity, or kint64min/MAX where necessary. + EXPECT_TRUE(inf == d / 0); + EXPECT_TRUE(kint64max == d / absl::ZeroDuration()); +} + +TEST(Duration, InfinityComparison) { + const absl::Duration inf = absl::InfiniteDuration(); + const absl::Duration any_dur = absl::Seconds(1); + + // Equality + EXPECT_EQ(inf, inf); + EXPECT_EQ(-inf, -inf); + EXPECT_NE(inf, -inf); + EXPECT_NE(any_dur, inf); + EXPECT_NE(any_dur, -inf); + + // Relational + EXPECT_GT(inf, any_dur); + EXPECT_LT(-inf, any_dur); + EXPECT_LT(-inf, inf); + EXPECT_GT(inf, -inf); +} + +TEST(Duration, InfinityAddition) { + const absl::Duration sec_max = absl::Seconds(kint64max); + const absl::Duration sec_min = absl::Seconds(kint64min); + const absl::Duration any_dur = absl::Seconds(1); + const absl::Duration inf = absl::InfiniteDuration(); + + // Addition + EXPECT_EQ(inf, inf + inf); + EXPECT_EQ(inf, inf + -inf); + EXPECT_EQ(-inf, -inf + inf); + EXPECT_EQ(-inf, -inf + -inf); + + EXPECT_EQ(inf, inf + any_dur); + EXPECT_EQ(inf, any_dur + inf); + EXPECT_EQ(-inf, -inf + any_dur); + EXPECT_EQ(-inf, any_dur + -inf); + + // Interesting case + absl::Duration almost_inf = sec_max + absl::Nanoseconds(999999999); + EXPECT_GT(inf, almost_inf); + almost_inf += -absl::Nanoseconds(999999999); + EXPECT_GT(inf, almost_inf); + + // Addition overflow/underflow + EXPECT_EQ(inf, sec_max + absl::Seconds(1)); + EXPECT_EQ(inf, sec_max + sec_max); + EXPECT_EQ(-inf, sec_min + -absl::Seconds(1)); + EXPECT_EQ(-inf, sec_min + -sec_max); + + // For reference: IEEE 754 behavior + const double dbl_inf = std::numeric_limits<double>::infinity(); + EXPECT_TRUE(std::isinf(dbl_inf + dbl_inf)); + EXPECT_TRUE(std::isnan(dbl_inf + -dbl_inf)); // We return inf + EXPECT_TRUE(std::isnan(-dbl_inf + dbl_inf)); // We return inf + EXPECT_TRUE(std::isinf(-dbl_inf + -dbl_inf)); +} + +TEST(Duration, InfinitySubtraction) { + const absl::Duration sec_max = absl::Seconds(kint64max); + const absl::Duration sec_min = absl::Seconds(kint64min); + const absl::Duration any_dur = absl::Seconds(1); + const absl::Duration inf = absl::InfiniteDuration(); + + // Subtraction + EXPECT_EQ(inf, inf - inf); + EXPECT_EQ(inf, inf - -inf); + EXPECT_EQ(-inf, -inf - inf); + EXPECT_EQ(-inf, -inf - -inf); + + EXPECT_EQ(inf, inf - any_dur); + EXPECT_EQ(-inf, any_dur - inf); + EXPECT_EQ(-inf, -inf - any_dur); + EXPECT_EQ(inf, any_dur - -inf); + + // Subtraction overflow/underflow + EXPECT_EQ(inf, sec_max - -absl::Seconds(1)); + EXPECT_EQ(inf, sec_max - -sec_max); + EXPECT_EQ(-inf, sec_min - absl::Seconds(1)); + EXPECT_EQ(-inf, sec_min - sec_max); + + // Interesting case + absl::Duration almost_neg_inf = sec_min; + EXPECT_LT(-inf, almost_neg_inf); + almost_neg_inf -= -absl::Nanoseconds(1); + EXPECT_LT(-inf, almost_neg_inf); + + // For reference: IEEE 754 behavior + const double dbl_inf = std::numeric_limits<double>::infinity(); + EXPECT_TRUE(std::isnan(dbl_inf - dbl_inf)); // We return inf + EXPECT_TRUE(std::isinf(dbl_inf - -dbl_inf)); + EXPECT_TRUE(std::isinf(-dbl_inf - dbl_inf)); + EXPECT_TRUE(std::isnan(-dbl_inf - -dbl_inf)); // We return inf +} + +TEST(Duration, InfinityMultiplication) { + const absl::Duration sec_max = absl::Seconds(kint64max); + const absl::Duration sec_min = absl::Seconds(kint64min); + const absl::Duration inf = absl::InfiniteDuration(); + +#define TEST_INF_MUL_WITH_TYPE(T) \ + EXPECT_EQ(inf, inf * static_cast<T>(2)); \ + EXPECT_EQ(-inf, inf * static_cast<T>(-2)); \ + EXPECT_EQ(-inf, -inf * static_cast<T>(2)); \ + EXPECT_EQ(inf, -inf * static_cast<T>(-2)); \ + EXPECT_EQ(inf, inf * static_cast<T>(0)); \ + EXPECT_EQ(-inf, -inf * static_cast<T>(0)); \ + EXPECT_EQ(inf, sec_max * static_cast<T>(2)); \ + EXPECT_EQ(inf, sec_min * static_cast<T>(-2)); \ + EXPECT_EQ(inf, (sec_max / static_cast<T>(2)) * static_cast<T>(3)); \ + EXPECT_EQ(-inf, sec_max * static_cast<T>(-2)); \ + EXPECT_EQ(-inf, sec_min * static_cast<T>(2)); \ + EXPECT_EQ(-inf, (sec_min / static_cast<T>(2)) * static_cast<T>(3)); + + TEST_INF_MUL_WITH_TYPE(int64_t); // NOLINT(readability/function) + TEST_INF_MUL_WITH_TYPE(double); // NOLINT(readability/function) + +#undef TEST_INF_MUL_WITH_TYPE + + const double dbl_inf = std::numeric_limits<double>::infinity(); + EXPECT_EQ(inf, inf * dbl_inf); + EXPECT_EQ(-inf, -inf * dbl_inf); + EXPECT_EQ(-inf, inf * -dbl_inf); + EXPECT_EQ(inf, -inf * -dbl_inf); + + const absl::Duration any_dur = absl::Seconds(1); + EXPECT_EQ(inf, any_dur * dbl_inf); + EXPECT_EQ(-inf, -any_dur * dbl_inf); + EXPECT_EQ(-inf, any_dur * -dbl_inf); + EXPECT_EQ(inf, -any_dur * -dbl_inf); + + // Fixed-point multiplication will produce a finite value, whereas floating + // point fuzziness will overflow to inf. + EXPECT_NE(absl::InfiniteDuration(), absl::Seconds(1) * kint64max); + EXPECT_EQ(inf, absl::Seconds(1) * static_cast<double>(kint64max)); + EXPECT_NE(-absl::InfiniteDuration(), absl::Seconds(1) * kint64min); + EXPECT_EQ(-inf, absl::Seconds(1) * static_cast<double>(kint64min)); + + // Note that sec_max * or / by 1.0 overflows to inf due to the 53-bit + // limitations of double. + EXPECT_NE(inf, sec_max); + EXPECT_NE(inf, sec_max / 1); + EXPECT_EQ(inf, sec_max / 1.0); + EXPECT_NE(inf, sec_max * 1); + EXPECT_EQ(inf, sec_max * 1.0); +} + +TEST(Duration, InfinityDivision) { + const absl::Duration sec_max = absl::Seconds(kint64max); + const absl::Duration sec_min = absl::Seconds(kint64min); + const absl::Duration inf = absl::InfiniteDuration(); + + // Division of Duration by a double +#define TEST_INF_DIV_WITH_TYPE(T) \ + EXPECT_EQ(inf, inf / static_cast<T>(2)); \ + EXPECT_EQ(-inf, inf / static_cast<T>(-2)); \ + EXPECT_EQ(-inf, -inf / static_cast<T>(2)); \ + EXPECT_EQ(inf, -inf / static_cast<T>(-2)); + + TEST_INF_DIV_WITH_TYPE(int64_t); // NOLINT(readability/function) + TEST_INF_DIV_WITH_TYPE(double); // NOLINT(readability/function) + +#undef TEST_INF_DIV_WITH_TYPE + + // Division of Duration by a double overflow/underflow + EXPECT_EQ(inf, sec_max / 0.5); + EXPECT_EQ(inf, sec_min / -0.5); + EXPECT_EQ(inf, ((sec_max / 0.5) + absl::Seconds(1)) / 0.5); + EXPECT_EQ(-inf, sec_max / -0.5); + EXPECT_EQ(-inf, sec_min / 0.5); + EXPECT_EQ(-inf, ((sec_min / 0.5) - absl::Seconds(1)) / 0.5); + + const double dbl_inf = std::numeric_limits<double>::infinity(); + EXPECT_EQ(inf, inf / dbl_inf); + EXPECT_EQ(-inf, inf / -dbl_inf); + EXPECT_EQ(-inf, -inf / dbl_inf); + EXPECT_EQ(inf, -inf / -dbl_inf); + + const absl::Duration any_dur = absl::Seconds(1); + EXPECT_EQ(absl::ZeroDuration(), any_dur / dbl_inf); + EXPECT_EQ(absl::ZeroDuration(), any_dur / -dbl_inf); + EXPECT_EQ(absl::ZeroDuration(), -any_dur / dbl_inf); + EXPECT_EQ(absl::ZeroDuration(), -any_dur / -dbl_inf); +} + +TEST(Duration, InfinityModulus) { + const absl::Duration sec_max = absl::Seconds(kint64max); + const absl::Duration any_dur = absl::Seconds(1); + const absl::Duration inf = absl::InfiniteDuration(); + + EXPECT_EQ(inf, inf % inf); + EXPECT_EQ(inf, inf % -inf); + EXPECT_EQ(-inf, -inf % -inf); + EXPECT_EQ(-inf, -inf % inf); + + EXPECT_EQ(any_dur, any_dur % inf); + EXPECT_EQ(any_dur, any_dur % -inf); + EXPECT_EQ(-any_dur, -any_dur % inf); + EXPECT_EQ(-any_dur, -any_dur % -inf); + + EXPECT_EQ(inf, inf % -any_dur); + EXPECT_EQ(inf, inf % any_dur); + EXPECT_EQ(-inf, -inf % -any_dur); + EXPECT_EQ(-inf, -inf % any_dur); + + // Remainder isn't affected by overflow. + EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Seconds(1)); + EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Milliseconds(1)); + EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Microseconds(1)); + EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1)); + EXPECT_EQ(absl::ZeroDuration(), sec_max % absl::Nanoseconds(1) / 4); +} + +TEST(Duration, InfinityIDiv) { + const absl::Duration sec_max = absl::Seconds(kint64max); + const absl::Duration any_dur = absl::Seconds(1); + const absl::Duration inf = absl::InfiniteDuration(); + const double dbl_inf = std::numeric_limits<double>::infinity(); + + // IDivDuration (int64_t return value + a remainer) + absl::Duration rem = absl::ZeroDuration(); + EXPECT_EQ(kint64max, absl::IDivDuration(inf, inf, &rem)); + EXPECT_EQ(inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -inf, &rem)); + EXPECT_EQ(-inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64max, absl::IDivDuration(inf, any_dur, &rem)); + EXPECT_EQ(inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(0, absl::IDivDuration(any_dur, inf, &rem)); + EXPECT_EQ(any_dur, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64max, absl::IDivDuration(-inf, -any_dur, &rem)); + EXPECT_EQ(-inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(0, absl::IDivDuration(-any_dur, -inf, &rem)); + EXPECT_EQ(-any_dur, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64min, absl::IDivDuration(-inf, inf, &rem)); + EXPECT_EQ(-inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64min, absl::IDivDuration(inf, -inf, &rem)); + EXPECT_EQ(inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64min, absl::IDivDuration(-inf, any_dur, &rem)); + EXPECT_EQ(-inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(0, absl::IDivDuration(-any_dur, inf, &rem)); + EXPECT_EQ(-any_dur, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(kint64min, absl::IDivDuration(inf, -any_dur, &rem)); + EXPECT_EQ(inf, rem); + + rem = absl::ZeroDuration(); + EXPECT_EQ(0, absl::IDivDuration(any_dur, -inf, &rem)); + EXPECT_EQ(any_dur, rem); + + // IDivDuration overflow/underflow + rem = any_dur; + EXPECT_EQ(kint64max, + absl::IDivDuration(sec_max, absl::Nanoseconds(1) / 4, &rem)); + EXPECT_EQ(sec_max - absl::Nanoseconds(kint64max) / 4, rem); + + rem = any_dur; + EXPECT_EQ(kint64max, + absl::IDivDuration(sec_max, absl::Milliseconds(1), &rem)); + EXPECT_EQ(sec_max - absl::Milliseconds(kint64max), rem); + + rem = any_dur; + EXPECT_EQ(kint64max, + absl::IDivDuration(-sec_max, -absl::Milliseconds(1), &rem)); + EXPECT_EQ(-sec_max + absl::Milliseconds(kint64max), rem); + + rem = any_dur; + EXPECT_EQ(kint64min, + absl::IDivDuration(-sec_max, absl::Milliseconds(1), &rem)); + EXPECT_EQ(-sec_max - absl::Milliseconds(kint64min), rem); + + rem = any_dur; + EXPECT_EQ(kint64min, + absl::IDivDuration(sec_max, -absl::Milliseconds(1), &rem)); + EXPECT_EQ(sec_max + absl::Milliseconds(kint64min), rem); + + // + // operator/(Duration, Duration) is a wrapper for IDivDuration(). + // + + // IEEE 754 says inf / inf should be nan, but int64_t doesn't have + // nan so we'll return kint64max/kint64min instead. + EXPECT_TRUE(std::isnan(dbl_inf / dbl_inf)); + EXPECT_EQ(kint64max, inf / inf); + EXPECT_EQ(kint64max, -inf / -inf); + EXPECT_EQ(kint64min, -inf / inf); + EXPECT_EQ(kint64min, inf / -inf); + + EXPECT_TRUE(std::isinf(dbl_inf / 2.0)); + EXPECT_EQ(kint64max, inf / any_dur); + EXPECT_EQ(kint64max, -inf / -any_dur); + EXPECT_EQ(kint64min, -inf / any_dur); + EXPECT_EQ(kint64min, inf / -any_dur); + + EXPECT_EQ(0.0, 2.0 / dbl_inf); + EXPECT_EQ(0, any_dur / inf); + EXPECT_EQ(0, any_dur / -inf); + EXPECT_EQ(0, -any_dur / inf); + EXPECT_EQ(0, -any_dur / -inf); + EXPECT_EQ(0, absl::ZeroDuration() / inf); + + // Division of Duration by a Duration overflow/underflow + EXPECT_EQ(kint64max, sec_max / absl::Milliseconds(1)); + EXPECT_EQ(kint64max, -sec_max / -absl::Milliseconds(1)); + EXPECT_EQ(kint64min, -sec_max / absl::Milliseconds(1)); + EXPECT_EQ(kint64min, sec_max / -absl::Milliseconds(1)); +} + +TEST(Duration, InfinityFDiv) { + const absl::Duration any_dur = absl::Seconds(1); + const absl::Duration inf = absl::InfiniteDuration(); + const double dbl_inf = std::numeric_limits<double>::infinity(); + + EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, inf)); + EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -inf)); + EXPECT_EQ(dbl_inf, absl::FDivDuration(inf, any_dur)); + EXPECT_EQ(0.0, absl::FDivDuration(any_dur, inf)); + EXPECT_EQ(dbl_inf, absl::FDivDuration(-inf, -any_dur)); + EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, -inf)); + + EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, inf)); + EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -inf)); + EXPECT_EQ(-dbl_inf, absl::FDivDuration(-inf, any_dur)); + EXPECT_EQ(0.0, absl::FDivDuration(-any_dur, inf)); + EXPECT_EQ(-dbl_inf, absl::FDivDuration(inf, -any_dur)); + EXPECT_EQ(0.0, absl::FDivDuration(any_dur, -inf)); +} + +TEST(Duration, DivisionByZero) { + const absl::Duration zero = absl::ZeroDuration(); + const absl::Duration inf = absl::InfiniteDuration(); + const absl::Duration any_dur = absl::Seconds(1); + const double dbl_inf = std::numeric_limits<double>::infinity(); + const double dbl_denorm = std::numeric_limits<double>::denorm_min(); + + // Operator/(Duration, double) + EXPECT_EQ(inf, zero / 0.0); + EXPECT_EQ(-inf, zero / -0.0); + EXPECT_EQ(inf, any_dur / 0.0); + EXPECT_EQ(-inf, any_dur / -0.0); + EXPECT_EQ(-inf, -any_dur / 0.0); + EXPECT_EQ(inf, -any_dur / -0.0); + + // Tests dividing by a number very close to, but not quite zero. + EXPECT_EQ(zero, zero / dbl_denorm); + EXPECT_EQ(zero, zero / -dbl_denorm); + EXPECT_EQ(inf, any_dur / dbl_denorm); + EXPECT_EQ(-inf, any_dur / -dbl_denorm); + EXPECT_EQ(-inf, -any_dur / dbl_denorm); + EXPECT_EQ(inf, -any_dur / -dbl_denorm); + + // IDiv + absl::Duration rem = zero; + EXPECT_EQ(kint64max, absl::IDivDuration(zero, zero, &rem)); + EXPECT_EQ(inf, rem); + + rem = zero; + EXPECT_EQ(kint64max, absl::IDivDuration(any_dur, zero, &rem)); + EXPECT_EQ(inf, rem); + + rem = zero; + EXPECT_EQ(kint64min, absl::IDivDuration(-any_dur, zero, &rem)); + EXPECT_EQ(-inf, rem); + + // Operator/(Duration, Duration) + EXPECT_EQ(kint64max, zero / zero); + EXPECT_EQ(kint64max, any_dur / zero); + EXPECT_EQ(kint64min, -any_dur / zero); + + // FDiv + EXPECT_EQ(dbl_inf, absl::FDivDuration(zero, zero)); + EXPECT_EQ(dbl_inf, absl::FDivDuration(any_dur, zero)); + EXPECT_EQ(-dbl_inf, absl::FDivDuration(-any_dur, zero)); +} + +TEST(Duration, NaN) { + // Note that IEEE 754 does not define the behavior of a nan's sign when it is + // copied, so the code below allows for either + or - InfiniteDuration. +#define TEST_NAN_HANDLING(NAME, NAN) \ + do { \ + const auto inf = absl::InfiniteDuration(); \ + auto x = NAME(NAN); \ + EXPECT_TRUE(x == inf || x == -inf); \ + auto y = NAME(42); \ + y *= NAN; \ + EXPECT_TRUE(y == inf || y == -inf); \ + auto z = NAME(42); \ + z /= NAN; \ + EXPECT_TRUE(z == inf || z == -inf); \ + } while (0) + + const double nan = std::numeric_limits<double>::quiet_NaN(); + TEST_NAN_HANDLING(absl::Nanoseconds, nan); + TEST_NAN_HANDLING(absl::Microseconds, nan); + TEST_NAN_HANDLING(absl::Milliseconds, nan); + TEST_NAN_HANDLING(absl::Seconds, nan); + TEST_NAN_HANDLING(absl::Minutes, nan); + TEST_NAN_HANDLING(absl::Hours, nan); + + TEST_NAN_HANDLING(absl::Nanoseconds, -nan); + TEST_NAN_HANDLING(absl::Microseconds, -nan); + TEST_NAN_HANDLING(absl::Milliseconds, -nan); + TEST_NAN_HANDLING(absl::Seconds, -nan); + TEST_NAN_HANDLING(absl::Minutes, -nan); + TEST_NAN_HANDLING(absl::Hours, -nan); + +#undef TEST_NAN_HANDLING +} + +TEST(Duration, Range) { + const absl::Duration range = ApproxYears(100 * 1e9); + const absl::Duration range_future = range; + const absl::Duration range_past = -range; + + EXPECT_LT(range_future, absl::InfiniteDuration()); + EXPECT_GT(range_past, -absl::InfiniteDuration()); + + const absl::Duration full_range = range_future - range_past; + EXPECT_GT(full_range, absl::ZeroDuration()); + EXPECT_LT(full_range, absl::InfiniteDuration()); + + const absl::Duration neg_full_range = range_past - range_future; + EXPECT_LT(neg_full_range, absl::ZeroDuration()); + EXPECT_GT(neg_full_range, -absl::InfiniteDuration()); + + EXPECT_LT(neg_full_range, full_range); + EXPECT_EQ(neg_full_range, -full_range); +} + +TEST(Duration, RelationalOperators) { +#define TEST_REL_OPS(UNIT) \ + static_assert(UNIT(2) == UNIT(2), ""); \ + static_assert(UNIT(1) != UNIT(2), ""); \ + static_assert(UNIT(1) < UNIT(2), ""); \ + static_assert(UNIT(3) > UNIT(2), ""); \ + static_assert(UNIT(1) <= UNIT(2), ""); \ + static_assert(UNIT(2) <= UNIT(2), ""); \ + static_assert(UNIT(3) >= UNIT(2), ""); \ + static_assert(UNIT(2) >= UNIT(2), ""); + + TEST_REL_OPS(absl::Nanoseconds); + TEST_REL_OPS(absl::Microseconds); + TEST_REL_OPS(absl::Milliseconds); + TEST_REL_OPS(absl::Seconds); + TEST_REL_OPS(absl::Minutes); + TEST_REL_OPS(absl::Hours); + +#undef TEST_REL_OPS +} + +TEST(Duration, Addition) { +#define TEST_ADD_OPS(UNIT) \ + do { \ + EXPECT_EQ(UNIT(2), UNIT(1) + UNIT(1)); \ + EXPECT_EQ(UNIT(1), UNIT(2) - UNIT(1)); \ + EXPECT_EQ(UNIT(0), UNIT(2) - UNIT(2)); \ + EXPECT_EQ(UNIT(-1), UNIT(1) - UNIT(2)); \ + EXPECT_EQ(UNIT(-2), UNIT(0) - UNIT(2)); \ + EXPECT_EQ(UNIT(-2), UNIT(1) - UNIT(3)); \ + absl::Duration a = UNIT(1); \ + a += UNIT(1); \ + EXPECT_EQ(UNIT(2), a); \ + a -= UNIT(1); \ + EXPECT_EQ(UNIT(1), a); \ + } while (0) + + TEST_ADD_OPS(absl::Nanoseconds); + TEST_ADD_OPS(absl::Microseconds); + TEST_ADD_OPS(absl::Milliseconds); + TEST_ADD_OPS(absl::Seconds); + TEST_ADD_OPS(absl::Minutes); + TEST_ADD_OPS(absl::Hours); + +#undef TEST_ADD_OPS + + EXPECT_EQ(absl::Seconds(2), absl::Seconds(3) - 2 * absl::Milliseconds(500)); + EXPECT_EQ(absl::Seconds(2) + absl::Milliseconds(500), + absl::Seconds(3) - absl::Milliseconds(500)); + + EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(998), + absl::Milliseconds(999) + absl::Milliseconds(999)); + + EXPECT_EQ(absl::Milliseconds(-1), + absl::Milliseconds(998) - absl::Milliseconds(999)); + + // Tests fractions of a nanoseconds. These are implementation details only. + EXPECT_GT(absl::Nanoseconds(1), absl::Nanoseconds(1) / 2); + EXPECT_EQ(absl::Nanoseconds(1), + absl::Nanoseconds(1) / 2 + absl::Nanoseconds(1) / 2); + EXPECT_GT(absl::Nanoseconds(1) / 4, absl::Nanoseconds(0)); + EXPECT_EQ(absl::Nanoseconds(1) / 8, absl::Nanoseconds(0)); + + // Tests subtraction that will cause wrap around of the rep_lo_ bits. + absl::Duration d_7_5 = absl::Seconds(7) + absl::Milliseconds(500); + absl::Duration d_3_7 = absl::Seconds(3) + absl::Milliseconds(700); + absl::Duration ans_3_8 = absl::Seconds(3) + absl::Milliseconds(800); + EXPECT_EQ(ans_3_8, d_7_5 - d_3_7); + + // Subtracting min_duration + absl::Duration min_dur = absl::Seconds(kint64min); + EXPECT_EQ(absl::Seconds(0), min_dur - min_dur); + EXPECT_EQ(absl::Seconds(kint64max), absl::Seconds(-1) - min_dur); +} + +TEST(Duration, Negation) { + // By storing negations of various values in constexpr variables we + // verify that the initializers are constant expressions. + constexpr absl::Duration negated_zero_duration = -absl::ZeroDuration(); + EXPECT_EQ(negated_zero_duration, absl::ZeroDuration()); + + constexpr absl::Duration negated_infinite_duration = + -absl::InfiniteDuration(); + EXPECT_NE(negated_infinite_duration, absl::InfiniteDuration()); + EXPECT_EQ(-negated_infinite_duration, absl::InfiniteDuration()); + + // The public APIs to check if a duration is infinite depend on using + // -InfiniteDuration(), but we're trying to test operator- here, so we + // need to use the lower-level internal query IsInfiniteDuration. + EXPECT_TRUE( + absl::time_internal::IsInfiniteDuration(negated_infinite_duration)); + + // The largest Duration is kint64max seconds and kTicksPerSecond - 1 ticks. + // Using the absl::time_internal::MakeDuration API is the cleanest way to + // construct that Duration. + constexpr absl::Duration max_duration = absl::time_internal::MakeDuration( + kint64max, absl::time_internal::kTicksPerSecond - 1); + constexpr absl::Duration negated_max_duration = -max_duration; + // The largest negatable value is one tick above the minimum representable; + // it's the negation of max_duration. + constexpr absl::Duration nearly_min_duration = + absl::time_internal::MakeDuration(kint64min, int64_t{1}); + constexpr absl::Duration negated_nearly_min_duration = -nearly_min_duration; + + EXPECT_EQ(negated_max_duration, nearly_min_duration); + EXPECT_EQ(negated_nearly_min_duration, max_duration); + EXPECT_EQ(-(-max_duration), max_duration); + + constexpr absl::Duration min_duration = + absl::time_internal::MakeDuration(kint64min); + constexpr absl::Duration negated_min_duration = -min_duration; + EXPECT_EQ(negated_min_duration, absl::InfiniteDuration()); +} + +TEST(Duration, AbsoluteValue) { + EXPECT_EQ(absl::ZeroDuration(), AbsDuration(absl::ZeroDuration())); + EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(1))); + EXPECT_EQ(absl::Seconds(1), AbsDuration(absl::Seconds(-1))); + + EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(absl::InfiniteDuration())); + EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(-absl::InfiniteDuration())); + + absl::Duration max_dur = + absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4); + EXPECT_EQ(max_dur, AbsDuration(max_dur)); + + absl::Duration min_dur = absl::Seconds(kint64min); + EXPECT_EQ(absl::InfiniteDuration(), AbsDuration(min_dur)); + EXPECT_EQ(max_dur, AbsDuration(min_dur + absl::Nanoseconds(1) / 4)); +} + +TEST(Duration, Multiplication) { +#define TEST_MUL_OPS(UNIT) \ + do { \ + EXPECT_EQ(UNIT(5), UNIT(2) * 2.5); \ + EXPECT_EQ(UNIT(2), UNIT(5) / 2.5); \ + EXPECT_EQ(UNIT(-5), UNIT(-2) * 2.5); \ + EXPECT_EQ(UNIT(-5), -UNIT(2) * 2.5); \ + EXPECT_EQ(UNIT(-5), UNIT(2) * -2.5); \ + EXPECT_EQ(UNIT(-2), UNIT(-5) / 2.5); \ + EXPECT_EQ(UNIT(-2), -UNIT(5) / 2.5); \ + EXPECT_EQ(UNIT(-2), UNIT(5) / -2.5); \ + EXPECT_EQ(UNIT(2), UNIT(11) % UNIT(3)); \ + absl::Duration a = UNIT(2); \ + a *= 2.5; \ + EXPECT_EQ(UNIT(5), a); \ + a /= 2.5; \ + EXPECT_EQ(UNIT(2), a); \ + a %= UNIT(1); \ + EXPECT_EQ(UNIT(0), a); \ + absl::Duration big = UNIT(1000000000); \ + big *= 3; \ + big /= 3; \ + EXPECT_EQ(UNIT(1000000000), big); \ + EXPECT_EQ(-UNIT(2), -UNIT(2)); \ + EXPECT_EQ(-UNIT(2), UNIT(2) * -1); \ + EXPECT_EQ(-UNIT(2), -1 * UNIT(2)); \ + EXPECT_EQ(-UNIT(-2), UNIT(2)); \ + EXPECT_EQ(2, UNIT(2) / UNIT(1)); \ + absl::Duration rem; \ + EXPECT_EQ(2, absl::IDivDuration(UNIT(2), UNIT(1), &rem)); \ + EXPECT_EQ(2.0, absl::FDivDuration(UNIT(2), UNIT(1))); \ + } while (0) + + TEST_MUL_OPS(absl::Nanoseconds); + TEST_MUL_OPS(absl::Microseconds); + TEST_MUL_OPS(absl::Milliseconds); + TEST_MUL_OPS(absl::Seconds); + TEST_MUL_OPS(absl::Minutes); + TEST_MUL_OPS(absl::Hours); + +#undef TEST_MUL_OPS + + // Ensures that multiplication and division by 1 with a maxed-out durations + // doesn't lose precision. + absl::Duration max_dur = + absl::Seconds(kint64max) + (absl::Seconds(1) - absl::Nanoseconds(1) / 4); + absl::Duration min_dur = absl::Seconds(kint64min); + EXPECT_EQ(max_dur, max_dur * 1); + EXPECT_EQ(max_dur, max_dur / 1); + EXPECT_EQ(min_dur, min_dur * 1); + EXPECT_EQ(min_dur, min_dur / 1); + + // Tests division on a Duration with a large number of significant digits. + // Tests when the digits span hi and lo as well as only in hi. + absl::Duration sigfigs = absl::Seconds(2000000000) + absl::Nanoseconds(3); + EXPECT_EQ(absl::Seconds(666666666) + absl::Nanoseconds(666666667) + + absl::Nanoseconds(1) / 2, + sigfigs / 3); + sigfigs = absl::Seconds(int64_t{7000000000}); + EXPECT_EQ(absl::Seconds(2333333333) + absl::Nanoseconds(333333333) + + absl::Nanoseconds(1) / 4, + sigfigs / 3); + + EXPECT_EQ(absl::Seconds(7) + absl::Milliseconds(500), absl::Seconds(3) * 2.5); + EXPECT_EQ(absl::Seconds(8) * -1 + absl::Milliseconds(300), + (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5); + EXPECT_EQ(-absl::Seconds(8) + absl::Milliseconds(300), + (absl::Seconds(2) + absl::Milliseconds(200)) * -3.5); + EXPECT_EQ(absl::Seconds(1) + absl::Milliseconds(875), + (absl::Seconds(7) + absl::Milliseconds(500)) / 4); + EXPECT_EQ(absl::Seconds(30), + (absl::Seconds(7) + absl::Milliseconds(500)) / 0.25); + EXPECT_EQ(absl::Seconds(3), + (absl::Seconds(7) + absl::Milliseconds(500)) / 2.5); + + // Tests division remainder. + EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(7) % absl::Nanoseconds(1)); + EXPECT_EQ(absl::Nanoseconds(0), absl::Nanoseconds(0) % absl::Nanoseconds(10)); + EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(7) % absl::Nanoseconds(5)); + EXPECT_EQ(absl::Nanoseconds(2), absl::Nanoseconds(2) % absl::Nanoseconds(5)); + + EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(10) % absl::Nanoseconds(3)); + EXPECT_EQ(absl::Nanoseconds(1), + absl::Nanoseconds(10) % absl::Nanoseconds(-3)); + EXPECT_EQ(absl::Nanoseconds(-1), + absl::Nanoseconds(-10) % absl::Nanoseconds(3)); + EXPECT_EQ(absl::Nanoseconds(-1), + absl::Nanoseconds(-10) % absl::Nanoseconds(-3)); + + EXPECT_EQ(absl::Milliseconds(100), + absl::Seconds(1) % absl::Milliseconds(300)); + EXPECT_EQ( + absl::Milliseconds(300), + (absl::Seconds(3) + absl::Milliseconds(800)) % absl::Milliseconds(500)); + + EXPECT_EQ(absl::Nanoseconds(1), absl::Nanoseconds(1) % absl::Seconds(1)); + EXPECT_EQ(absl::Nanoseconds(-1), absl::Nanoseconds(-1) % absl::Seconds(1)); + EXPECT_EQ(0, absl::Nanoseconds(-1) / absl::Seconds(1)); // Actual -1e-9 + + // Tests identity a = (a/b)*b + a%b +#define TEST_MOD_IDENTITY(a, b) \ + EXPECT_EQ((a), ((a) / (b))*(b) + ((a)%(b))) + + TEST_MOD_IDENTITY(absl::Seconds(0), absl::Seconds(2)); + TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(1)); + TEST_MOD_IDENTITY(absl::Seconds(1), absl::Seconds(2)); + TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(1)); + + TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(1)); + TEST_MOD_IDENTITY(absl::Seconds(2), absl::Seconds(-1)); + TEST_MOD_IDENTITY(absl::Seconds(-2), absl::Seconds(-1)); + + TEST_MOD_IDENTITY(absl::Nanoseconds(0), absl::Nanoseconds(2)); + TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(1)); + TEST_MOD_IDENTITY(absl::Nanoseconds(1), absl::Nanoseconds(2)); + TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(1)); + + TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(1)); + TEST_MOD_IDENTITY(absl::Nanoseconds(2), absl::Nanoseconds(-1)); + TEST_MOD_IDENTITY(absl::Nanoseconds(-2), absl::Nanoseconds(-1)); + + // Mixed seconds + subseconds + absl::Duration mixed_a = absl::Seconds(1) + absl::Nanoseconds(2); + absl::Duration mixed_b = absl::Seconds(1) + absl::Nanoseconds(3); + + TEST_MOD_IDENTITY(absl::Seconds(0), mixed_a); + TEST_MOD_IDENTITY(mixed_a, mixed_a); + TEST_MOD_IDENTITY(mixed_a, mixed_b); + TEST_MOD_IDENTITY(mixed_b, mixed_a); + + TEST_MOD_IDENTITY(-mixed_a, mixed_b); + TEST_MOD_IDENTITY(mixed_a, -mixed_b); + TEST_MOD_IDENTITY(-mixed_a, -mixed_b); + +#undef TEST_MOD_IDENTITY +} + +TEST(Duration, Truncation) { + const absl::Duration d = absl::Nanoseconds(1234567890); + const absl::Duration inf = absl::InfiniteDuration(); + for (int unit_sign : {1, -1}) { // sign shouldn't matter + EXPECT_EQ(absl::Nanoseconds(1234567890), + Trunc(d, unit_sign * absl::Nanoseconds(1))); + EXPECT_EQ(absl::Microseconds(1234567), + Trunc(d, unit_sign * absl::Microseconds(1))); + EXPECT_EQ(absl::Milliseconds(1234), + Trunc(d, unit_sign * absl::Milliseconds(1))); + EXPECT_EQ(absl::Seconds(1), Trunc(d, unit_sign * absl::Seconds(1))); + EXPECT_EQ(inf, Trunc(inf, unit_sign * absl::Seconds(1))); + + EXPECT_EQ(absl::Nanoseconds(-1234567890), + Trunc(-d, unit_sign * absl::Nanoseconds(1))); + EXPECT_EQ(absl::Microseconds(-1234567), + Trunc(-d, unit_sign * absl::Microseconds(1))); + EXPECT_EQ(absl::Milliseconds(-1234), + Trunc(-d, unit_sign * absl::Milliseconds(1))); + EXPECT_EQ(absl::Seconds(-1), Trunc(-d, unit_sign * absl::Seconds(1))); + EXPECT_EQ(-inf, Trunc(-inf, unit_sign * absl::Seconds(1))); + } +} + +TEST(Duration, Flooring) { + const absl::Duration d = absl::Nanoseconds(1234567890); + const absl::Duration inf = absl::InfiniteDuration(); + for (int unit_sign : {1, -1}) { // sign shouldn't matter + EXPECT_EQ(absl::Nanoseconds(1234567890), + absl::Floor(d, unit_sign * absl::Nanoseconds(1))); + EXPECT_EQ(absl::Microseconds(1234567), + absl::Floor(d, unit_sign * absl::Microseconds(1))); + EXPECT_EQ(absl::Milliseconds(1234), + absl::Floor(d, unit_sign * absl::Milliseconds(1))); + EXPECT_EQ(absl::Seconds(1), absl::Floor(d, unit_sign * absl::Seconds(1))); + EXPECT_EQ(inf, absl::Floor(inf, unit_sign * absl::Seconds(1))); + + EXPECT_EQ(absl::Nanoseconds(-1234567890), + absl::Floor(-d, unit_sign * absl::Nanoseconds(1))); + EXPECT_EQ(absl::Microseconds(-1234568), + absl::Floor(-d, unit_sign * absl::Microseconds(1))); + EXPECT_EQ(absl::Milliseconds(-1235), + absl::Floor(-d, unit_sign * absl::Milliseconds(1))); + EXPECT_EQ(absl::Seconds(-2), absl::Floor(-d, unit_sign * absl::Seconds(1))); + EXPECT_EQ(-inf, absl::Floor(-inf, unit_sign * absl::Seconds(1))); + } +} + +TEST(Duration, Ceiling) { + const absl::Duration d = absl::Nanoseconds(1234567890); + const absl::Duration inf = absl::InfiniteDuration(); + for (int unit_sign : {1, -1}) { // // sign shouldn't matter + EXPECT_EQ(absl::Nanoseconds(1234567890), + absl::Ceil(d, unit_sign * absl::Nanoseconds(1))); + EXPECT_EQ(absl::Microseconds(1234568), + absl::Ceil(d, unit_sign * absl::Microseconds(1))); + EXPECT_EQ(absl::Milliseconds(1235), + absl::Ceil(d, unit_sign * absl::Milliseconds(1))); + EXPECT_EQ(absl::Seconds(2), absl::Ceil(d, unit_sign * absl::Seconds(1))); + EXPECT_EQ(inf, absl::Ceil(inf, unit_sign * absl::Seconds(1))); + + EXPECT_EQ(absl::Nanoseconds(-1234567890), + absl::Ceil(-d, unit_sign * absl::Nanoseconds(1))); + EXPECT_EQ(absl::Microseconds(-1234567), + absl::Ceil(-d, unit_sign * absl::Microseconds(1))); + EXPECT_EQ(absl::Milliseconds(-1234), + absl::Ceil(-d, unit_sign * absl::Milliseconds(1))); + EXPECT_EQ(absl::Seconds(-1), absl::Ceil(-d, unit_sign * absl::Seconds(1))); + EXPECT_EQ(-inf, absl::Ceil(-inf, unit_sign * absl::Seconds(1))); + } +} + +TEST(Duration, RoundTripUnits) { + const int kRange = 100000; + +#define ROUND_TRIP_UNIT(U, LOW, HIGH) \ + do { \ + for (int64_t i = LOW; i < HIGH; ++i) { \ + absl::Duration d = absl::U(i); \ + if (d == absl::InfiniteDuration()) \ + EXPECT_EQ(kint64max, d / absl::U(1)); \ + else if (d == -absl::InfiniteDuration()) \ + EXPECT_EQ(kint64min, d / absl::U(1)); \ + else \ + EXPECT_EQ(i, absl::U(i) / absl::U(1)); \ + } \ + } while (0) + + ROUND_TRIP_UNIT(Nanoseconds, kint64min, kint64min + kRange); + ROUND_TRIP_UNIT(Nanoseconds, -kRange, kRange); + ROUND_TRIP_UNIT(Nanoseconds, kint64max - kRange, kint64max); + + ROUND_TRIP_UNIT(Microseconds, kint64min, kint64min + kRange); + ROUND_TRIP_UNIT(Microseconds, -kRange, kRange); + ROUND_TRIP_UNIT(Microseconds, kint64max - kRange, kint64max); + + ROUND_TRIP_UNIT(Milliseconds, kint64min, kint64min + kRange); + ROUND_TRIP_UNIT(Milliseconds, -kRange, kRange); + ROUND_TRIP_UNIT(Milliseconds, kint64max - kRange, kint64max); + + ROUND_TRIP_UNIT(Seconds, kint64min, kint64min + kRange); + ROUND_TRIP_UNIT(Seconds, -kRange, kRange); + ROUND_TRIP_UNIT(Seconds, kint64max - kRange, kint64max); + + ROUND_TRIP_UNIT(Minutes, kint64min / 60, kint64min / 60 + kRange); + ROUND_TRIP_UNIT(Minutes, -kRange, kRange); + ROUND_TRIP_UNIT(Minutes, kint64max / 60 - kRange, kint64max / 60); + + ROUND_TRIP_UNIT(Hours, kint64min / 3600, kint64min / 3600 + kRange); + ROUND_TRIP_UNIT(Hours, -kRange, kRange); + ROUND_TRIP_UNIT(Hours, kint64max / 3600 - kRange, kint64max / 3600); + +#undef ROUND_TRIP_UNIT +} + +TEST(Duration, TruncConversions) { + // Tests ToTimespec()/DurationFromTimespec() + const struct { + absl::Duration d; + timespec ts; + } to_ts[] = { + {absl::Seconds(1) + absl::Nanoseconds(1), {1, 1}}, + {absl::Seconds(1) + absl::Nanoseconds(1) / 2, {1, 0}}, + {absl::Seconds(1) + absl::Nanoseconds(0), {1, 0}}, + {absl::Seconds(0) + absl::Nanoseconds(0), {0, 0}}, + {absl::Seconds(0) - absl::Nanoseconds(1) / 2, {0, 0}}, + {absl::Seconds(0) - absl::Nanoseconds(1), {-1, 999999999}}, + {absl::Seconds(-1) + absl::Nanoseconds(1), {-1, 1}}, + {absl::Seconds(-1) + absl::Nanoseconds(1) / 2, {-1, 1}}, + {absl::Seconds(-1) + absl::Nanoseconds(0), {-1, 0}}, + {absl::Seconds(-1) - absl::Nanoseconds(1) / 2, {-1, 0}}, + }; + for (const auto& test : to_ts) { + EXPECT_THAT(absl::ToTimespec(test.d), TimespecMatcher(test.ts)); + } + const struct { + timespec ts; + absl::Duration d; + } from_ts[] = { + {{1, 1}, absl::Seconds(1) + absl::Nanoseconds(1)}, + {{1, 0}, absl::Seconds(1) + absl::Nanoseconds(0)}, + {{0, 0}, absl::Seconds(0) + absl::Nanoseconds(0)}, + {{0, -1}, absl::Seconds(0) - absl::Nanoseconds(1)}, + {{-1, 999999999}, absl::Seconds(0) - absl::Nanoseconds(1)}, + {{-1, 1}, absl::Seconds(-1) + absl::Nanoseconds(1)}, + {{-1, 0}, absl::Seconds(-1) + absl::Nanoseconds(0)}, + {{-1, -1}, absl::Seconds(-1) - absl::Nanoseconds(1)}, + {{-2, 999999999}, absl::Seconds(-1) - absl::Nanoseconds(1)}, + }; + for (const auto& test : from_ts) { + EXPECT_EQ(test.d, absl::DurationFromTimespec(test.ts)); + } + + // Tests ToTimeval()/DurationFromTimeval() (same as timespec above) + const struct { + absl::Duration d; + timeval tv; + } to_tv[] = { + {absl::Seconds(1) + absl::Microseconds(1), {1, 1}}, + {absl::Seconds(1) + absl::Microseconds(1) / 2, {1, 0}}, + {absl::Seconds(1) + absl::Microseconds(0), {1, 0}}, + {absl::Seconds(0) + absl::Microseconds(0), {0, 0}}, + {absl::Seconds(0) - absl::Microseconds(1) / 2, {0, 0}}, + {absl::Seconds(0) - absl::Microseconds(1), {-1, 999999}}, + {absl::Seconds(-1) + absl::Microseconds(1), {-1, 1}}, + {absl::Seconds(-1) + absl::Microseconds(1) / 2, {-1, 1}}, + {absl::Seconds(-1) + absl::Microseconds(0), {-1, 0}}, + {absl::Seconds(-1) - absl::Microseconds(1) / 2, {-1, 0}}, + }; + for (const auto& test : to_tv) { + EXPECT_THAT(absl::ToTimeval(test.d), TimevalMatcher(test.tv)); + } + const struct { + timeval tv; + absl::Duration d; + } from_tv[] = { + {{1, 1}, absl::Seconds(1) + absl::Microseconds(1)}, + {{1, 0}, absl::Seconds(1) + absl::Microseconds(0)}, + {{0, 0}, absl::Seconds(0) + absl::Microseconds(0)}, + {{0, -1}, absl::Seconds(0) - absl::Microseconds(1)}, + {{-1, 999999}, absl::Seconds(0) - absl::Microseconds(1)}, + {{-1, 1}, absl::Seconds(-1) + absl::Microseconds(1)}, + {{-1, 0}, absl::Seconds(-1) + absl::Microseconds(0)}, + {{-1, -1}, absl::Seconds(-1) - absl::Microseconds(1)}, + {{-2, 999999}, absl::Seconds(-1) - absl::Microseconds(1)}, + }; + for (const auto& test : from_tv) { + EXPECT_EQ(test.d, absl::DurationFromTimeval(test.tv)); + } +} + +TEST(Duration, SmallConversions) { + // Special tests for conversions of small durations. + + EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0)); + // TODO(bww): Is the next one OK? + EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(0.124999999e-9)); + EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.125e-9)); + EXPECT_EQ(absl::Nanoseconds(1) / 4, absl::Seconds(0.250e-9)); + EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.375e-9)); + EXPECT_EQ(absl::Nanoseconds(1) / 2, absl::Seconds(0.500e-9)); + EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.625e-9)); + EXPECT_EQ(absl::Nanoseconds(3) / 4, absl::Seconds(0.750e-9)); + EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(0.875e-9)); + EXPECT_EQ(absl::Nanoseconds(1), absl::Seconds(1.000e-9)); + + EXPECT_EQ(absl::ZeroDuration(), absl::Seconds(-0.124999999e-9)); + EXPECT_EQ(-absl::Nanoseconds(1) / 4, absl::Seconds(-0.125e-9)); + EXPECT_EQ(-absl::Nanoseconds(1) / 4, absl::Seconds(-0.250e-9)); + EXPECT_EQ(-absl::Nanoseconds(1) / 2, absl::Seconds(-0.375e-9)); + EXPECT_EQ(-absl::Nanoseconds(1) / 2, absl::Seconds(-0.500e-9)); + EXPECT_EQ(-absl::Nanoseconds(3) / 4, absl::Seconds(-0.625e-9)); + EXPECT_EQ(-absl::Nanoseconds(3) / 4, absl::Seconds(-0.750e-9)); + EXPECT_EQ(-absl::Nanoseconds(1), absl::Seconds(-0.875e-9)); + EXPECT_EQ(-absl::Nanoseconds(1), absl::Seconds(-1.000e-9)); + + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + EXPECT_THAT(ToTimespec(absl::Nanoseconds(0)), TimespecMatcher(ts)); + // TODO(bww): Are the next three OK? + EXPECT_THAT(ToTimespec(absl::Nanoseconds(1) / 4), TimespecMatcher(ts)); + EXPECT_THAT(ToTimespec(absl::Nanoseconds(2) / 4), TimespecMatcher(ts)); + EXPECT_THAT(ToTimespec(absl::Nanoseconds(3) / 4), TimespecMatcher(ts)); + ts.tv_nsec = 1; + EXPECT_THAT(ToTimespec(absl::Nanoseconds(4) / 4), TimespecMatcher(ts)); + EXPECT_THAT(ToTimespec(absl::Nanoseconds(5) / 4), TimespecMatcher(ts)); + EXPECT_THAT(ToTimespec(absl::Nanoseconds(6) / 4), TimespecMatcher(ts)); + EXPECT_THAT(ToTimespec(absl::Nanoseconds(7) / 4), TimespecMatcher(ts)); + ts.tv_nsec = 2; + EXPECT_THAT(ToTimespec(absl::Nanoseconds(8) / 4), TimespecMatcher(ts)); + + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + EXPECT_THAT(ToTimeval(absl::Nanoseconds(0)), TimevalMatcher(tv)); + // TODO(bww): Is the next one OK? + EXPECT_THAT(ToTimeval(absl::Nanoseconds(999)), TimevalMatcher(tv)); + tv.tv_usec = 1; + EXPECT_THAT(ToTimeval(absl::Nanoseconds(1000)), TimevalMatcher(tv)); + EXPECT_THAT(ToTimeval(absl::Nanoseconds(1999)), TimevalMatcher(tv)); + tv.tv_usec = 2; + EXPECT_THAT(ToTimeval(absl::Nanoseconds(2000)), TimevalMatcher(tv)); +} + +void VerifySameAsMul(double time_as_seconds, int* const misses) { + auto direct_seconds = absl::Seconds(time_as_seconds); + auto mul_by_one_second = time_as_seconds * absl::Seconds(1); + if (direct_seconds != mul_by_one_second) { + if (*misses > 10) return; + ASSERT_LE(++(*misses), 10) << "Too many errors, not reporting more."; + EXPECT_EQ(direct_seconds, mul_by_one_second) + << "given double time_as_seconds = " << std::setprecision(17) + << time_as_seconds; + } +} + +// For a variety of interesting durations, we find the exact point +// where one double converts to that duration, and the very next double +// converts to the next duration. For both of those points, verify that +// Seconds(point) returns the same duration as point * Seconds(1.0) +TEST(Duration, ToDoubleSecondsCheckEdgeCases) { + constexpr uint32_t kTicksPerSecond = absl::time_internal::kTicksPerSecond; + constexpr auto duration_tick = absl::time_internal::MakeDuration(0, 1u); + int misses = 0; + for (int64_t seconds = 0; seconds < 99; ++seconds) { + uint32_t tick_vals[] = {0, +999, +999999, +999999999, kTicksPerSecond - 1, + 0, 1000, 1000000, 1000000000, kTicksPerSecond, + 1, 1001, 1000001, 1000000001, kTicksPerSecond + 1, + 2, 1002, 1000002, 1000000002, kTicksPerSecond + 2, + 3, 1003, 1000003, 1000000003, kTicksPerSecond + 3, + 4, 1004, 1000004, 1000000004, kTicksPerSecond + 4, + 5, 6, 7, 8, 9}; + for (uint32_t ticks : tick_vals) { + absl::Duration s_plus_t = absl::Seconds(seconds) + ticks * duration_tick; + for (absl::Duration d : {s_plus_t, -s_plus_t}) { + absl::Duration after_d = d + duration_tick; + EXPECT_NE(d, after_d); + EXPECT_EQ(after_d - d, duration_tick); + + double low_edge = ToDoubleSeconds(d); + EXPECT_EQ(d, absl::Seconds(low_edge)); + + double high_edge = ToDoubleSeconds(after_d); + EXPECT_EQ(after_d, absl::Seconds(high_edge)); + + for (;;) { + double midpoint = low_edge + (high_edge - low_edge) / 2; + if (midpoint == low_edge || midpoint == high_edge) break; + absl::Duration mid_duration = absl::Seconds(midpoint); + if (mid_duration == d) { + low_edge = midpoint; + } else { + EXPECT_EQ(mid_duration, after_d); + high_edge = midpoint; + } + } + // Now low_edge is the highest double that converts to Duration d, + // and high_edge is the lowest double that converts to Duration after_d. + VerifySameAsMul(low_edge, &misses); + VerifySameAsMul(high_edge, &misses); + } + } + } +} + +TEST(Duration, ToDoubleSecondsCheckRandom) { + std::random_device rd; + std::seed_seq seed({rd(), rd(), rd(), rd(), rd(), rd(), rd(), rd()}); + std::mt19937_64 gen(seed); + // We want doubles distributed from 1/8ns up to 2^63, where + // as many values are tested from 1ns to 2ns as from 1sec to 2sec, + // so even distribute along a log-scale of those values, and + // exponentiate before using them. (9.223377e+18 is just slightly + // out of bounds for absl::Duration.) + std::uniform_real_distribution<double> uniform(std::log(0.125e-9), + std::log(9.223377e+18)); + int misses = 0; + for (int i = 0; i < 1000000; ++i) { + double d = std::exp(uniform(gen)); + VerifySameAsMul(d, &misses); + VerifySameAsMul(-d, &misses); + } +} + +TEST(Duration, ConversionSaturation) { + absl::Duration d; + + const auto max_timeval_sec = + std::numeric_limits<decltype(timeval::tv_sec)>::max(); + const auto min_timeval_sec = + std::numeric_limits<decltype(timeval::tv_sec)>::min(); + timeval tv; + tv.tv_sec = max_timeval_sec; + tv.tv_usec = 999998; + d = absl::DurationFromTimeval(tv); + tv = ToTimeval(d); + EXPECT_EQ(max_timeval_sec, tv.tv_sec); + EXPECT_EQ(999998, tv.tv_usec); + d += absl::Microseconds(1); + tv = ToTimeval(d); + EXPECT_EQ(max_timeval_sec, tv.tv_sec); + EXPECT_EQ(999999, tv.tv_usec); + d += absl::Microseconds(1); // no effect + tv = ToTimeval(d); + EXPECT_EQ(max_timeval_sec, tv.tv_sec); + EXPECT_EQ(999999, tv.tv_usec); + + tv.tv_sec = min_timeval_sec; + tv.tv_usec = 1; + d = absl::DurationFromTimeval(tv); + tv = ToTimeval(d); + EXPECT_EQ(min_timeval_sec, tv.tv_sec); + EXPECT_EQ(1, tv.tv_usec); + d -= absl::Microseconds(1); + tv = ToTimeval(d); + EXPECT_EQ(min_timeval_sec, tv.tv_sec); + EXPECT_EQ(0, tv.tv_usec); + d -= absl::Microseconds(1); // no effect + tv = ToTimeval(d); + EXPECT_EQ(min_timeval_sec, tv.tv_sec); + EXPECT_EQ(0, tv.tv_usec); + + const auto max_timespec_sec = + std::numeric_limits<decltype(timespec::tv_sec)>::max(); + const auto min_timespec_sec = + std::numeric_limits<decltype(timespec::tv_sec)>::min(); + timespec ts; + ts.tv_sec = max_timespec_sec; + ts.tv_nsec = 999999998; + d = absl::DurationFromTimespec(ts); + ts = absl::ToTimespec(d); + EXPECT_EQ(max_timespec_sec, ts.tv_sec); + EXPECT_EQ(999999998, ts.tv_nsec); + d += absl::Nanoseconds(1); + ts = absl::ToTimespec(d); + EXPECT_EQ(max_timespec_sec, ts.tv_sec); + EXPECT_EQ(999999999, ts.tv_nsec); + d += absl::Nanoseconds(1); // no effect + ts = absl::ToTimespec(d); + EXPECT_EQ(max_timespec_sec, ts.tv_sec); + EXPECT_EQ(999999999, ts.tv_nsec); + + ts.tv_sec = min_timespec_sec; + ts.tv_nsec = 1; + d = absl::DurationFromTimespec(ts); + ts = absl::ToTimespec(d); + EXPECT_EQ(min_timespec_sec, ts.tv_sec); + EXPECT_EQ(1, ts.tv_nsec); + d -= absl::Nanoseconds(1); + ts = absl::ToTimespec(d); + EXPECT_EQ(min_timespec_sec, ts.tv_sec); + EXPECT_EQ(0, ts.tv_nsec); + d -= absl::Nanoseconds(1); // no effect + ts = absl::ToTimespec(d); + EXPECT_EQ(min_timespec_sec, ts.tv_sec); + EXPECT_EQ(0, ts.tv_nsec); +} + +TEST(Duration, FormatDuration) { + // Example from Go's docs. + EXPECT_EQ("72h3m0.5s", + absl::FormatDuration(absl::Hours(72) + absl::Minutes(3) + + absl::Milliseconds(500))); + // Go's largest time: 2540400h10m10.000000000s + EXPECT_EQ("2540400h10m10s", + absl::FormatDuration(absl::Hours(2540400) + absl::Minutes(10) + + absl::Seconds(10))); + + EXPECT_EQ("0", absl::FormatDuration(absl::ZeroDuration())); + EXPECT_EQ("0", absl::FormatDuration(absl::Seconds(0))); + EXPECT_EQ("0", absl::FormatDuration(absl::Nanoseconds(0))); + + EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1))); + EXPECT_EQ("1us", absl::FormatDuration(absl::Microseconds(1))); + EXPECT_EQ("1ms", absl::FormatDuration(absl::Milliseconds(1))); + EXPECT_EQ("1s", absl::FormatDuration(absl::Seconds(1))); + EXPECT_EQ("1m", absl::FormatDuration(absl::Minutes(1))); + EXPECT_EQ("1h", absl::FormatDuration(absl::Hours(1))); + + EXPECT_EQ("1h1m", absl::FormatDuration(absl::Hours(1) + absl::Minutes(1))); + EXPECT_EQ("1h1s", absl::FormatDuration(absl::Hours(1) + absl::Seconds(1))); + EXPECT_EQ("1m1s", absl::FormatDuration(absl::Minutes(1) + absl::Seconds(1))); + + EXPECT_EQ("1h0.25s", + absl::FormatDuration(absl::Hours(1) + absl::Milliseconds(250))); + EXPECT_EQ("1m0.25s", + absl::FormatDuration(absl::Minutes(1) + absl::Milliseconds(250))); + EXPECT_EQ("1h1m0.25s", + absl::FormatDuration(absl::Hours(1) + absl::Minutes(1) + + absl::Milliseconds(250))); + EXPECT_EQ("1h0.0005s", + absl::FormatDuration(absl::Hours(1) + absl::Microseconds(500))); + EXPECT_EQ("1h0.0000005s", + absl::FormatDuration(absl::Hours(1) + absl::Nanoseconds(500))); + + // Subsecond special case. + EXPECT_EQ("1.5ns", absl::FormatDuration(absl::Nanoseconds(1) + + absl::Nanoseconds(1) / 2)); + EXPECT_EQ("1.25ns", absl::FormatDuration(absl::Nanoseconds(1) + + absl::Nanoseconds(1) / 4)); + EXPECT_EQ("1ns", absl::FormatDuration(absl::Nanoseconds(1) + + absl::Nanoseconds(1) / 9)); + EXPECT_EQ("1.2us", absl::FormatDuration(absl::Microseconds(1) + + absl::Nanoseconds(200))); + EXPECT_EQ("1.2ms", absl::FormatDuration(absl::Milliseconds(1) + + absl::Microseconds(200))); + EXPECT_EQ("1.0002ms", absl::FormatDuration(absl::Milliseconds(1) + + absl::Nanoseconds(200))); + EXPECT_EQ("1.00001ms", absl::FormatDuration(absl::Milliseconds(1) + + absl::Nanoseconds(10))); + EXPECT_EQ("1.000001ms", + absl::FormatDuration(absl::Milliseconds(1) + absl::Nanoseconds(1))); + + // Negative durations. + EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1))); + EXPECT_EQ("-1us", absl::FormatDuration(absl::Microseconds(-1))); + EXPECT_EQ("-1ms", absl::FormatDuration(absl::Milliseconds(-1))); + EXPECT_EQ("-1s", absl::FormatDuration(absl::Seconds(-1))); + EXPECT_EQ("-1m", absl::FormatDuration(absl::Minutes(-1))); + EXPECT_EQ("-1h", absl::FormatDuration(absl::Hours(-1))); + + EXPECT_EQ("-1h1m", + absl::FormatDuration(-(absl::Hours(1) + absl::Minutes(1)))); + EXPECT_EQ("-1h1s", + absl::FormatDuration(-(absl::Hours(1) + absl::Seconds(1)))); + EXPECT_EQ("-1m1s", + absl::FormatDuration(-(absl::Minutes(1) + absl::Seconds(1)))); + + EXPECT_EQ("-1ns", absl::FormatDuration(absl::Nanoseconds(-1))); + EXPECT_EQ("-1.2us", absl::FormatDuration( + -(absl::Microseconds(1) + absl::Nanoseconds(200)))); + EXPECT_EQ("-1.2ms", absl::FormatDuration( + -(absl::Milliseconds(1) + absl::Microseconds(200)))); + EXPECT_EQ("-1.0002ms", absl::FormatDuration(-(absl::Milliseconds(1) + + absl::Nanoseconds(200)))); + EXPECT_EQ("-1.00001ms", absl::FormatDuration(-(absl::Milliseconds(1) + + absl::Nanoseconds(10)))); + EXPECT_EQ("-1.000001ms", absl::FormatDuration(-(absl::Milliseconds(1) + + absl::Nanoseconds(1)))); + + // + // Interesting corner cases. + // + + const absl::Duration qns = absl::Nanoseconds(1) / 4; + const absl::Duration max_dur = + absl::Seconds(kint64max) + (absl::Seconds(1) - qns); + const absl::Duration min_dur = absl::Seconds(kint64min); + + EXPECT_EQ("0.25ns", absl::FormatDuration(qns)); + EXPECT_EQ("-0.25ns", absl::FormatDuration(-qns)); + EXPECT_EQ("2562047788015215h30m7.99999999975s", + absl::FormatDuration(max_dur)); + EXPECT_EQ("-2562047788015215h30m8s", absl::FormatDuration(min_dur)); + + // Tests printing full precision from units that print using FDivDuration + EXPECT_EQ("55.00000000025s", absl::FormatDuration(absl::Seconds(55) + qns)); + EXPECT_EQ("55.00000025ms", + absl::FormatDuration(absl::Milliseconds(55) + qns)); + EXPECT_EQ("55.00025us", absl::FormatDuration(absl::Microseconds(55) + qns)); + EXPECT_EQ("55.25ns", absl::FormatDuration(absl::Nanoseconds(55) + qns)); + + // Formatting infinity + EXPECT_EQ("inf", absl::FormatDuration(absl::InfiniteDuration())); + EXPECT_EQ("-inf", absl::FormatDuration(-absl::InfiniteDuration())); + + // Formatting approximately +/- 100 billion years + const absl::Duration huge_range = ApproxYears(100000000000); + EXPECT_EQ("876000000000000h", absl::FormatDuration(huge_range)); + EXPECT_EQ("-876000000000000h", absl::FormatDuration(-huge_range)); + + EXPECT_EQ("876000000000000h0.999999999s", + absl::FormatDuration(huge_range + + (absl::Seconds(1) - absl::Nanoseconds(1)))); + EXPECT_EQ("876000000000000h0.9999999995s", + absl::FormatDuration( + huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 2))); + EXPECT_EQ("876000000000000h0.99999999975s", + absl::FormatDuration( + huge_range + (absl::Seconds(1) - absl::Nanoseconds(1) / 4))); + + EXPECT_EQ("-876000000000000h0.999999999s", + absl::FormatDuration(-huge_range - + (absl::Seconds(1) - absl::Nanoseconds(1)))); + EXPECT_EQ("-876000000000000h0.9999999995s", + absl::FormatDuration( + -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 2))); + EXPECT_EQ("-876000000000000h0.99999999975s", + absl::FormatDuration( + -huge_range - (absl::Seconds(1) - absl::Nanoseconds(1) / 4))); +} + +TEST(Duration, ParseDuration) { + absl::Duration d; + + // No specified unit. Should only work for zero and infinity. + EXPECT_TRUE(absl::ParseDuration("0", &d)); + EXPECT_EQ(absl::ZeroDuration(), d); + EXPECT_TRUE(absl::ParseDuration("+0", &d)); + EXPECT_EQ(absl::ZeroDuration(), d); + EXPECT_TRUE(absl::ParseDuration("-0", &d)); + EXPECT_EQ(absl::ZeroDuration(), d); + + EXPECT_TRUE(absl::ParseDuration("inf", &d)); + EXPECT_EQ(absl::InfiniteDuration(), d); + EXPECT_TRUE(absl::ParseDuration("+inf", &d)); + EXPECT_EQ(absl::InfiniteDuration(), d); + EXPECT_TRUE(absl::ParseDuration("-inf", &d)); + EXPECT_EQ(-absl::InfiniteDuration(), d); + EXPECT_FALSE(absl::ParseDuration("infBlah", &d)); + + // Illegal input forms. + EXPECT_FALSE(absl::ParseDuration("", &d)); + EXPECT_FALSE(absl::ParseDuration("0.0", &d)); + EXPECT_FALSE(absl::ParseDuration(".0", &d)); + EXPECT_FALSE(absl::ParseDuration(".", &d)); + EXPECT_FALSE(absl::ParseDuration("01", &d)); + EXPECT_FALSE(absl::ParseDuration("1", &d)); + EXPECT_FALSE(absl::ParseDuration("-1", &d)); + EXPECT_FALSE(absl::ParseDuration("2", &d)); + EXPECT_FALSE(absl::ParseDuration("2 s", &d)); + EXPECT_FALSE(absl::ParseDuration(".s", &d)); + EXPECT_FALSE(absl::ParseDuration("-.s", &d)); + EXPECT_FALSE(absl::ParseDuration("s", &d)); + EXPECT_FALSE(absl::ParseDuration(" 2s", &d)); + EXPECT_FALSE(absl::ParseDuration("2s ", &d)); + EXPECT_FALSE(absl::ParseDuration(" 2s ", &d)); + EXPECT_FALSE(absl::ParseDuration("2mt", &d)); + EXPECT_FALSE(absl::ParseDuration("1e3s", &d)); + + // One unit type. + EXPECT_TRUE(absl::ParseDuration("1ns", &d)); + EXPECT_EQ(absl::Nanoseconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1us", &d)); + EXPECT_EQ(absl::Microseconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1ms", &d)); + EXPECT_EQ(absl::Milliseconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1s", &d)); + EXPECT_EQ(absl::Seconds(1), d); + EXPECT_TRUE(absl::ParseDuration("2m", &d)); + EXPECT_EQ(absl::Minutes(2), d); + EXPECT_TRUE(absl::ParseDuration("2h", &d)); + EXPECT_EQ(absl::Hours(2), d); + + // Huge counts of a unit. + EXPECT_TRUE(absl::ParseDuration("9223372036854775807us", &d)); + EXPECT_EQ(absl::Microseconds(9223372036854775807), d); + EXPECT_TRUE(absl::ParseDuration("-9223372036854775807us", &d)); + EXPECT_EQ(absl::Microseconds(-9223372036854775807), d); + + // Multiple units. + EXPECT_TRUE(absl::ParseDuration("2h3m4s", &d)); + EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4), d); + EXPECT_TRUE(absl::ParseDuration("3m4s5us", &d)); + EXPECT_EQ(absl::Minutes(3) + absl::Seconds(4) + absl::Microseconds(5), d); + EXPECT_TRUE(absl::ParseDuration("2h3m4s5ms6us7ns", &d)); + EXPECT_EQ(absl::Hours(2) + absl::Minutes(3) + absl::Seconds(4) + + absl::Milliseconds(5) + absl::Microseconds(6) + + absl::Nanoseconds(7), + d); + + // Multiple units out of order. + EXPECT_TRUE(absl::ParseDuration("2us3m4s5h", &d)); + EXPECT_EQ(absl::Hours(5) + absl::Minutes(3) + absl::Seconds(4) + + absl::Microseconds(2), + d); + + // Fractional values of units. + EXPECT_TRUE(absl::ParseDuration("1.5ns", &d)); + EXPECT_EQ(1.5 * absl::Nanoseconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1.5us", &d)); + EXPECT_EQ(1.5 * absl::Microseconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1.5ms", &d)); + EXPECT_EQ(1.5 * absl::Milliseconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1.5s", &d)); + EXPECT_EQ(1.5 * absl::Seconds(1), d); + EXPECT_TRUE(absl::ParseDuration("1.5m", &d)); + EXPECT_EQ(1.5 * absl::Minutes(1), d); + EXPECT_TRUE(absl::ParseDuration("1.5h", &d)); + EXPECT_EQ(1.5 * absl::Hours(1), d); + + // Huge fractional counts of a unit. + EXPECT_TRUE(absl::ParseDuration("0.4294967295s", &d)); + EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d); + EXPECT_TRUE(absl::ParseDuration("0.429496729501234567890123456789s", &d)); + EXPECT_EQ(absl::Nanoseconds(429496729) + absl::Nanoseconds(1) / 2, d); + + // Negative durations. + EXPECT_TRUE(absl::ParseDuration("-1s", &d)); + EXPECT_EQ(absl::Seconds(-1), d); + EXPECT_TRUE(absl::ParseDuration("-1m", &d)); + EXPECT_EQ(absl::Minutes(-1), d); + EXPECT_TRUE(absl::ParseDuration("-1h", &d)); + EXPECT_EQ(absl::Hours(-1), d); + + EXPECT_TRUE(absl::ParseDuration("-1h2s", &d)); + EXPECT_EQ(-(absl::Hours(1) + absl::Seconds(2)), d); + EXPECT_FALSE(absl::ParseDuration("1h-2s", &d)); + EXPECT_FALSE(absl::ParseDuration("-1h-2s", &d)); + EXPECT_FALSE(absl::ParseDuration("-1h -2s", &d)); +} + +TEST(Duration, FormatParseRoundTrip) { +#define TEST_PARSE_ROUNDTRIP(d) \ + do { \ + std::string s = absl::FormatDuration(d); \ + absl::Duration dur; \ + EXPECT_TRUE(absl::ParseDuration(s, &dur)); \ + EXPECT_EQ(d, dur); \ + } while (0) + + TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1)); + TEST_PARSE_ROUNDTRIP(absl::Microseconds(1)); + TEST_PARSE_ROUNDTRIP(absl::Milliseconds(1)); + TEST_PARSE_ROUNDTRIP(absl::Seconds(1)); + TEST_PARSE_ROUNDTRIP(absl::Minutes(1)); + TEST_PARSE_ROUNDTRIP(absl::Hours(1)); + TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(2)); + + TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(-1)); + TEST_PARSE_ROUNDTRIP(absl::Microseconds(-1)); + TEST_PARSE_ROUNDTRIP(absl::Milliseconds(-1)); + TEST_PARSE_ROUNDTRIP(absl::Seconds(-1)); + TEST_PARSE_ROUNDTRIP(absl::Minutes(-1)); + TEST_PARSE_ROUNDTRIP(absl::Hours(-1)); + + TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(2)); + TEST_PARSE_ROUNDTRIP(absl::Hours(1) + absl::Nanoseconds(-2)); + TEST_PARSE_ROUNDTRIP(absl::Hours(-1) + absl::Nanoseconds(-2)); + + TEST_PARSE_ROUNDTRIP(absl::Nanoseconds(1) + + absl::Nanoseconds(1) / 4); // 1.25ns + + const absl::Duration huge_range = ApproxYears(100000000000); + TEST_PARSE_ROUNDTRIP(huge_range); + TEST_PARSE_ROUNDTRIP(huge_range + (absl::Seconds(1) - absl::Nanoseconds(1))); + +#undef TEST_PARSE_ROUNDTRIP +} + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/format.cc b/third_party/abseil_cpp/absl/time/format.cc new file mode 100644 index 000000000000..4005fb704cf6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/format.cc @@ -0,0 +1,160 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <string.h> + +#include <cctype> +#include <cstdint> + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" +#include "absl/time/time.h" + +namespace cctz = absl::time_internal::cctz; + +namespace absl { +ABSL_NAMESPACE_BEGIN + +ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez"; +ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; + +ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z"; +ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z"; + +namespace { + +const char kInfiniteFutureStr[] = "infinite-future"; +const char kInfinitePastStr[] = "infinite-past"; + +struct cctz_parts { + cctz::time_point<cctz::seconds> sec; + cctz::detail::femtoseconds fem; +}; + +inline cctz::time_point<cctz::seconds> unix_epoch() { + return std::chrono::time_point_cast<cctz::seconds>( + std::chrono::system_clock::from_time_t(0)); +} + +// Splits a Time into seconds and femtoseconds, which can be used with CCTZ. +// Requires that 't' is finite. See duration.cc for details about rep_hi and +// rep_lo. +cctz_parts Split(absl::Time t) { + const auto d = time_internal::ToUnixDuration(t); + const int64_t rep_hi = time_internal::GetRepHi(d); + const int64_t rep_lo = time_internal::GetRepLo(d); + const auto sec = unix_epoch() + cctz::seconds(rep_hi); + const auto fem = cctz::detail::femtoseconds(rep_lo * (1000 * 1000 / 4)); + return {sec, fem}; +} + +// Joins the given seconds and femtoseconds into a Time. See duration.cc for +// details about rep_hi and rep_lo. +absl::Time Join(const cctz_parts& parts) { + const int64_t rep_hi = (parts.sec - unix_epoch()).count(); + const uint32_t rep_lo = parts.fem.count() / (1000 * 1000 / 4); + const auto d = time_internal::MakeDuration(rep_hi, rep_lo); + return time_internal::FromUnixDuration(d); +} + +} // namespace + +std::string FormatTime(absl::string_view format, absl::Time t, + absl::TimeZone tz) { + if (t == absl::InfiniteFuture()) return std::string(kInfiniteFutureStr); + if (t == absl::InfinitePast()) return std::string(kInfinitePastStr); + const auto parts = Split(t); + return cctz::detail::format(std::string(format), parts.sec, parts.fem, + cctz::time_zone(tz)); +} + +std::string FormatTime(absl::Time t, absl::TimeZone tz) { + return FormatTime(RFC3339_full, t, tz); +} + +std::string FormatTime(absl::Time t) { + return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone()); +} + +bool ParseTime(absl::string_view format, absl::string_view input, + absl::Time* time, std::string* err) { + return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err); +} + +// If the input string does not contain an explicit UTC offset, interpret +// the fields with respect to the given TimeZone. +bool ParseTime(absl::string_view format, absl::string_view input, + absl::TimeZone tz, absl::Time* time, std::string* err) { + auto strip_leading_space = [](absl::string_view* sv) { + while (!sv->empty()) { + if (!std::isspace(sv->front())) return; + sv->remove_prefix(1); + } + }; + + // Portable toolchains means we don't get nice constexpr here. + struct Literal { + const char* name; + size_t size; + absl::Time value; + }; + static Literal literals[] = { + {kInfiniteFutureStr, strlen(kInfiniteFutureStr), InfiniteFuture()}, + {kInfinitePastStr, strlen(kInfinitePastStr), InfinitePast()}, + }; + strip_leading_space(&input); + for (const auto& lit : literals) { + if (absl::StartsWith(input, absl::string_view(lit.name, lit.size))) { + absl::string_view tail = input; + tail.remove_prefix(lit.size); + strip_leading_space(&tail); + if (tail.empty()) { + *time = lit.value; + return true; + } + } + } + + std::string error; + cctz_parts parts; + const bool b = + cctz::detail::parse(std::string(format), std::string(input), + cctz::time_zone(tz), &parts.sec, &parts.fem, &error); + if (b) { + *time = Join(parts); + } else if (err != nullptr) { + *err = error; + } + return b; +} + +// Functions required to support absl::Time flags. +bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) { + return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error); +} + +std::string AbslUnparseFlag(absl::Time t) { + return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone()); +} +bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) { + return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error); +} + +std::string UnparseFlag(absl::Time t) { + return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone()); +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/format_benchmark.cc b/third_party/abseil_cpp/absl/time/format_benchmark.cc new file mode 100644 index 000000000000..19e481dbd1a5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/format_benchmark.cc @@ -0,0 +1,64 @@ +// Copyright 2018 The Abseil Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cstddef> +#include <string> + +#include "absl/time/internal/test_util.h" +#include "absl/time/time.h" +#include "benchmark/benchmark.h" + +namespace { + +namespace { +const char* const kFormats[] = { + absl::RFC1123_full, // 0 + absl::RFC1123_no_wday, // 1 + absl::RFC3339_full, // 2 + absl::RFC3339_sec, // 3 + "%Y-%m-%d%ET%H:%M:%S", // 4 + "%Y-%m-%d", // 5 +}; +const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); +} // namespace + +void BM_Format_FormatTime(benchmark::State& state) { + const std::string fmt = kFormats[state.range(0)]; + state.SetLabel(fmt); + const absl::TimeZone lax = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + const absl::Time t = + absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) + + absl::Nanoseconds(1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length()); + } +} +BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1); + +void BM_Format_ParseTime(benchmark::State& state) { + const std::string fmt = kFormats[state.range(0)]; + state.SetLabel(fmt); + const absl::TimeZone lax = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + absl::Time t = absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) + + absl::Nanoseconds(1); + const std::string when = absl::FormatTime(fmt, t, lax); + std::string err; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ParseTime(fmt, when, lax, &t, &err)); + } +} +BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1); + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/format_test.cc b/third_party/abseil_cpp/absl/time/format_test.cc new file mode 100644 index 000000000000..a9a1eb8ee1d6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/format_test.cc @@ -0,0 +1,441 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cstdint> +#include <limits> +#include <string> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/time/internal/test_util.h" +#include "absl/time/time.h" + +using testing::HasSubstr; + +namespace { + +// A helper that tests the given format specifier by itself, and with leading +// and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu"). +void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, + const std::string& fmt, const std::string& ans) { + EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz)); + EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz)); + EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz)); + EXPECT_EQ("xxx " + ans + " yyy", + absl::FormatTime("xxx " + fmt + " yyy", t, tz)); +} + +// +// Testing FormatTime() +// + +TEST(FormatTime, Basics) { + absl::TimeZone tz = absl::UTCTimeZone(); + absl::Time t = absl::FromTimeT(0); + + // Starts with a couple basic edge cases. + EXPECT_EQ("", absl::FormatTime("", t, tz)); + EXPECT_EQ(" ", absl::FormatTime(" ", t, tz)); + EXPECT_EQ(" ", absl::FormatTime(" ", t, tz)); + EXPECT_EQ("xxx", absl::FormatTime("xxx", t, tz)); + std::string big(128, 'x'); + EXPECT_EQ(big, absl::FormatTime(big, t, tz)); + // Cause the 1024-byte buffer to grow. + std::string bigger(100000, 'x'); + EXPECT_EQ(bigger, absl::FormatTime(bigger, t, tz)); + + t += absl::Hours(13) + absl::Minutes(4) + absl::Seconds(5); + t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8); + EXPECT_EQ("1970-01-01", absl::FormatTime("%Y-%m-%d", t, tz)); + EXPECT_EQ("13:04:05", absl::FormatTime("%H:%M:%S", t, tz)); + EXPECT_EQ("13:04:05.006", absl::FormatTime("%H:%M:%E3S", t, tz)); + EXPECT_EQ("13:04:05.006007", absl::FormatTime("%H:%M:%E6S", t, tz)); + EXPECT_EQ("13:04:05.006007008", absl::FormatTime("%H:%M:%E9S", t, tz)); +} + +TEST(FormatTime, LocaleSpecific) { + const absl::TimeZone tz = absl::UTCTimeZone(); + absl::Time t = absl::FromTimeT(0); + + TestFormatSpecifier(t, tz, "%a", "Thu"); + TestFormatSpecifier(t, tz, "%A", "Thursday"); + TestFormatSpecifier(t, tz, "%b", "Jan"); + TestFormatSpecifier(t, tz, "%B", "January"); + + // %c should at least produce the numeric year and time-of-day. + const std::string s = + absl::FormatTime("%c", absl::FromTimeT(0), absl::UTCTimeZone()); + EXPECT_THAT(s, HasSubstr("1970")); + EXPECT_THAT(s, HasSubstr("00:00:00")); + + TestFormatSpecifier(t, tz, "%p", "AM"); + TestFormatSpecifier(t, tz, "%x", "01/01/70"); + TestFormatSpecifier(t, tz, "%X", "00:00:00"); +} + +TEST(FormatTime, ExtendedSeconds) { + const absl::TimeZone tz = absl::UTCTimeZone(); + + // No subseconds. + absl::Time t = absl::FromTimeT(0) + absl::Seconds(5); + EXPECT_EQ("05", absl::FormatTime("%E*S", t, tz)); + EXPECT_EQ("05.000000000000000", absl::FormatTime("%E15S", t, tz)); + + // With subseconds. + t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8); + EXPECT_EQ("05.006007008", absl::FormatTime("%E*S", t, tz)); + EXPECT_EQ("05", absl::FormatTime("%E0S", t, tz)); + EXPECT_EQ("05.006007008000000", absl::FormatTime("%E15S", t, tz)); + + // Times before the Unix epoch. + t = absl::FromUnixMicros(-1); + EXPECT_EQ("1969-12-31 23:59:59.999999", + absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); + + // Here is a "%E*S" case we got wrong for a while. While the first + // instant below is correctly rendered as "...:07.333304", the second + // one used to appear as "...:07.33330499999999999". + t = absl::FromUnixMicros(1395024427333304); + EXPECT_EQ("2014-03-17 02:47:07.333304", + absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); + t += absl::Microseconds(1); + EXPECT_EQ("2014-03-17 02:47:07.333305", + absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); +} + +TEST(FormatTime, RFC1123FormatPadsYear) { // locale specific + absl::TimeZone tz = absl::UTCTimeZone(); + + // A year of 77 should be padded to 0077. + absl::Time t = absl::FromCivil(absl::CivilSecond(77, 6, 28, 9, 8, 7), tz); + EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000", + absl::FormatTime(absl::RFC1123_full, t, tz)); + EXPECT_EQ("28 Jun 0077 09:08:07 +0000", + absl::FormatTime(absl::RFC1123_no_wday, t, tz)); +} + +TEST(FormatTime, InfiniteTime) { + absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); + + // The format and timezone are ignored. + EXPECT_EQ("infinite-future", + absl::FormatTime("%H:%M blah", absl::InfiniteFuture(), tz)); + EXPECT_EQ("infinite-past", + absl::FormatTime("%H:%M blah", absl::InfinitePast(), tz)); +} + +// +// Testing ParseTime() +// + +TEST(ParseTime, Basics) { + absl::Time t = absl::FromTimeT(1234567890); + std::string err; + + // Simple edge cases. + EXPECT_TRUE(absl::ParseTime("", "", &t, &err)) << err; + EXPECT_EQ(absl::UnixEpoch(), t); // everything defaulted + EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err; + EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err; + EXPECT_TRUE(absl::ParseTime("x", "x", &t, &err)) << err; + EXPECT_TRUE(absl::ParseTime("xxx", "xxx", &t, &err)) << err; + + EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", + "2013-06-28 19:08:09 -0800", &t, &err)) + << err; + const auto ci = absl::FixedTimeZone(-8 * 60 * 60).At(t); + EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); +} + +TEST(ParseTime, NullErrorString) { + absl::Time t; + EXPECT_FALSE(absl::ParseTime("%Q", "invalid format", &t, nullptr)); + EXPECT_FALSE(absl::ParseTime("%H", "12 trailing data", &t, nullptr)); + EXPECT_FALSE( + absl::ParseTime("%H out of range", "42 out of range", &t, nullptr)); +} + +TEST(ParseTime, WithTimeZone) { + const absl::TimeZone tz = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + absl::Time t; + std::string e; + + // We can parse a string without a UTC offset if we supply a timezone. + EXPECT_TRUE( + absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e)) + << e; + auto ci = tz.At(t); + EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); + + // But the timezone is ignored when a UTC offset is present. + EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", + "2013-06-28 19:08:09 +0800", tz, &t, &e)) + << e; + ci = absl::FixedTimeZone(8 * 60 * 60).At(t); + EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); +} + +TEST(ParseTime, ErrorCases) { + absl::Time t = absl::FromTimeT(0); + std::string err; + + EXPECT_FALSE(absl::ParseTime("%S", "123", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); + + // Can't parse an illegal format specifier. + err.clear(); + EXPECT_FALSE(absl::ParseTime("%Q", "x", &t, &err)) << err; + // Exact contents of "err" are platform-dependent because of + // differences in the strptime implementation between macOS and Linux. + EXPECT_FALSE(err.empty()); + + // Fails because of trailing, unparsed data "blah". + EXPECT_FALSE(absl::ParseTime("%m-%d", "2-3 blah", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); + + // Feb 31 requires normalization. + EXPECT_FALSE(absl::ParseTime("%m-%d", "2-31", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Out-of-range")); + + // Check that we cannot have spaces in UTC offsets. + EXPECT_TRUE(absl::ParseTime("%z", "-0203", &t, &err)) << err; + EXPECT_FALSE(absl::ParseTime("%z", "- 2 3", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_TRUE(absl::ParseTime("%Ez", "-02:03", &t, &err)) << err; + EXPECT_FALSE(absl::ParseTime("%Ez", "- 2: 3", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + + // Check that we reject other malformed UTC offsets. + EXPECT_FALSE(absl::ParseTime("%Ez", "+-08:00", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%Ez", "-+08:00", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + + // Check that we do not accept "-0" in fields that allow zero. + EXPECT_FALSE(absl::ParseTime("%Y", "-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%E4Y", "-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%H", "-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%M", "-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%S", "-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%z", "+-000", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%Ez", "+-0:00", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + EXPECT_FALSE(absl::ParseTime("%z", "-00-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); + EXPECT_FALSE(absl::ParseTime("%Ez", "-00:-0", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); +} + +TEST(ParseTime, ExtendedSeconds) { + std::string err; + absl::Time t; + + // Here is a "%E*S" case we got wrong for a while. The fractional + // part of the first instant is less than 2^31 and was correctly + // parsed, while the second (and any subsecond field >=2^31) failed. + t = absl::UnixEpoch(); + EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483647", &t, &err)) << err; + EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + + absl::Nanoseconds(1) / 2, + t); + t = absl::UnixEpoch(); + EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483648", &t, &err)) << err; + EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + + absl::Nanoseconds(3) / 4, + t); + + // We should also be able to specify long strings of digits far + // beyond the current resolution and have them convert the same way. + t = absl::UnixEpoch(); + EXPECT_TRUE(absl::ParseTime( + "%E*S", "0.214748364801234567890123456789012345678901234567890123456789", + &t, &err)) + << err; + EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + + absl::Nanoseconds(3) / 4, + t); +} + +TEST(ParseTime, ExtendedOffsetErrors) { + std::string err; + absl::Time t; + + // %z against +-HHMM. + EXPECT_FALSE(absl::ParseTime("%z", "-123", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); + + // %z against +-HH. + EXPECT_FALSE(absl::ParseTime("%z", "-1", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); + + // %Ez against +-HH:MM. + EXPECT_FALSE(absl::ParseTime("%Ez", "-12:3", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); + + // %Ez against +-HHMM. + EXPECT_FALSE(absl::ParseTime("%Ez", "-123", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Illegal trailing data")); + + // %Ez against +-HH. + EXPECT_FALSE(absl::ParseTime("%Ez", "-1", &t, &err)) << err; + EXPECT_THAT(err, HasSubstr("Failed to parse")); +} + +TEST(ParseTime, InfiniteTime) { + absl::Time t; + std::string err; + EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future", &t, &err)); + EXPECT_EQ(absl::InfiniteFuture(), t); + + // Surrounding whitespace. + EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future", &t, &err)); + EXPECT_EQ(absl::InfiniteFuture(), t); + EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future ", &t, &err)); + EXPECT_EQ(absl::InfiniteFuture(), t); + EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future ", &t, &err)); + EXPECT_EQ(absl::InfiniteFuture(), t); + + EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past", &t, &err)); + EXPECT_EQ(absl::InfinitePast(), t); + + // Surrounding whitespace. + EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past", &t, &err)); + EXPECT_EQ(absl::InfinitePast(), t); + EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past ", &t, &err)); + EXPECT_EQ(absl::InfinitePast(), t); + EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past ", &t, &err)); + EXPECT_EQ(absl::InfinitePast(), t); + + // "infinite-future" as literal string + absl::TimeZone tz = absl::UTCTimeZone(); + EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04", + &t, &err)); + EXPECT_NE(absl::InfiniteFuture(), t); + EXPECT_EQ(3, tz.At(t).cs.hour()); + EXPECT_EQ(4, tz.At(t).cs.minute()); + + // "infinite-past" as literal string + EXPECT_TRUE( + absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err)); + EXPECT_NE(absl::InfinitePast(), t); + EXPECT_EQ(3, tz.At(t).cs.hour()); + EXPECT_EQ(4, tz.At(t).cs.minute()); + + // The input doesn't match the format. + EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err)); + EXPECT_FALSE(absl::ParseTime("infinite-past %H:%M", "03:04", &t, &err)); +} + +TEST(ParseTime, FailsOnUnrepresentableTime) { + const absl::TimeZone utc = absl::UTCTimeZone(); + absl::Time t; + EXPECT_FALSE( + absl::ParseTime("%Y-%m-%d", "-292277022657-01-27", utc, &t, nullptr)); + EXPECT_TRUE( + absl::ParseTime("%Y-%m-%d", "-292277022657-01-28", utc, &t, nullptr)); + EXPECT_TRUE( + absl::ParseTime("%Y-%m-%d", "292277026596-12-04", utc, &t, nullptr)); + EXPECT_FALSE( + absl::ParseTime("%Y-%m-%d", "292277026596-12-05", utc, &t, nullptr)); +} + +// +// Roundtrip test for FormatTime()/ParseTime(). +// + +TEST(FormatParse, RoundTrip) { + const absl::TimeZone lax = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + const absl::Time in = + absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax); + const absl::Duration subseconds = absl::Nanoseconds(654321); + std::string err; + + // RFC3339, which renders subseconds. + { + absl::Time out; + const std::string s = + absl::FormatTime(absl::RFC3339_full, in + subseconds, lax); + EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) + << s << ": " << err; + EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez + } + + // RFC1123, which only does whole seconds. + { + absl::Time out; + const std::string s = absl::FormatTime(absl::RFC1123_full, in, lax); + EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err)) + << s << ": " << err; + EXPECT_EQ(in, out); // RFC1123_full includes %z + } + + // `absl::FormatTime()` falls back to strftime() for "%c", which appears to + // work. On Windows, `absl::ParseTime()` falls back to std::get_time() which + // appears to fail on "%c" (or at least on the "%c" text produced by + // `strftime()`). This makes it fail the round-trip test. + // + // Under the emscripten compiler `absl::ParseTime() falls back to + // `strptime()`, but that ends up using a different definition for "%c" + // compared to `strftime()`, also causing the round-trip test to fail + // (see https://github.com/kripken/emscripten/pull/7491). +#if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) + // Even though we don't know what %c will produce, it should roundtrip, + // but only in the 0-offset timezone. + { + absl::Time out; + const std::string s = absl::FormatTime("%c", in, absl::UTCTimeZone()); + EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err; + EXPECT_EQ(in, out); + } +#endif // !_MSC_VER && !__EMSCRIPTEN__ +} + +TEST(FormatParse, RoundTripDistantFuture) { + const absl::TimeZone tz = absl::UTCTimeZone(); + const absl::Time in = + absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()); + std::string err; + + absl::Time out; + const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz); + EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) + << s << ": " << err; + EXPECT_EQ(in, out); +} + +TEST(FormatParse, RoundTripDistantPast) { + const absl::TimeZone tz = absl::UTCTimeZone(); + const absl::Time in = + absl::FromUnixSeconds(std::numeric_limits<int64_t>::min()); + std::string err; + + absl::Time out; + const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz); + EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) + << s << ": " << err; + EXPECT_EQ(in, out); +} + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/BUILD.bazel b/third_party/abseil_cpp/absl/time/internal/cctz/BUILD.bazel new file mode 100644 index 000000000000..45a952924d98 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/BUILD.bazel @@ -0,0 +1,171 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") + +package(features = ["-parse_headers"]) + +licenses(["notice"]) + +filegroup( + name = "zoneinfo", + srcs = glob(["testdata/zoneinfo/**"]), +) + +config_setting( + name = "osx", + constraint_values = [ + "@bazel_tools//platforms:osx", + ], +) + +config_setting( + name = "ios", + constraint_values = [ + "@bazel_tools//platforms:ios", + ], +) + +### libraries + +cc_library( + name = "civil_time", + srcs = ["src/civil_time_detail.cc"], + hdrs = [ + "include/cctz/civil_time.h", + ], + textual_hdrs = ["include/cctz/civil_time_detail.h"], + visibility = ["//visibility:public"], + deps = ["//absl/base:config"], +) + +cc_library( + name = "time_zone", + srcs = [ + "src/time_zone_fixed.cc", + "src/time_zone_fixed.h", + "src/time_zone_format.cc", + "src/time_zone_if.cc", + "src/time_zone_if.h", + "src/time_zone_impl.cc", + "src/time_zone_impl.h", + "src/time_zone_info.cc", + "src/time_zone_info.h", + "src/time_zone_libc.cc", + "src/time_zone_libc.h", + "src/time_zone_lookup.cc", + "src/time_zone_posix.cc", + "src/time_zone_posix.h", + "src/tzfile.h", + "src/zone_info_source.cc", + ], + hdrs = [ + "include/cctz/time_zone.h", + "include/cctz/zone_info_source.h", + ], + linkopts = select({ + ":osx": [ + "-framework Foundation", + ], + ":ios": [ + "-framework Foundation", + ], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + ":civil_time", + "//absl/base:config", + ], +) + +### tests + +test_suite( + name = "all_tests", + visibility = ["//visibility:public"], +) + +cc_test( + name = "civil_time_test", + size = "small", + srcs = ["src/civil_time_test.cc"], + deps = [ + ":civil_time", + "//absl/base:config", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "time_zone_format_test", + size = "small", + srcs = ["src/time_zone_format_test.cc"], + data = [":zoneinfo"], + tags = [ + "no_test_android_arm", + "no_test_android_arm64", + "no_test_android_x86", + ], + deps = [ + ":civil_time", + ":time_zone", + "//absl/base:config", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "time_zone_lookup_test", + size = "small", + timeout = "moderate", + srcs = ["src/time_zone_lookup_test.cc"], + data = [":zoneinfo"], + tags = [ + "no_test_android_arm", + "no_test_android_arm64", + "no_test_android_x86", + ], + deps = [ + ":civil_time", + ":time_zone", + "//absl/base:config", + "@com_google_googletest//:gtest_main", + ], +) + +### benchmarks + +cc_test( + name = "cctz_benchmark", + srcs = [ + "src/cctz_benchmark.cc", + "src/time_zone_if.h", + "src/time_zone_impl.h", + "src/time_zone_info.h", + "src/tzfile.h", + ], + linkstatic = 1, + tags = ["benchmark"], + deps = [ + ":civil_time", + ":time_zone", + "//absl/base:config", + "@com_github_google_benchmark//:benchmark_main", + ], +) + +### examples + +### binaries diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/civil_time.h b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/civil_time.h new file mode 100644 index 000000000000..d47ff86fe43e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/civil_time.h @@ -0,0 +1,332 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ +#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// The term "civil time" refers to the legally recognized human-scale time +// that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil +// time follows the Gregorian Calendar and is a time-zone-independent concept. +// A "date" is perhaps the most common example of a civil time (represented in +// this library as cctz::civil_day). This library provides six classes and a +// handful of functions that help with rounding, iterating, and arithmetic on +// civil times while avoiding complications like daylight-saving time (DST). +// +// The following six classes form the core of this civil-time library: +// +// * civil_second +// * civil_minute +// * civil_hour +// * civil_day +// * civil_month +// * civil_year +// +// Each class is a simple value type with the same interface for construction +// and the same six accessors for each of the civil fields (year, month, day, +// hour, minute, and second, aka YMDHMS). These classes differ only in their +// alignment, which is indicated by the type name and specifies the field on +// which arithmetic operates. +// +// Each class can be constructed by passing up to six optional integer +// arguments representing the YMDHMS fields (in that order) to the +// constructor. Omitted fields are assigned their minimum valid value. Hours, +// minutes, and seconds will be set to 0, month and day will be set to 1, and +// since there is no minimum valid year, it will be set to 1970. So, a +// default-constructed civil-time object will have YMDHMS fields representing +// "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g., +// October 32 -> November 1) so that all civil-time objects represent valid +// values. +// +// Each civil-time class is aligned to the civil-time field indicated in the +// class's name after normalization. Alignment is performed by setting all the +// inferior fields to their minimum valid value (as described above). The +// following are examples of how each of the six types would align the fields +// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the +// string format used here is not important; it's just a shorthand way of +// showing the six YMDHMS fields.) +// +// civil_second 2015-11-22 12:34:56 +// civil_minute 2015-11-22 12:34:00 +// civil_hour 2015-11-22 12:00:00 +// civil_day 2015-11-22 00:00:00 +// civil_month 2015-11-01 00:00:00 +// civil_year 2015-01-01 00:00:00 +// +// Each civil-time type performs arithmetic on the field to which it is +// aligned. This means that adding 1 to a civil_day increments the day field +// (normalizing as necessary), and subtracting 7 from a civil_month operates +// on the month field (normalizing as necessary). All arithmetic produces a +// valid civil time. Difference requires two similarly aligned civil-time +// objects and returns the scalar answer in units of the objects' alignment. +// For example, the difference between two civil_hour objects will give an +// answer in units of civil hours. +// +// In addition to the six civil-time types just described, there are +// a handful of helper functions and algorithms for performing common +// calculations. These are described below. +// +// Note: In C++14 and later, this library is usable in a constexpr context. +// +// CONSTRUCTION: +// +// Each of the civil-time types can be constructed in two ways: by directly +// passing to the constructor up to six (optional) integers representing the +// YMDHMS fields, or by copying the YMDHMS fields from a differently aligned +// civil-time type. +// +// civil_day default_value; // 1970-01-01 00:00:00 +// +// civil_day a(2015, 2, 3); // 2015-02-03 00:00:00 +// civil_day b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00 +// civil_day c(2015); // 2015-01-01 00:00:00 +// +// civil_second ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06 +// civil_minute mm(ss); // 2015-02-03 04:05:00 +// civil_hour hh(mm); // 2015-02-03 04:00:00 +// civil_day d(hh); // 2015-02-03 00:00:00 +// civil_month m(d); // 2015-02-01 00:00:00 +// civil_year y(m); // 2015-01-01 00:00:00 +// +// m = civil_month(y); // 2015-01-01 00:00:00 +// d = civil_day(m); // 2015-01-01 00:00:00 +// hh = civil_hour(d); // 2015-01-01 00:00:00 +// mm = civil_minute(hh); // 2015-01-01 00:00:00 +// ss = civil_second(mm); // 2015-01-01 00:00:00 +// +// ALIGNMENT CONVERSION: +// +// The alignment of a civil-time object cannot change, but the object may be +// used to construct a new object with a different alignment. This is referred +// to as "realigning". When realigning to a type with the same or more +// precision (e.g., civil_day -> civil_second), the conversion may be +// performed implicitly since no information is lost. However, if information +// could be discarded (e.g., civil_second -> civil_day), the conversion must +// be explicit at the call site. +// +// void fun(const civil_day& day); +// +// civil_second cs; +// fun(cs); // Won't compile because data may be discarded +// fun(civil_day(cs)); // OK: explicit conversion +// +// civil_day cd; +// fun(cd); // OK: no conversion needed +// +// civil_month cm; +// fun(cm); // OK: implicit conversion to civil_day +// +// NORMALIZATION: +// +// Integer arguments passed to the constructor may be out-of-range, in which +// case they are normalized to produce a valid civil-time object. This enables +// natural arithmetic on constructor arguments without worrying about the +// field's range. Normalization guarantees that there are no invalid +// civil-time objects. +// +// civil_day d(2016, 10, 32); // Out-of-range day; normalized to 2016-11-01 +// +// Note: If normalization is undesired, you can signal an error by comparing +// the constructor arguments to the normalized values returned by the YMDHMS +// properties. +// +// PROPERTIES: +// +// All civil-time types have accessors for all six of the civil-time fields: +// year, month, day, hour, minute, and second. Recall that fields inferior to +// the type's alignment will be set to their minimum valid value. +// +// civil_day d(2015, 6, 28); +// // d.year() == 2015 +// // d.month() == 6 +// // d.day() == 28 +// // d.hour() == 0 +// // d.minute() == 0 +// // d.second() == 0 +// +// COMPARISON: +// +// Comparison always considers all six YMDHMS fields, regardless of the type's +// alignment. Comparison between differently aligned civil-time types is +// allowed. +// +// civil_day feb_3(2015, 2, 3); // 2015-02-03 00:00:00 +// civil_day mar_4(2015, 3, 4); // 2015-03-04 00:00:00 +// // feb_3 < mar_4 +// // civil_year(feb_3) == civil_year(mar_4) +// +// civil_second feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00 +// // feb_3 < feb_3_noon +// // feb_3 == civil_day(feb_3_noon) +// +// // Iterates all the days of February 2015. +// for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) { +// // ... +// } +// +// STREAMING: +// +// Each civil-time type may be sent to an output stream using operator<<(). +// The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields +// inferior to the type's alignment are omitted. +// +// civil_second cs(2015, 2, 3, 4, 5, 6); +// std::cout << cs << "\n"; // Outputs: 2015-02-03T04:05:06 +// +// civil_day cd(cs); +// std::cout << cd << "\n"; // Outputs: 2015-02-03 +// +// civil_year cy(cs); +// std::cout << cy << "\n"; // Outputs: 2015 +// +// ARITHMETIC: +// +// Civil-time types support natural arithmetic operators such as addition, +// subtraction, and difference. Arithmetic operates on the civil-time field +// indicated in the type's name. Difference requires arguments with the same +// alignment and returns the answer in units of the alignment. +// +// civil_day a(2015, 2, 3); +// ++a; // 2015-02-04 00:00:00 +// --a; // 2015-02-03 00:00:00 +// civil_day b = a + 1; // 2015-02-04 00:00:00 +// civil_day c = 1 + b; // 2015-02-05 00:00:00 +// int n = c - a; // n = 2 (civil days) +// int m = c - civil_month(c); // Won't compile: different types. +// +// EXAMPLE: Adding a month to January 31. +// +// One of the classic questions that arises when considering a civil-time +// library (or a date library or a date/time library) is this: "What happens +// when you add a month to January 31?" This is an interesting question +// because there could be a number of possible answers: +// +// 1. March 3 (or 2 if a leap year). This may make sense if the operation +// wants the equivalent of February 31. +// 2. February 28 (or 29 if a leap year). This may make sense if the operation +// wants the last day of January to go to the last day of February. +// 3. Error. The caller may get some error, an exception, an invalid date +// object, or maybe false is returned. This may make sense because there is +// no single unambiguously correct answer to the question. +// +// Practically speaking, any answer that is not what the programmer intended +// is the wrong answer. +// +// This civil-time library avoids the problem by making it impossible to ask +// ambiguous questions. All civil-time objects are aligned to a particular +// civil-field boundary (such as aligned to a year, month, day, hour, minute, +// or second), and arithmetic operates on the field to which the object is +// aligned. This means that in order to "add a month" the object must first be +// aligned to a month boundary, which is equivalent to the first day of that +// month. +// +// Of course, there are ways to compute an answer the question at hand using +// this civil-time library, but they require the programmer to be explicit +// about the answer they expect. To illustrate, let's see how to compute all +// three of the above possible answers to the question of "Jan 31 plus 1 +// month": +// +// const civil_day d(2015, 1, 31); +// +// // Answer 1: +// // Add 1 to the month field in the constructor, and rely on normalization. +// const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day()); +// // ans_normalized == 2015-03-03 (aka Feb 31) +// +// // Answer 2: +// // Add 1 to month field, capping to the end of next month. +// const auto next_month = civil_month(d) + 1; +// const auto last_day_of_next_month = civil_day(next_month + 1) - 1; +// const auto ans_capped = std::min(ans_normalized, last_day_of_next_month); +// // ans_capped == 2015-02-28 +// +// // Answer 3: +// // Signal an error if the normalized answer is not in next month. +// if (civil_month(ans_normalized) != next_month) { +// // error, month overflow +// } +// +using civil_year = detail::civil_year; +using civil_month = detail::civil_month; +using civil_day = detail::civil_day; +using civil_hour = detail::civil_hour; +using civil_minute = detail::civil_minute; +using civil_second = detail::civil_second; + +// An enum class with members monday, tuesday, wednesday, thursday, friday, +// saturday, and sunday. These enum values may be sent to an output stream +// using operator<<(). The result is the full weekday name in English with a +// leading capital letter. +// +// weekday wd = weekday::thursday; +// std::cout << wd << "\n"; // Outputs: Thursday +// +using detail::weekday; + +// Returns the weekday for the given civil-time value. +// +// civil_day a(2015, 8, 13); +// weekday wd = get_weekday(a); // wd == weekday::thursday +// +using detail::get_weekday; + +// Returns the civil_day that strictly follows or precedes the given +// civil_day, and that falls on the given weekday. +// +// For example, given: +// +// August 2015 +// Su Mo Tu We Th Fr Sa +// 1 +// 2 3 4 5 6 7 8 +// 9 10 11 12 13 14 15 +// 16 17 18 19 20 21 22 +// 23 24 25 26 27 28 29 +// 30 31 +// +// civil_day a(2015, 8, 13); // get_weekday(a) == weekday::thursday +// civil_day b = next_weekday(a, weekday::thursday); // b = 2015-08-20 +// civil_day c = prev_weekday(a, weekday::thursday); // c = 2015-08-06 +// +// civil_day d = ... +// // Gets the following Thursday if d is not already Thursday +// civil_day thurs1 = next_weekday(d - 1, weekday::thursday); +// // Gets the previous Thursday if d is not already Thursday +// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday); +// +using detail::next_weekday; +using detail::prev_weekday; + +// Returns the day-of-year for the given civil-time value. +// +// civil_day a(2015, 1, 1); +// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1 +// civil_day b(2015, 12, 31); +// int yd_dec_31 = get_yearday(b); // yd_dec_31 = 365 +// +using detail::get_yearday; + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h new file mode 100644 index 000000000000..8aadde57ca72 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/civil_time_detail.h @@ -0,0 +1,628 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ +#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ + +#include <cstdint> +#include <limits> +#include <ostream> +#include <type_traits> + +#include "absl/base/config.h" + +// Disable constexpr support unless we are in C++14 mode. +#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) +#define CONSTEXPR_D constexpr // data +#define CONSTEXPR_F constexpr // function +#define CONSTEXPR_M constexpr // member +#else +#define CONSTEXPR_D const +#define CONSTEXPR_F inline +#define CONSTEXPR_M +#endif + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// Support years that at least span the range of 64-bit time_t values. +using year_t = std::int_fast64_t; + +// Type alias that indicates an argument is not normalized (e.g., the +// constructor parameters and operands/results of addition/subtraction). +using diff_t = std::int_fast64_t; + +namespace detail { + +// Type aliases that indicate normalized argument values. +using month_t = std::int_fast8_t; // [1:12] +using day_t = std::int_fast8_t; // [1:31] +using hour_t = std::int_fast8_t; // [0:23] +using minute_t = std::int_fast8_t; // [0:59] +using second_t = std::int_fast8_t; // [0:59] + +// Normalized civil-time fields: Y-M-D HH:MM:SS. +struct fields { + CONSTEXPR_M fields(year_t year, month_t month, day_t day, hour_t hour, + minute_t minute, second_t second) + : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {} + std::int_least64_t y; + std::int_least8_t m; + std::int_least8_t d; + std::int_least8_t hh; + std::int_least8_t mm; + std::int_least8_t ss; +}; + +struct second_tag {}; +struct minute_tag : second_tag {}; +struct hour_tag : minute_tag {}; +struct day_tag : hour_tag {}; +struct month_tag : day_tag {}; +struct year_tag : month_tag {}; + +//////////////////////////////////////////////////////////////////////// + +// Field normalization (without avoidable overflow). + +namespace impl { + +CONSTEXPR_F bool is_leap_year(year_t y) noexcept { + return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); +} +CONSTEXPR_F int year_index(year_t y, month_t m) noexcept { + return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400; +} +CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept { + const int yi = year_index(y, m); + return 36524 + (yi == 0 || yi > 300); +} +CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept { + const int yi = year_index(y, m); + return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96); +} +CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept { + return is_leap_year(y + (m > 2)) ? 366 : 365; +} +CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept { + CONSTEXPR_D int k_days_per_month[1 + 12] = { + -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // non leap year + }; + return k_days_per_month[m] + (m == 2 && is_leap_year(y)); +} + +CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh, + minute_t mm, second_t ss) noexcept { + year_t ey = y % 400; + const year_t oey = ey; + ey += (cd / 146097) * 400; + cd %= 146097; + if (cd < 0) { + ey -= 400; + cd += 146097; + } + ey += (d / 146097) * 400; + d = d % 146097 + cd; + if (d > 0) { + if (d > 146097) { + ey += 400; + d -= 146097; + } + } else { + if (d > -365) { + // We often hit the previous year when stepping a civil time backwards, + // so special case it to avoid counting up by 100/4/1-year chunks. + ey -= 1; + d += days_per_year(ey, m); + } else { + ey -= 400; + d += 146097; + } + } + if (d > 365) { + for (;;) { + int n = days_per_century(ey, m); + if (d <= n) break; + d -= n; + ey += 100; + } + for (;;) { + int n = days_per_4years(ey, m); + if (d <= n) break; + d -= n; + ey += 4; + } + for (;;) { + int n = days_per_year(ey, m); + if (d <= n) break; + d -= n; + ++ey; + } + } + if (d > 28) { + for (;;) { + int n = days_per_month(ey, m); + if (d <= n) break; + d -= n; + if (++m > 12) { + ++ey; + m = 1; + } + } + } + return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss); +} +CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh, + minute_t mm, second_t ss) noexcept { + if (m != 12) { + y += m / 12; + m %= 12; + if (m <= 0) { + y -= 1; + m += 12; + } + } + return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss); +} +CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, diff_t hh, + minute_t mm, second_t ss) noexcept { + cd += hh / 24; + hh %= 24; + if (hh < 0) { + cd -= 1; + hh += 24; + } + return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss); +} +CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch, + diff_t mm, second_t ss) noexcept { + ch += mm / 60; + mm %= 60; + if (mm < 0) { + ch -= 1; + mm += 60; + } + return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24, + static_cast<minute_t>(mm), ss); +} +CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm, + diff_t ss) noexcept { + // Optimization for when (non-constexpr) fields are already normalized. + if (0 <= ss && ss < 60) { + const second_t nss = static_cast<second_t>(ss); + if (0 <= mm && mm < 60) { + const minute_t nmm = static_cast<minute_t>(mm); + if (0 <= hh && hh < 24) { + const hour_t nhh = static_cast<hour_t>(hh); + if (1 <= d && d <= 28 && 1 <= m && m <= 12) { + const day_t nd = static_cast<day_t>(d); + const month_t nm = static_cast<month_t>(m); + return fields(y, nm, nd, nhh, nmm, nss); + } + return n_mon(y, m, d, 0, nhh, nmm, nss); + } + return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss); + } + return n_min(y, m, d, hh, mm / 60, mm % 60, nss); + } + diff_t cm = ss / 60; + ss %= 60; + if (ss < 0) { + cm -= 1; + ss += 60; + } + return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60, + static_cast<second_t>(ss)); +} + +} // namespace impl + +//////////////////////////////////////////////////////////////////////// + +// Increments the indicated (normalized) field by "n". +CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept { + return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60); +} +CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept { + return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss); +} +CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept { + return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss); +} +CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept { + return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss); +} +CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept { + return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss); +} +CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept { + return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss); +} + +//////////////////////////////////////////////////////////////////////// + +namespace impl { + +// Returns (v * f + a) but avoiding intermediate overflow when possible. +CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept { + return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f; +} + +// Map a (normalized) Y/M/D to the number of days before/after 1970-01-01. +// Probably overflows for years outside [-292277022656:292277026595]. +CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept { + const diff_t eyear = (m <= 2) ? y - 1 : y; + const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400; + const diff_t yoe = eyear - era * 400; + const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; + const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; + return era * 146097 + doe - 719468; +} + +// Returns the difference in days between two normalized Y-M-D tuples. +// ymd_ord() will encounter integer overflow given extreme year values, +// yet the difference between two such extreme values may actually be +// small, so we take a little care to avoid overflow when possible by +// exploiting the 146097-day cycle. +CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, year_t y2, + month_t m2, day_t d2) noexcept { + const diff_t a_c4_off = y1 % 400; + const diff_t b_c4_off = y2 % 400; + diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off); + diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2); + if (c4_diff > 0 && delta < 0) { + delta += 2 * 146097; + c4_diff -= 2 * 400; + } else if (c4_diff < 0 && delta > 0) { + delta -= 2 * 146097; + c4_diff += 2 * 400; + } + return (c4_diff / 400 * 146097) + delta; +} + +} // namespace impl + +// Returns the difference between fields structs using the indicated unit. +CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept { + return f1.y - f2.y; +} +CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept { + return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m)); +} +CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept { + return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d); +} +CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept { + return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh)); +} +CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept { + return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm)); +} +CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept { + return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss); +} + +//////////////////////////////////////////////////////////////////////// + +// Aligns the (normalized) fields struct to the indicated field. +CONSTEXPR_F fields align(second_tag, fields f) noexcept { return f; } +CONSTEXPR_F fields align(minute_tag, fields f) noexcept { + return fields{f.y, f.m, f.d, f.hh, f.mm, 0}; +} +CONSTEXPR_F fields align(hour_tag, fields f) noexcept { + return fields{f.y, f.m, f.d, f.hh, 0, 0}; +} +CONSTEXPR_F fields align(day_tag, fields f) noexcept { + return fields{f.y, f.m, f.d, 0, 0, 0}; +} +CONSTEXPR_F fields align(month_tag, fields f) noexcept { + return fields{f.y, f.m, 1, 0, 0, 0}; +} +CONSTEXPR_F fields align(year_tag, fields f) noexcept { + return fields{f.y, 1, 1, 0, 0, 0}; +} + +//////////////////////////////////////////////////////////////////////// + +namespace impl { + +template <typename H> +H AbslHashValueImpl(second_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss); +} +template <typename H> +H AbslHashValueImpl(minute_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm); +} +template <typename H> +H AbslHashValueImpl(hour_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d, f.hh); +} +template <typename H> +H AbslHashValueImpl(day_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m, f.d); +} +template <typename H> +H AbslHashValueImpl(month_tag, H h, fields f) { + return H::combine(std::move(h), f.y, f.m); +} +template <typename H> +H AbslHashValueImpl(year_tag, H h, fields f) { + return H::combine(std::move(h), f.y); +} + +} // namespace impl + +//////////////////////////////////////////////////////////////////////// + +template <typename T> +class civil_time { + public: + explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1, + diff_t hh = 0, diff_t mm = 0, + diff_t ss = 0) noexcept + : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {} + + CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {} + civil_time(const civil_time&) = default; + civil_time& operator=(const civil_time&) = default; + + // Conversion between civil times of different alignment. Conversion to + // a more precise alignment is allowed implicitly (e.g., day -> hour), + // but conversion where information is discarded must be explicit + // (e.g., second -> minute). + template <typename U, typename S> + using preserves_data = + typename std::enable_if<std::is_base_of<U, S>::value>::type; + template <typename U> + CONSTEXPR_M civil_time(const civil_time<U>& ct, + preserves_data<T, U>* = nullptr) noexcept + : civil_time(ct.f_) {} + template <typename U> + explicit CONSTEXPR_M civil_time(const civil_time<U>& ct, + preserves_data<U, T>* = nullptr) noexcept + : civil_time(ct.f_) {} + + // Factories for the maximum/minimum representable civil_time. + static CONSTEXPR_F civil_time(max)() { + const auto max_year = (std::numeric_limits<std::int_least64_t>::max)(); + return civil_time(max_year, 12, 31, 23, 59, 59); + } + static CONSTEXPR_F civil_time(min)() { + const auto min_year = (std::numeric_limits<std::int_least64_t>::min)(); + return civil_time(min_year, 1, 1, 0, 0, 0); + } + + // Field accessors. Note: All but year() return an int. + CONSTEXPR_M year_t year() const noexcept { return f_.y; } + CONSTEXPR_M int month() const noexcept { return f_.m; } + CONSTEXPR_M int day() const noexcept { return f_.d; } + CONSTEXPR_M int hour() const noexcept { return f_.hh; } + CONSTEXPR_M int minute() const noexcept { return f_.mm; } + CONSTEXPR_M int second() const noexcept { return f_.ss; } + + // Assigning arithmetic. + CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept { + return *this = *this + n; + } + CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept { + return *this = *this - n; + } + CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; } + CONSTEXPR_M civil_time operator++(int) noexcept { + const civil_time a = *this; + ++*this; + return a; + } + CONSTEXPR_M civil_time& operator--() noexcept { return *this -= 1; } + CONSTEXPR_M civil_time operator--(int) noexcept { + const civil_time a = *this; + --*this; + return a; + } + + // Binary arithmetic operators. + friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept { + return civil_time(step(T{}, a.f_, n)); + } + friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept { + return a + n; + } + friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept { + 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_); + } + + template <typename H> + friend H AbslHashValue(H h, civil_time a) { + return impl::AbslHashValueImpl(T{}, std::move(h), a.f_); + } + + private: + // All instantiations of this template are allowed to call the following + // private constructor and access the private fields member. + template <typename U> + friend class civil_time; + + // The designated constructor that all others eventually call. + explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {} + + fields f_; +}; + +// Disallows difference between differently aligned types. +// auto n = civil_day(...) - civil_hour(...); // would be confusing. +template <typename T, typename U> +CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete; + +using civil_year = civil_time<year_tag>; +using civil_month = civil_time<month_tag>; +using civil_day = civil_time<day_tag>; +using civil_hour = civil_time<hour_tag>; +using civil_minute = civil_time<minute_tag>; +using civil_second = civil_time<second_tag>; + +//////////////////////////////////////////////////////////////////////// + +// Relational operators that work with differently aligned objects. +// Always compares all six fields. +template <typename T1, typename T2> +CONSTEXPR_F bool operator<(const civil_time<T1>& lhs, + const civil_time<T2>& rhs) noexcept { + return ( + lhs.year() < rhs.year() || + (lhs.year() == rhs.year() && + (lhs.month() < rhs.month() || + (lhs.month() == rhs.month() && + (lhs.day() < rhs.day() || (lhs.day() == rhs.day() && + (lhs.hour() < rhs.hour() || + (lhs.hour() == rhs.hour() && + (lhs.minute() < rhs.minute() || + (lhs.minute() == rhs.minute() && + (lhs.second() < rhs.second()))))))))))); +} +template <typename T1, typename T2> +CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs, + const civil_time<T2>& rhs) noexcept { + return !(rhs < lhs); +} +template <typename T1, typename T2> +CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs, + const civil_time<T2>& rhs) noexcept { + return !(lhs < rhs); +} +template <typename T1, typename T2> +CONSTEXPR_F bool operator>(const civil_time<T1>& lhs, + const civil_time<T2>& rhs) noexcept { + return rhs < lhs; +} +template <typename T1, typename T2> +CONSTEXPR_F bool operator==(const civil_time<T1>& lhs, + const civil_time<T2>& rhs) noexcept { + return lhs.year() == rhs.year() && lhs.month() == rhs.month() && + lhs.day() == rhs.day() && lhs.hour() == rhs.hour() && + lhs.minute() == rhs.minute() && lhs.second() == rhs.second(); +} +template <typename T1, typename T2> +CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs, + const civil_time<T2>& rhs) noexcept { + return !(lhs == rhs); +} + +//////////////////////////////////////////////////////////////////////// + +enum class weekday { + monday, + tuesday, + wednesday, + thursday, + friday, + saturday, + sunday, +}; + +CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept { + CONSTEXPR_D weekday k_weekday_by_mon_off[13] = { + weekday::monday, weekday::tuesday, weekday::wednesday, + weekday::thursday, weekday::friday, weekday::saturday, + weekday::sunday, weekday::monday, weekday::tuesday, + weekday::wednesday, weekday::thursday, weekday::friday, + weekday::saturday, + }; + CONSTEXPR_D int k_weekday_offsets[1 + 12] = { + -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4, + }; + year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3); + wd += wd / 4 - wd / 100 + wd / 400; + wd += k_weekday_offsets[cs.month()] + cs.day(); + return k_weekday_by_mon_off[wd % 7 + 6]; +} + +//////////////////////////////////////////////////////////////////////// + +CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept { + CONSTEXPR_D weekday k_weekdays_forw[14] = { + weekday::monday, weekday::tuesday, weekday::wednesday, + weekday::thursday, weekday::friday, weekday::saturday, + weekday::sunday, weekday::monday, weekday::tuesday, + weekday::wednesday, weekday::thursday, weekday::friday, + weekday::saturday, weekday::sunday, + }; + weekday base = get_weekday(cd); + for (int i = 0;; ++i) { + if (base == k_weekdays_forw[i]) { + for (int j = i + 1;; ++j) { + if (wd == k_weekdays_forw[j]) { + return cd + (j - i); + } + } + } + } +} + +CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept { + CONSTEXPR_D weekday k_weekdays_back[14] = { + weekday::sunday, weekday::saturday, weekday::friday, + weekday::thursday, weekday::wednesday, weekday::tuesday, + weekday::monday, weekday::sunday, weekday::saturday, + weekday::friday, weekday::thursday, weekday::wednesday, + weekday::tuesday, weekday::monday, + }; + weekday base = get_weekday(cd); + for (int i = 0;; ++i) { + if (base == k_weekdays_back[i]) { + for (int j = i + 1;; ++j) { + if (wd == k_weekdays_back[j]) { + return cd - (j - i); + } + } + } + } +} + +CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept { + CONSTEXPR_D int k_month_offsets[1 + 12] = { + -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, + }; + const int feb29 = (cs.month() > 2 && impl::is_leap_year(cs.year())); + return k_month_offsets[cs.month()] + feb29 + cs.day(); +} + +//////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& os, const civil_year& y); +std::ostream& operator<<(std::ostream& os, const civil_month& m); +std::ostream& operator<<(std::ostream& os, const civil_day& d); +std::ostream& operator<<(std::ostream& os, const civil_hour& h); +std::ostream& operator<<(std::ostream& os, const civil_minute& m); +std::ostream& operator<<(std::ostream& os, const civil_second& s); +std::ostream& operator<<(std::ostream& os, weekday wd); + +} // namespace detail +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#undef CONSTEXPR_M +#undef CONSTEXPR_F +#undef CONSTEXPR_D + +#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/time_zone.h b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/time_zone.h new file mode 100644 index 000000000000..5562a37bc807 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/time_zone.h @@ -0,0 +1,386 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// A library for translating between absolute times (represented by +// std::chrono::time_points of the std::chrono::system_clock) and civil +// times (represented by cctz::civil_second) using the rules defined by +// a time zone (cctz::time_zone). + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ + +#include <chrono> +#include <cstdint> +#include <string> +#include <utility> + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// Convenience aliases. Not intended as public API points. +template <typename D> +using time_point = std::chrono::time_point<std::chrono::system_clock, D>; +using seconds = std::chrono::duration<std::int_fast64_t>; +using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead. + +namespace detail { +template <typename D> +inline std::pair<time_point<seconds>, D> split_seconds( + const time_point<D>& tp) { + auto sec = std::chrono::time_point_cast<seconds>(tp); + auto sub = tp - sec; + if (sub.count() < 0) { + sec -= seconds(1); + sub += seconds(1); + } + return {sec, std::chrono::duration_cast<D>(sub)}; +} +inline std::pair<time_point<seconds>, seconds> split_seconds( + const time_point<seconds>& tp) { + return {tp, seconds::zero()}; +} +} // namespace detail + +// cctz::time_zone is an opaque, small, value-type class representing a +// geo-political region within which particular rules are used for mapping +// between absolute and civil times. Time zones are named using the TZ +// identifiers from the IANA Time Zone Database, such as "America/Los_Angeles" +// or "Australia/Sydney". Time zones are created from factory functions such +// as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ +// identifiers. +// +// Example: +// cctz::time_zone utc = cctz::utc_time_zone(); +// cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8)); +// cctz::time_zone loc = cctz::local_time_zone(); +// cctz::time_zone lax; +// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } +// +// See also: +// - http://www.iana.org/time-zones +// - https://en.wikipedia.org/wiki/Zoneinfo +class time_zone { + public: + time_zone() : time_zone(nullptr) {} // Equivalent to UTC + time_zone(const time_zone&) = default; + time_zone& operator=(const time_zone&) = default; + + std::string name() const; + + // An absolute_lookup represents the civil time (cctz::civil_second) within + // this time_zone at the given absolute time (time_point). There are + // additionally a few other fields that may be useful when working with + // older APIs, such as std::tm. + // + // Example: + // const cctz::time_zone tz = ... + // const auto tp = std::chrono::system_clock::now(); + // const cctz::time_zone::absolute_lookup al = tz.lookup(tp); + struct absolute_lookup { + civil_second cs; + // Note: The following fields exist for backward compatibility with older + // APIs. Accessing these fields directly is a sign of imprudent logic in + // the calling code. Modern time-related code should only access this data + // indirectly by way of cctz::format(). + int offset; // civil seconds east of UTC + bool is_dst; // is offset non-standard? + const char* abbr; // time-zone abbreviation (e.g., "PST") + }; + absolute_lookup lookup(const time_point<seconds>& tp) const; + template <typename D> + absolute_lookup lookup(const time_point<D>& tp) const { + return lookup(detail::split_seconds(tp).first); + } + + // A civil_lookup represents the absolute time(s) (time_point) that + // correspond to the given civil time (cctz::civil_second) within this + // time_zone. Usually the given civil time represents a unique instant + // in time, in which case the conversion is unambiguous. However, + // within this time zone, the given civil time may be skipped (e.g., + // during a positive UTC offset shift), or repeated (e.g., during a + // negative UTC offset shift). To account for these possibilities, + // civil_lookup is richer than just a single time_point. + // + // In all cases the civil_lookup::kind enum will indicate the nature + // of the given civil-time argument, and the pre, trans, and post + // members will give the absolute time answers using the pre-transition + // offset, the transition point itself, and the post-transition offset, + // respectively (all three times are equal if kind == UNIQUE). If any + // of these three absolute times is outside the representable range of a + // time_point<seconds> the field is set to its maximum/minimum value. + // + // Example: + // cctz::time_zone lax; + // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } + // + // // A unique civil time. + // auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0)); + // // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE + // // jan01.pre is 2011/01/01 00:00:00 -0800 + // // jan01.trans is 2011/01/01 00:00:00 -0800 + // // jan01.post is 2011/01/01 00:00:00 -0800 + // + // // A Spring DST transition, when there is a gap in civil time. + // auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0)); + // // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED + // // mar13.pre is 2011/03/13 03:15:00 -0700 + // // mar13.trans is 2011/03/13 03:00:00 -0700 + // // mar13.post is 2011/03/13 01:15:00 -0800 + // + // // A Fall DST transition, when civil times are repeated. + // auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0)); + // // nov06.kind == cctz::time_zone::civil_lookup::REPEATED + // // nov06.pre is 2011/11/06 01:15:00 -0700 + // // nov06.trans is 2011/11/06 01:00:00 -0800 + // // nov06.post is 2011/11/06 01:15:00 -0800 + struct civil_lookup { + enum civil_kind { + UNIQUE, // the civil time was singular (pre == trans == post) + SKIPPED, // the civil time did not exist (pre >= trans > post) + REPEATED, // the civil time was ambiguous (pre < trans <= post) + } kind; + time_point<seconds> pre; // uses the pre-transition offset + time_point<seconds> trans; // instant of civil-offset change + time_point<seconds> post; // uses the post-transition offset + }; + civil_lookup lookup(const civil_second& cs) const; + + // Finds the time of the next/previous offset change in this time zone. + // + // By definition, next_transition(tp, &trans) returns false when tp has + // its maximum value, and prev_transition(tp, &trans) returns false + // when tp has its minimum value. If the zone has no transitions, the + // result will also be false no matter what the argument. + // + // Otherwise, when tp has its minimum value, next_transition(tp, &trans) + // returns true and sets trans to the first recorded transition. Chains + // of calls to next_transition()/prev_transition() will eventually return + // false, but it is unspecified exactly when next_transition(tp, &trans) + // jumps to false, or what time is set by prev_transition(tp, &trans) for + // a very distant tp. + // + // Note: Enumeration of time-zone transitions is for informational purposes + // only. Modern time-related code should not care about when offset changes + // occur. + // + // Example: + // cctz::time_zone nyc; + // if (!cctz::load_time_zone("America/New_York", &nyc)) { ... } + // const auto now = std::chrono::system_clock::now(); + // auto tp = cctz::time_point<cctz::seconds>::min(); + // cctz::time_zone::civil_transition trans; + // while (tp <= now && nyc.next_transition(tp, &trans)) { + // // transition: trans.from -> trans.to + // tp = nyc.lookup(trans.to).trans; + // } + struct civil_transition { + civil_second from; // the civil time we jump from + civil_second to; // the civil time we jump to + }; + bool next_transition(const time_point<seconds>& tp, + civil_transition* trans) const; + template <typename D> + bool next_transition(const time_point<D>& tp, civil_transition* trans) const { + return next_transition(detail::split_seconds(tp).first, trans); + } + bool prev_transition(const time_point<seconds>& tp, + civil_transition* trans) const; + template <typename D> + bool prev_transition(const time_point<D>& tp, civil_transition* trans) const { + return prev_transition(detail::split_seconds(tp).first, trans); + } + + // version() and description() provide additional information about the + // time zone. The content of each of the returned strings is unspecified, + // however, when the IANA Time Zone Database is the underlying data source + // the version() string will be in the familar form (e.g, "2018e") or + // empty when unavailable. + // + // Note: These functions are for informational or testing purposes only. + std::string version() const; // empty when unknown + std::string description() const; + + // Relational operators. + friend bool operator==(time_zone lhs, time_zone rhs) { + return &lhs.effective_impl() == &rhs.effective_impl(); + } + friend bool operator!=(time_zone lhs, time_zone rhs) { return !(lhs == rhs); } + + template <typename H> + friend H AbslHashValue(H h, time_zone tz) { + return H::combine(std::move(h), &tz.effective_impl()); + } + + class Impl; + + private: + explicit time_zone(const Impl* impl) : impl_(impl) {} + const Impl& effective_impl() const; // handles implicit UTC + const Impl* impl_; +}; + +// Loads the named time zone. May perform I/O on the initial load. +// If the name is invalid, or some other kind of error occurs, returns +// false and "*tz" is set to the UTC time zone. +bool load_time_zone(const std::string& name, time_zone* tz); + +// Returns a time_zone representing UTC. Cannot fail. +time_zone utc_time_zone(); + +// Returns a time zone that is a fixed offset (seconds east) from UTC. +// Note: If the absolute value of the offset is greater than 24 hours +// you'll get UTC (i.e., zero offset) instead. +time_zone fixed_time_zone(const seconds& offset); + +// Returns a time zone representing the local time zone. Falls back to UTC. +// Note: local_time_zone.name() may only be something like "localtime". +time_zone local_time_zone(); + +// Returns the civil time (cctz::civil_second) within the given time zone at +// the given absolute time (time_point). Since the additional fields provided +// by the time_zone::absolute_lookup struct should rarely be needed in modern +// code, this convert() function is simpler and should be preferred. +template <typename D> +inline civil_second convert(const time_point<D>& tp, const time_zone& tz) { + return tz.lookup(tp).cs; +} + +// Returns the absolute time (time_point) that corresponds to the given civil +// time within the given time zone. If the civil time is not unique (i.e., if +// it was either repeated or non-existent), then the returned time_point is +// the best estimate that preserves relative order. That is, this function +// guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz). +inline time_point<seconds> convert(const civil_second& cs, + const time_zone& tz) { + const time_zone::civil_lookup cl = tz.lookup(cs); + if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans; + return cl.pre; +} + +namespace detail { +using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>; +std::string format(const std::string&, const time_point<seconds>&, + const femtoseconds&, const time_zone&); +bool parse(const std::string&, const std::string&, const time_zone&, + time_point<seconds>*, femtoseconds*, std::string* err = nullptr); +} // namespace detail + +// Formats the given time_point in the given cctz::time_zone according to +// the provided format string. Uses strftime()-like formatting options, +// with the following extensions: +// +// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) +// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) +// - %E#S - Seconds with # digits of fractional precision +// - %E*S - Seconds with full fractional precision (a literal '*') +// - %E#f - Fractional seconds with # digits of precision +// - %E*f - Fractional seconds with full precision (a literal '*') +// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// - %ET - The RFC3339 "date-time" separator "T" +// +// Note that %E0S behaves like %S, and %E0f produces no characters. In +// contrast %E*f always produces at least one digit, which may be '0'. +// +// Note that %Y produces as many characters as it takes to fully render the +// year. A year outside of [-999:9999] when formatted with %E4Y will produce +// more than four characters, just like %Y. +// +// Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z) +// so that the resulting string uniquely identifies an absolute time. +// +// Example: +// cctz::time_zone lax; +// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... } +// auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax); +// std::string f = cctz::format("%H:%M:%S", tp, lax); // "03:04:05" +// f = cctz::format("%H:%M:%E3S", tp, lax); // "03:04:05.000" +template <typename D> +inline std::string format(const std::string& fmt, const time_point<D>& tp, + const time_zone& tz) { + const auto p = detail::split_seconds(tp); + const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second); + return detail::format(fmt, p.first, n, tz); +} + +// Parses an input string according to the provided format string and +// returns the corresponding time_point. Uses strftime()-like formatting +// options, with the same extensions as cctz::format(), but with the +// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez +// and %E*z also accept the same inputs, which (along with %z) includes +// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'. +// +// %Y consumes as many numeric characters as it can, so the matching data +// should always be terminated with a non-numeric. %E4Y always consumes +// exactly four characters, including any sign. +// +// Unspecified fields are taken from the default date and time of ... +// +// "1970-01-01 00:00:00.0 +0000" +// +// For example, parsing a string of "15:45" (%H:%M) will return a time_point +// that represents "1970-01-01 15:45:00.0 +0000". +// +// Note that parse() returns time instants, so it makes most sense to parse +// fully-specified date/time strings that include a UTC offset (%z, %Ez, or +// %E*z). +// +// Note also that parse() only heeds the fields year, month, day, hour, +// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a +// or %A), while parsed for syntactic validity, are ignored in the conversion. +// +// Date and time fields that are out-of-range will be treated as errors rather +// than normalizing them like cctz::civil_second() would do. For example, it +// is an error to parse the date "Oct 32, 2013" because 32 is out of range. +// +// A second of ":60" is normalized to ":00" of the following minute with +// fractional seconds discarded. The following table shows how the given +// seconds and subseconds will be parsed: +// +// "59.x" -> 59.x // exact +// "60.x" -> 00.0 // normalized +// "00.x" -> 00.x // exact +// +// Errors are indicated by returning false. +// +// Example: +// const cctz::time_zone tz = ... +// std::chrono::system_clock::time_point tp; +// if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) { +// ... +// } +template <typename D> +inline bool parse(const std::string& fmt, const std::string& input, + const time_zone& tz, time_point<D>* tpp) { + time_point<seconds> sec; + detail::femtoseconds fs; + const bool b = detail::parse(fmt, input, tz, &sec, &fs); + if (b) { + // TODO: Return false if unrepresentable as a time_point<D>. + *tpp = std::chrono::time_point_cast<D>(sec); + *tpp += std::chrono::duration_cast<D>(fs); + } + return b; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/zone_info_source.h b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/zone_info_source.h new file mode 100644 index 000000000000..012eb4ec30e0 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/include/cctz/zone_info_source.h @@ -0,0 +1,102 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_ +#define ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_ + +#include <cstddef> +#include <functional> +#include <memory> +#include <string> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// A stdio-like interface for providing zoneinfo data for a particular zone. +class ZoneInfoSource { + public: + virtual ~ZoneInfoSource(); + + virtual std::size_t Read(void* ptr, std::size_t size) = 0; // like fread() + virtual int Skip(std::size_t offset) = 0; // like fseek() + + // Until the zoneinfo data supports versioning information, we provide + // a way for a ZoneInfoSource to indicate it out-of-band. The default + // implementation returns an empty string. + virtual std::string Version() const; +}; + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz_extension { + +// A function-pointer type for a factory that returns a ZoneInfoSource +// given the name of a time zone and a fallback factory. Returns null +// when the data for the named zone cannot be found. +using ZoneInfoSourceFactory = + std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)( + const std::string&, + const std::function<std::unique_ptr< + absl::time_internal::cctz::ZoneInfoSource>(const std::string&)>&); + +// The user can control the mapping of zone names to zoneinfo data by +// providing a definition for cctz_extension::zone_info_source_factory. +// For example, given functions my_factory() and my_other_factory() that +// can return a ZoneInfoSource for a named zone, we could inject them into +// cctz::load_time_zone() with: +// +// namespace cctz_extension { +// namespace { +// std::unique_ptr<cctz::ZoneInfoSource> CustomFactory( +// const std::string& name, +// const std::function<std::unique_ptr<cctz::ZoneInfoSource>( +// const std::string& name)>& fallback_factory) { +// if (auto zip = my_factory(name)) return zip; +// if (auto zip = fallback_factory(name)) return zip; +// if (auto zip = my_other_factory(name)) return zip; +// return nullptr; +// } +// } // namespace +// ZoneInfoSourceFactory zone_info_source_factory = CustomFactory; +// } // namespace cctz_extension +// +// This might be used, say, to use zoneinfo data embedded in the program, +// or read from a (possibly compressed) file archive, or both. +// +// cctz_extension::zone_info_source_factory() will be called: +// (1) from the same thread as the cctz::load_time_zone() call, +// (2) only once for any zone name, and +// (3) serially (i.e., no concurrent execution). +// +// The fallback factory obtains zoneinfo data by reading files in ${TZDIR}, +// and it is used automatically when no zone_info_source_factory definition +// is linked into the program. +extern ZoneInfoSourceFactory zone_info_source_factory; + +} // namespace cctz_extension +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/cctz_benchmark.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/cctz_benchmark.cc new file mode 100644 index 000000000000..4e39188ff3e6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/cctz_benchmark.cc @@ -0,0 +1,1030 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <algorithm> +#include <cassert> +#include <chrono> +#include <ctime> +#include <random> +#include <string> +#include <vector> + +#include "benchmark/benchmark.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" +#include "time_zone_impl.h" + +namespace { + +namespace cctz = absl::time_internal::cctz; + +void BM_Difference_Days(benchmark::State& state) { + const cctz::civil_day c(2014, 8, 22); + const cctz::civil_day epoch(1970, 1, 1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(c - epoch); + } +} +BENCHMARK(BM_Difference_Days); + +void BM_Step_Days(benchmark::State& state) { + const cctz::civil_day kStart(2014, 8, 22); + cctz::civil_day c = kStart; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(++c); + } +} +BENCHMARK(BM_Step_Days); + +void BM_GetWeekday(benchmark::State& state) { + const cctz::civil_day c(2014, 8, 22); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::get_weekday(c)); + } +} +BENCHMARK(BM_GetWeekday); + +void BM_NextWeekday(benchmark::State& state) { + const cctz::civil_day kStart(2014, 8, 22); + const cctz::civil_day kDays[7] = { + kStart + 0, kStart + 1, kStart + 2, kStart + 3, + kStart + 4, kStart + 5, kStart + 6, + }; + const cctz::weekday kWeekdays[7] = { + cctz::weekday::monday, cctz::weekday::tuesday, cctz::weekday::wednesday, + cctz::weekday::thursday, cctz::weekday::friday, cctz::weekday::saturday, + cctz::weekday::sunday, + }; + while (state.KeepRunningBatch(7 * 7)) { + for (const auto from : kDays) { + for (const auto to : kWeekdays) { + benchmark::DoNotOptimize(cctz::next_weekday(from, to)); + } + } + } +} +BENCHMARK(BM_NextWeekday); + +void BM_PrevWeekday(benchmark::State& state) { + const cctz::civil_day kStart(2014, 8, 22); + const cctz::civil_day kDays[7] = { + kStart + 0, kStart + 1, kStart + 2, kStart + 3, + kStart + 4, kStart + 5, kStart + 6, + }; + const cctz::weekday kWeekdays[7] = { + cctz::weekday::monday, cctz::weekday::tuesday, cctz::weekday::wednesday, + cctz::weekday::thursday, cctz::weekday::friday, cctz::weekday::saturday, + cctz::weekday::sunday, + }; + while (state.KeepRunningBatch(7 * 7)) { + for (const auto from : kDays) { + for (const auto to : kWeekdays) { + benchmark::DoNotOptimize(cctz::prev_weekday(from, to)); + } + } + } +} +BENCHMARK(BM_PrevWeekday); + +const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez"; +const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; + +const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; +const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; + +// A list of known time-zone names. +// TODO: Refactor with src/time_zone_lookup_test.cc. +const char* const kTimeZoneNames[] = {"Africa/Abidjan", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Algiers", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Bissau", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/El_Aaiun", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Kampala", + "Africa/Khartoum", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Lagos", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maputo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Sao_Tome", + "Africa/Timbuktu", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Anguilla", + "America/Antigua", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/ComodRivadavia", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Aruba", + "America/Asuncion", + "America/Atikokan", + "America/Atka", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Buenos_Aires", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Catamarca", + "America/Cayenne", + "America/Cayman", + "America/Chicago", + "America/Chihuahua", + "America/Coral_Harbour", + "America/Cordoba", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Dominica", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Ensenada", + "America/Fort_Nelson", + "America/Fort_Wayne", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Grenada", + "America/Guadeloupe", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Indianapolis", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Jujuy", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/Knox_IN", + "America/Kralendijk", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Louisville", + "America/Lower_Princes", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Marigot", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Mendoza", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Nuuk", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Port_of_Spain", + "America/Porto_Acre", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Rosario", + "America/Santa_Isabel", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Shiprock", + "America/Sitka", + "America/St_Barthelemy", + "America/St_Johns", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Tortola", + "America/Vancouver", + "America/Virgin", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/McMurdo", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Ashkhabad", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Bahrain", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Colombo", + "Asia/Dacca", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Harbin", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Istanbul", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kashgar", + "Asia/Kathmandu", + "Asia/Katmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Muscat", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Phnom_Penh", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Rangoon", + "Asia/Riyadh", + "Asia/Saigon", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ujung_Pandang", + "Asia/Ulaanbaatar", + "Asia/Ulan_Bator", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vientiane", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faeroe", + "Atlantic/Faroe", + "Atlantic/Jan_Mayen", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/St_Helena", + "Atlantic/Stanley", + "Australia/ACT", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Canberra", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/LHI", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/NSW", + "Australia/North", + "Australia/Perth", + "Australia/Queensland", + "Australia/South", + "Australia/Sydney", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "CET", + "CST6CDT", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "Chile/Continental", + "Chile/EasterIsland", + "Cuba", + "EET", + "EST", + "EST5EDT", + "Egypt", + "Eire", + "Etc/GMT", + "Etc/GMT+0", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT-0", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/UTC", + "Etc/Universal", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belfast", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Bratislava", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Busingen", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Guernsey", + "Europe/Helsinki", + "Europe/Isle_of_Man", + "Europe/Istanbul", + "Europe/Jersey", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Lisbon", + "Europe/Ljubljana", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Mariehamn", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Paris", + "Europe/Podgorica", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Skopje", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Tiraspol", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zagreb", + "Europe/Zaporozhye", + "Europe/Zurich", + "GB", + "GB-Eire", + "GMT", + "GMT+0", + "GMT-0", + "GMT0", + "Greenwich", + "HST", + "Hongkong", + "Iceland", + "Indian/Antananarivo", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "MET", + "MST", + "MST7MDT", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "NZ", + "NZ-CHAT", + "Navajo", + "PRC", + "PST8PDT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Johnston", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Midway", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "ROC", + "ROK", + "Singapore", + "Turkey", + "UCT", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Samoa", + "UTC", + "Universal", + "W-SU", + "WET", + "Zulu", + nullptr}; + +std::vector<std::string> AllTimeZoneNames() { + std::vector<std::string> names; + for (const char* const* namep = kTimeZoneNames; *namep != nullptr; ++namep) { + names.push_back(std::string("file:") + *namep); + } + assert(!names.empty()); + + std::mt19937 urbg(42); // a UniformRandomBitGenerator with fixed seed + std::shuffle(names.begin(), names.end(), urbg); + return names; +} + +cctz::time_zone TestTimeZone() { + cctz::time_zone tz; + cctz::load_time_zone("America/Los_Angeles", &tz); + return tz; +} + +void BM_Zone_LoadUTCTimeZoneFirst(benchmark::State& state) { + cctz::time_zone tz; + cctz::load_time_zone("UTC", &tz); // in case we're first + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz)); + } +} +BENCHMARK(BM_Zone_LoadUTCTimeZoneFirst); + +void BM_Zone_LoadUTCTimeZoneLast(benchmark::State& state) { + cctz::time_zone tz; + for (const auto& name : AllTimeZoneNames()) { + cctz::load_time_zone(name, &tz); // prime cache + } + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::load_time_zone("UTC", &tz)); + } +} +BENCHMARK(BM_Zone_LoadUTCTimeZoneLast); + +void BM_Zone_LoadTimeZoneFirst(benchmark::State& state) { + cctz::time_zone tz = cctz::utc_time_zone(); // in case we're first + const std::string name = "file:America/Los_Angeles"; + while (state.KeepRunning()) { + state.PauseTiming(); + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + state.ResumeTiming(); + benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz)); + } +} +BENCHMARK(BM_Zone_LoadTimeZoneFirst); + +void BM_Zone_LoadTimeZoneCached(benchmark::State& state) { + cctz::time_zone tz = cctz::utc_time_zone(); // in case we're first + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + const std::string name = "file:America/Los_Angeles"; + cctz::load_time_zone(name, &tz); // prime cache + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::load_time_zone(name, &tz)); + } +} +BENCHMARK(BM_Zone_LoadTimeZoneCached); + +void BM_Zone_LoadLocalTimeZoneCached(benchmark::State& state) { + cctz::utc_time_zone(); // in case we're first + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + cctz::local_time_zone(); // prime cache + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::local_time_zone()); + } +} +BENCHMARK(BM_Zone_LoadLocalTimeZoneCached); + +void BM_Zone_LoadAllTimeZonesFirst(benchmark::State& state) { + cctz::time_zone tz; + const std::vector<std::string> names = AllTimeZoneNames(); + for (auto index = names.size(); state.KeepRunning(); ++index) { + if (index == names.size()) { + index = 0; + } + if (index == 0) { + state.PauseTiming(); + cctz::time_zone::Impl::ClearTimeZoneMapTestOnly(); + state.ResumeTiming(); + } + benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz)); + } +} +BENCHMARK(BM_Zone_LoadAllTimeZonesFirst); + +void BM_Zone_LoadAllTimeZonesCached(benchmark::State& state) { + cctz::time_zone tz; + const std::vector<std::string> names = AllTimeZoneNames(); + for (const auto& name : names) { + cctz::load_time_zone(name, &tz); // prime cache + } + for (auto index = names.size(); state.KeepRunning(); ++index) { + if (index == names.size()) { + index = 0; + } + benchmark::DoNotOptimize(cctz::load_time_zone(names[index], &tz)); + } +} +BENCHMARK(BM_Zone_LoadAllTimeZonesCached); + +void BM_Zone_TimeZoneEqualityImplicit(benchmark::State& state) { + cctz::time_zone tz; // implicit UTC + while (state.KeepRunning()) { + benchmark::DoNotOptimize(tz == tz); + } +} +BENCHMARK(BM_Zone_TimeZoneEqualityImplicit); + +void BM_Zone_TimeZoneEqualityExplicit(benchmark::State& state) { + cctz::time_zone tz = cctz::utc_time_zone(); // explicit UTC + while (state.KeepRunning()) { + benchmark::DoNotOptimize(tz == tz); + } +} +BENCHMARK(BM_Zone_TimeZoneEqualityExplicit); + +void BM_Zone_UTCTimeZone(benchmark::State& state) { + cctz::time_zone tz; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::utc_time_zone()); + } +} +BENCHMARK(BM_Zone_UTCTimeZone); + +// In each "ToCivil" benchmark we switch between two instants separated +// by at least one transition in order to defeat any internal caching of +// previous results (e.g., see local_time_hint_). +// +// The "UTC" variants use UTC instead of the Google/local time zone. + +void BM_Time_ToCivil_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = TestTimeZone(); + std::chrono::system_clock::time_point tp = + std::chrono::system_clock::from_time_t(1384569027); + std::chrono::system_clock::time_point tp2 = + std::chrono::system_clock::from_time_t(1418962578); + while (state.KeepRunning()) { + std::swap(tp, tp2); + tp += std::chrono::seconds(1); + benchmark::DoNotOptimize(cctz::convert(tp, tz)); + } +} +BENCHMARK(BM_Time_ToCivil_CCTZ); + +void BM_Time_ToCivil_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + time_t t = 1384569027; + time_t t2 = 1418962578; + struct tm tm; + while (state.KeepRunning()) { + std::swap(t, t2); + t += 1; +#if defined(_WIN32) || defined(_WIN64) + benchmark::DoNotOptimize(localtime_s(&tm, &t)); +#else + benchmark::DoNotOptimize(localtime_r(&t, &tm)); +#endif + } +} +BENCHMARK(BM_Time_ToCivil_Libc); + +void BM_Time_ToCivilUTC_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = cctz::utc_time_zone(); + std::chrono::system_clock::time_point tp = + std::chrono::system_clock::from_time_t(1384569027); + while (state.KeepRunning()) { + tp += std::chrono::seconds(1); + benchmark::DoNotOptimize(cctz::convert(tp, tz)); + } +} +BENCHMARK(BM_Time_ToCivilUTC_CCTZ); + +void BM_Time_ToCivilUTC_Libc(benchmark::State& state) { + time_t t = 1384569027; + struct tm tm; + while (state.KeepRunning()) { + t += 1; +#if defined(_WIN32) || defined(_WIN64) + benchmark::DoNotOptimize(gmtime_s(&tm, &t)); +#else + benchmark::DoNotOptimize(gmtime_r(&t, &tm)); +#endif + } +} +BENCHMARK(BM_Time_ToCivilUTC_Libc); + +// In each "FromCivil" benchmark we switch between two YMDhms values +// separated by at least one transition in order to defeat any internal +// caching of previous results (e.g., see time_local_hint_). +// +// The "UTC" variants use UTC instead of the Google/local time zone. +// The "Day0" variants require normalization of the day of month. + +void BM_Time_FromCivil_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = TestTimeZone(); + int i = 0; + while (state.KeepRunning()) { + if ((i++ & 1) == 0) { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz)); + } else { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2013, 11, 15, 18, 30, 27), tz)); + } + } +} +BENCHMARK(BM_Time_FromCivil_CCTZ); + +void BM_Time_FromCivil_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + int i = 0; + while (state.KeepRunning()) { + struct tm tm; + if ((i++ & 1) == 0) { + tm.tm_year = 2014 - 1900; + tm.tm_mon = 12 - 1; + tm.tm_mday = 18; + tm.tm_hour = 20; + tm.tm_min = 16; + tm.tm_sec = 18; + } else { + tm.tm_year = 2013 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 15; + tm.tm_hour = 18; + tm.tm_min = 30; + tm.tm_sec = 27; + } + tm.tm_isdst = -1; + benchmark::DoNotOptimize(mktime(&tm)); + } +} +BENCHMARK(BM_Time_FromCivil_Libc); + +void BM_Time_FromCivilUTC_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = cctz::utc_time_zone(); + while (state.KeepRunning()) { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2014, 12, 18, 20, 16, 18), tz)); + } +} +BENCHMARK(BM_Time_FromCivilUTC_CCTZ); + +// There is no BM_Time_FromCivilUTC_Libc. + +void BM_Time_FromCivilDay0_CCTZ(benchmark::State& state) { + const cctz::time_zone tz = TestTimeZone(); + int i = 0; + while (state.KeepRunning()) { + if ((i++ & 1) == 0) { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2014, 12, 0, 20, 16, 18), tz)); + } else { + benchmark::DoNotOptimize( + cctz::convert(cctz::civil_second(2013, 11, 0, 18, 30, 27), tz)); + } + } +} +BENCHMARK(BM_Time_FromCivilDay0_CCTZ); + +void BM_Time_FromCivilDay0_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + int i = 0; + while (state.KeepRunning()) { + struct tm tm; + if ((i++ & 1) == 0) { + tm.tm_year = 2014 - 1900; + tm.tm_mon = 12 - 1; + tm.tm_mday = 0; + tm.tm_hour = 20; + tm.tm_min = 16; + tm.tm_sec = 18; + } else { + tm.tm_year = 2013 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 0; + tm.tm_hour = 18; + tm.tm_min = 30; + tm.tm_sec = 27; + } + tm.tm_isdst = -1; + benchmark::DoNotOptimize(mktime(&tm)); + } +} +BENCHMARK(BM_Time_FromCivilDay0_Libc); + +const char* const kFormats[] = { + RFC1123_full, // 0 + RFC1123_no_wday, // 1 + RFC3339_full, // 2 + RFC3339_sec, // 3 + "%Y-%m-%d%ET%H:%M:%S", // 4 + "%Y-%m-%d", // 5 +}; +const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]); + +void BM_Format_FormatTime(benchmark::State& state) { + const std::string fmt = kFormats[state.range(0)]; + state.SetLabel(fmt); + const cctz::time_zone tz = TestTimeZone(); + const std::chrono::system_clock::time_point tp = + cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) + + std::chrono::microseconds(1); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::format(fmt, tp, tz)); + } +} +BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1); + +void BM_Format_ParseTime(benchmark::State& state) { + const std::string fmt = kFormats[state.range(0)]; + state.SetLabel(fmt); + const cctz::time_zone tz = TestTimeZone(); + std::chrono::system_clock::time_point tp = + cctz::convert(cctz::civil_second(1977, 6, 28, 9, 8, 7), tz) + + std::chrono::microseconds(1); + const std::string when = cctz::format(fmt, tp, tz); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(cctz::parse(fmt, when, tz, &tp)); + } +} +BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1); + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/civil_time_detail.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/civil_time_detail.cc new file mode 100644 index 000000000000..0b07e397e560 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/civil_time_detail.cc @@ -0,0 +1,94 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h" + +#include <iomanip> +#include <ostream> +#include <sstream> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { +namespace detail { + +// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss, +// while omitting fields inferior to the type's alignment. For example, +// civil_day is formatted only as YYYY-MM-DD. +std::ostream& operator<<(std::ostream& os, const civil_year& y) { + std::stringstream ss; + ss << y.year(); // No padding. + return os << ss.str(); +} +std::ostream& operator<<(std::ostream& os, const civil_month& m) { + std::stringstream ss; + ss << civil_year(m) << '-'; + ss << std::setfill('0') << std::setw(2) << m.month(); + return os << ss.str(); +} +std::ostream& operator<<(std::ostream& os, const civil_day& d) { + std::stringstream ss; + ss << civil_month(d) << '-'; + ss << std::setfill('0') << std::setw(2) << d.day(); + return os << ss.str(); +} +std::ostream& operator<<(std::ostream& os, const civil_hour& h) { + std::stringstream ss; + ss << civil_day(h) << 'T'; + ss << std::setfill('0') << std::setw(2) << h.hour(); + return os << ss.str(); +} +std::ostream& operator<<(std::ostream& os, const civil_minute& m) { + std::stringstream ss; + ss << civil_hour(m) << ':'; + ss << std::setfill('0') << std::setw(2) << m.minute(); + return os << ss.str(); +} +std::ostream& operator<<(std::ostream& os, const civil_second& s) { + std::stringstream ss; + ss << civil_minute(s) << ':'; + ss << std::setfill('0') << std::setw(2) << s.second(); + return os << ss.str(); +} + +//////////////////////////////////////////////////////////////////////// + +std::ostream& operator<<(std::ostream& os, weekday wd) { + switch (wd) { + case weekday::monday: + return os << "Monday"; + case weekday::tuesday: + return os << "Tuesday"; + case weekday::wednesday: + return os << "Wednesday"; + case weekday::thursday: + return os << "Thursday"; + case weekday::friday: + return os << "Friday"; + case weekday::saturday: + return os << "Saturday"; + case weekday::sunday: + return os << "Sunday"; + } + return os; // Should never get here, but -Wreturn-type may warn without this. +} + +} // namespace detail +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/civil_time_test.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/civil_time_test.cc new file mode 100644 index 000000000000..a5a71230419f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/civil_time_test.cc @@ -0,0 +1,1066 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/internal/cctz/include/cctz/civil_time.h" + +#include <iomanip> +#include <limits> +#include <sstream> +#include <string> +#include <type_traits> + +#include "gtest/gtest.h" +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +template <typename T> +std::string Format(const T& t) { + std::stringstream ss; + ss << t; + return ss.str(); +} + +} // namespace + +#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) +// Construction constexpr tests + +TEST(CivilTime, Normal) { + constexpr civil_second css(2016, 1, 28, 17, 14, 12); + static_assert(css.second() == 12, "Normal.second"); + constexpr civil_minute cmm(2016, 1, 28, 17, 14); + static_assert(cmm.minute() == 14, "Normal.minute"); + constexpr civil_hour chh(2016, 1, 28, 17); + static_assert(chh.hour() == 17, "Normal.hour"); + constexpr civil_day cd(2016, 1, 28); + static_assert(cd.day() == 28, "Normal.day"); + constexpr civil_month cm(2016, 1); + static_assert(cm.month() == 1, "Normal.month"); + constexpr civil_year cy(2016); + static_assert(cy.year() == 2016, "Normal.year"); +} + +TEST(CivilTime, Conversion) { + constexpr civil_year cy(2016); + static_assert(cy.year() == 2016, "Conversion.year"); + constexpr civil_month cm(cy); + static_assert(cm.month() == 1, "Conversion.month"); + constexpr civil_day cd(cm); + static_assert(cd.day() == 1, "Conversion.day"); + constexpr civil_hour chh(cd); + static_assert(chh.hour() == 0, "Conversion.hour"); + constexpr civil_minute cmm(chh); + static_assert(cmm.minute() == 0, "Conversion.minute"); + constexpr civil_second css(cmm); + static_assert(css.second() == 0, "Conversion.second"); +} + +// Normalization constexpr tests + +TEST(CivilTime, Normalized) { + constexpr civil_second cs(2016, 1, 28, 17, 14, 12); + static_assert(cs.year() == 2016, "Normalized.year"); + static_assert(cs.month() == 1, "Normalized.month"); + static_assert(cs.day() == 28, "Normalized.day"); + static_assert(cs.hour() == 17, "Normalized.hour"); + static_assert(cs.minute() == 14, "Normalized.minute"); + static_assert(cs.second() == 12, "Normalized.second"); +} + +TEST(CivilTime, SecondOverflow) { + constexpr civil_second cs(2016, 1, 28, 17, 14, 121); + static_assert(cs.year() == 2016, "SecondOverflow.year"); + static_assert(cs.month() == 1, "SecondOverflow.month"); + static_assert(cs.day() == 28, "SecondOverflow.day"); + static_assert(cs.hour() == 17, "SecondOverflow.hour"); + static_assert(cs.minute() == 16, "SecondOverflow.minute"); + static_assert(cs.second() == 1, "SecondOverflow.second"); +} + +TEST(CivilTime, SecondUnderflow) { + constexpr civil_second cs(2016, 1, 28, 17, 14, -121); + static_assert(cs.year() == 2016, "SecondUnderflow.year"); + static_assert(cs.month() == 1, "SecondUnderflow.month"); + static_assert(cs.day() == 28, "SecondUnderflow.day"); + static_assert(cs.hour() == 17, "SecondUnderflow.hour"); + static_assert(cs.minute() == 11, "SecondUnderflow.minute"); + static_assert(cs.second() == 59, "SecondUnderflow.second"); +} + +TEST(CivilTime, MinuteOverflow) { + constexpr civil_second cs(2016, 1, 28, 17, 121, 12); + static_assert(cs.year() == 2016, "MinuteOverflow.year"); + static_assert(cs.month() == 1, "MinuteOverflow.month"); + static_assert(cs.day() == 28, "MinuteOverflow.day"); + static_assert(cs.hour() == 19, "MinuteOverflow.hour"); + static_assert(cs.minute() == 1, "MinuteOverflow.minute"); + static_assert(cs.second() == 12, "MinuteOverflow.second"); +} + +TEST(CivilTime, MinuteUnderflow) { + constexpr civil_second cs(2016, 1, 28, 17, -121, 12); + static_assert(cs.year() == 2016, "MinuteUnderflow.year"); + static_assert(cs.month() == 1, "MinuteUnderflow.month"); + static_assert(cs.day() == 28, "MinuteUnderflow.day"); + static_assert(cs.hour() == 14, "MinuteUnderflow.hour"); + static_assert(cs.minute() == 59, "MinuteUnderflow.minute"); + static_assert(cs.second() == 12, "MinuteUnderflow.second"); +} + +TEST(CivilTime, HourOverflow) { + constexpr civil_second cs(2016, 1, 28, 49, 14, 12); + static_assert(cs.year() == 2016, "HourOverflow.year"); + static_assert(cs.month() == 1, "HourOverflow.month"); + static_assert(cs.day() == 30, "HourOverflow.day"); + static_assert(cs.hour() == 1, "HourOverflow.hour"); + static_assert(cs.minute() == 14, "HourOverflow.minute"); + static_assert(cs.second() == 12, "HourOverflow.second"); +} + +TEST(CivilTime, HourUnderflow) { + constexpr civil_second cs(2016, 1, 28, -49, 14, 12); + static_assert(cs.year() == 2016, "HourUnderflow.year"); + static_assert(cs.month() == 1, "HourUnderflow.month"); + static_assert(cs.day() == 25, "HourUnderflow.day"); + static_assert(cs.hour() == 23, "HourUnderflow.hour"); + static_assert(cs.minute() == 14, "HourUnderflow.minute"); + static_assert(cs.second() == 12, "HourUnderflow.second"); +} + +TEST(CivilTime, MonthOverflow) { + constexpr civil_second cs(2016, 25, 28, 17, 14, 12); + static_assert(cs.year() == 2018, "MonthOverflow.year"); + static_assert(cs.month() == 1, "MonthOverflow.month"); + static_assert(cs.day() == 28, "MonthOverflow.day"); + static_assert(cs.hour() == 17, "MonthOverflow.hour"); + static_assert(cs.minute() == 14, "MonthOverflow.minute"); + static_assert(cs.second() == 12, "MonthOverflow.second"); +} + +TEST(CivilTime, MonthUnderflow) { + constexpr civil_second cs(2016, -25, 28, 17, 14, 12); + static_assert(cs.year() == 2013, "MonthUnderflow.year"); + static_assert(cs.month() == 11, "MonthUnderflow.month"); + static_assert(cs.day() == 28, "MonthUnderflow.day"); + static_assert(cs.hour() == 17, "MonthUnderflow.hour"); + static_assert(cs.minute() == 14, "MonthUnderflow.minute"); + static_assert(cs.second() == 12, "MonthUnderflow.second"); +} + +TEST(CivilTime, C4Overflow) { + constexpr civil_second cs(2016, 1, 292195, 17, 14, 12); + static_assert(cs.year() == 2816, "C4Overflow.year"); + static_assert(cs.month() == 1, "C4Overflow.month"); + static_assert(cs.day() == 1, "C4Overflow.day"); + static_assert(cs.hour() == 17, "C4Overflow.hour"); + static_assert(cs.minute() == 14, "C4Overflow.minute"); + static_assert(cs.second() == 12, "C4Overflow.second"); +} + +TEST(CivilTime, C4Underflow) { + constexpr civil_second cs(2016, 1, -292195, 17, 14, 12); + static_assert(cs.year() == 1215, "C4Underflow.year"); + static_assert(cs.month() == 12, "C4Underflow.month"); + static_assert(cs.day() == 30, "C4Underflow.day"); + static_assert(cs.hour() == 17, "C4Underflow.hour"); + static_assert(cs.minute() == 14, "C4Underflow.minute"); + static_assert(cs.second() == 12, "C4Underflow.second"); +} + +TEST(CivilTime, MixedNormalization) { + constexpr civil_second cs(2016, -42, 122, 99, -147, 4949); + static_assert(cs.year() == 2012, "MixedNormalization.year"); + static_assert(cs.month() == 10, "MixedNormalization.month"); + static_assert(cs.day() == 4, "MixedNormalization.day"); + static_assert(cs.hour() == 1, "MixedNormalization.hour"); + static_assert(cs.minute() == 55, "MixedNormalization.minute"); + static_assert(cs.second() == 29, "MixedNormalization.second"); +} + +// Relational constexpr tests + +TEST(CivilTime, Less) { + constexpr civil_second cs1(2016, 1, 28, 17, 14, 12); + constexpr civil_second cs2(2016, 1, 28, 17, 14, 13); + constexpr bool less = cs1 < cs2; + static_assert(less, "Less"); +} + +// Arithmetic constexpr tests + +TEST(CivilTime, Addition) { + constexpr civil_second cs1(2016, 1, 28, 17, 14, 12); + constexpr civil_second cs2 = cs1 + 50; + static_assert(cs2.year() == 2016, "Addition.year"); + static_assert(cs2.month() == 1, "Addition.month"); + static_assert(cs2.day() == 28, "Addition.day"); + static_assert(cs2.hour() == 17, "Addition.hour"); + static_assert(cs2.minute() == 15, "Addition.minute"); + static_assert(cs2.second() == 2, "Addition.second"); +} + +TEST(CivilTime, Subtraction) { + constexpr civil_second cs1(2016, 1, 28, 17, 14, 12); + constexpr civil_second cs2 = cs1 - 50; + static_assert(cs2.year() == 2016, "Subtraction.year"); + static_assert(cs2.month() == 1, "Subtraction.month"); + static_assert(cs2.day() == 28, "Subtraction.day"); + static_assert(cs2.hour() == 17, "Subtraction.hour"); + static_assert(cs2.minute() == 13, "Subtraction.minute"); + static_assert(cs2.second() == 22, "Subtraction.second"); +} + +TEST(CivilTime, Difference) { + constexpr civil_day cd1(2016, 1, 28); + constexpr civil_day cd2(2015, 1, 28); + constexpr int diff = cd1 - cd2; + static_assert(diff == 365, "Difference"); +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, ConstructionWithHugeYear) { + constexpr civil_hour h(-9223372036854775807, 1, 1, -1); + static_assert(h.year() == -9223372036854775807 - 1, + "ConstructionWithHugeYear"); + static_assert(h.month() == 12, "ConstructionWithHugeYear"); + static_assert(h.day() == 31, "ConstructionWithHugeYear"); + static_assert(h.hour() == 23, "ConstructionWithHugeYear"); +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, DifferenceWithHugeYear) { + { + constexpr civil_day d1(9223372036854775807, 1, 1); + constexpr civil_day d2(9223372036854775807, 12, 31); + static_assert(d2 - d1 == 364, "DifferenceWithHugeYear"); + } + { + constexpr civil_day d1(-9223372036854775807 - 1, 1, 1); + constexpr civil_day d2(-9223372036854775807 - 1, 12, 31); + static_assert(d2 - d1 == 365, "DifferenceWithHugeYear"); + } + { + // Check the limits of the return value at the end of the year range. + constexpr civil_day d1(9223372036854775807, 1, 1); + constexpr civil_day d2(9198119301927009252, 6, 6); + static_assert(d1 - d2 == 9223372036854775807, "DifferenceWithHugeYear"); + static_assert((d2 - 1) - d1 == -9223372036854775807 - 1, + "DifferenceWithHugeYear"); + } + { + // Check the limits of the return value at the start of the year range. + constexpr civil_day d1(-9223372036854775807 - 1, 1, 1); + constexpr civil_day d2(-9198119301927009254, 7, 28); + static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear"); + static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1, + "DifferenceWithHugeYear"); + } + { + // Check the limits of the return value from either side of year 0. + constexpr civil_day d1(-12626367463883278, 9, 3); + constexpr civil_day d2(12626367463883277, 3, 28); + static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear"); + static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1, + "DifferenceWithHugeYear"); + } +} + +// NOTE: Run this with --copt=-ftrapv to detect overflow problems. +TEST(CivilTime, DifferenceNoIntermediateOverflow) { + { + // The difference up to the minute field would be below the minimum + // diff_t, but the 52 extra seconds brings us back to the minimum. + constexpr civil_second s1(-292277022657, 1, 27, 8, 29 - 1, 52); + constexpr civil_second s2(1970, 1, 1, 0, 0 - 1, 0); + static_assert(s1 - s2 == -9223372036854775807 - 1, + "DifferenceNoIntermediateOverflow"); + } + { + // The difference up to the minute field would be above the maximum + // diff_t, but the -53 extra seconds brings us back to the maximum. + constexpr civil_second s1(292277026596, 12, 4, 15, 30, 7 - 7); + constexpr civil_second s2(1970, 1, 1, 0, 0, 0 - 7); + static_assert(s1 - s2 == 9223372036854775807, + "DifferenceNoIntermediateOverflow"); + } +} + +// Helper constexpr tests + +TEST(CivilTime, WeekDay) { + constexpr civil_day cd(2016, 1, 28); + constexpr weekday wd = get_weekday(cd); + static_assert(wd == weekday::thursday, "Weekday"); +} + +TEST(CivilTime, NextWeekDay) { + constexpr civil_day cd(2016, 1, 28); + constexpr civil_day next = next_weekday(cd, weekday::thursday); + static_assert(next.year() == 2016, "NextWeekDay.year"); + static_assert(next.month() == 2, "NextWeekDay.month"); + static_assert(next.day() == 4, "NextWeekDay.day"); +} + +TEST(CivilTime, PrevWeekDay) { + constexpr civil_day cd(2016, 1, 28); + constexpr civil_day prev = prev_weekday(cd, weekday::thursday); + static_assert(prev.year() == 2016, "PrevWeekDay.year"); + static_assert(prev.month() == 1, "PrevWeekDay.month"); + static_assert(prev.day() == 21, "PrevWeekDay.day"); +} + +TEST(CivilTime, YearDay) { + constexpr civil_day cd(2016, 1, 28); + constexpr int yd = get_yearday(cd); + static_assert(yd == 28, "YearDay"); +} +#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910) + +// The remaining tests do not use constexpr. + +TEST(CivilTime, DefaultConstruction) { + civil_second ss; + EXPECT_EQ("1970-01-01T00:00:00", Format(ss)); + + civil_minute mm; + EXPECT_EQ("1970-01-01T00:00", Format(mm)); + + civil_hour hh; + EXPECT_EQ("1970-01-01T00", Format(hh)); + + civil_day d; + EXPECT_EQ("1970-01-01", Format(d)); + + civil_month m; + EXPECT_EQ("1970-01", Format(m)); + + civil_year y; + EXPECT_EQ("1970", Format(y)); +} + +TEST(CivilTime, StructMember) { + struct S { + civil_day day; + }; + S s = {}; + EXPECT_EQ(civil_day{}, s.day); +} + +TEST(CivilTime, FieldsConstruction) { + EXPECT_EQ("2015-01-02T03:04:05", Format(civil_second(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03:04:00", Format(civil_second(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03:00:00", Format(civil_second(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00:00:00", Format(civil_second(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015, 1))); + EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015))); + + EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03:00", Format(civil_minute(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00:00", Format(civil_minute(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015, 1))); + EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015))); + + EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02T00", Format(civil_hour(2015, 1, 2))); + EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015, 1))); + EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015))); + + EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3))); + EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2))); + EXPECT_EQ("2015-01-01", Format(civil_day(2015, 1))); + EXPECT_EQ("2015-01-01", Format(civil_day(2015))); + + EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3))); + EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2))); + EXPECT_EQ("2015-01", Format(civil_month(2015, 1))); + EXPECT_EQ("2015-01", Format(civil_month(2015))); + + EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4, 5))); + EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4))); + EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3))); + EXPECT_EQ("2015", Format(civil_year(2015, 1, 2))); + EXPECT_EQ("2015", Format(civil_year(2015, 1))); + EXPECT_EQ("2015", Format(civil_year(2015))); +} + +TEST(CivilTime, FieldsConstructionLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + EXPECT_EQ("2038-01-19T03:14:07", + Format(civil_second(1970, 1, 1, 0, 0, kIntMax))); + EXPECT_EQ("6121-02-11T05:21:07", + Format(civil_second(1970, 1, 1, 0, kIntMax, kIntMax))); + EXPECT_EQ("251104-11-20T12:21:07", + Format(civil_second(1970, 1, 1, kIntMax, kIntMax, kIntMax))); + EXPECT_EQ("6130715-05-30T12:21:07", + Format(civil_second(1970, 1, kIntMax, kIntMax, kIntMax, kIntMax))); + EXPECT_EQ( + "185087685-11-26T12:21:07", + Format(civil_second(1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax))); + + const int kIntMin = std::numeric_limits<int>::min(); + EXPECT_EQ("1901-12-13T20:45:52", + Format(civil_second(1970, 1, 1, 0, 0, kIntMin))); + EXPECT_EQ("-2182-11-20T18:37:52", + Format(civil_second(1970, 1, 1, 0, kIntMin, kIntMin))); + EXPECT_EQ("-247165-02-11T10:37:52", + Format(civil_second(1970, 1, 1, kIntMin, kIntMin, kIntMin))); + EXPECT_EQ("-6126776-08-01T10:37:52", + Format(civil_second(1970, 1, kIntMin, kIntMin, kIntMin, kIntMin))); + EXPECT_EQ( + "-185083747-10-31T10:37:52", + Format(civil_second(1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin))); +} + +TEST(CivilTime, ImplicitCrossAlignment) { + civil_year year(2015); + civil_month month = year; + civil_day day = month; + civil_hour hour = day; + civil_minute minute = hour; + civil_second second = minute; + + second = year; + EXPECT_EQ(second, year); + second = month; + EXPECT_EQ(second, month); + second = day; + EXPECT_EQ(second, day); + second = hour; + EXPECT_EQ(second, hour); + second = minute; + EXPECT_EQ(second, minute); + + minute = year; + EXPECT_EQ(minute, year); + minute = month; + EXPECT_EQ(minute, month); + minute = day; + EXPECT_EQ(minute, day); + minute = hour; + EXPECT_EQ(minute, hour); + + hour = year; + EXPECT_EQ(hour, year); + hour = month; + EXPECT_EQ(hour, month); + hour = day; + EXPECT_EQ(hour, day); + + day = year; + EXPECT_EQ(day, year); + day = month; + EXPECT_EQ(day, month); + + month = year; + EXPECT_EQ(month, year); + + // Ensures unsafe conversions are not allowed. + EXPECT_FALSE((std::is_convertible<civil_second, civil_minute>::value)); + EXPECT_FALSE((std::is_convertible<civil_second, civil_hour>::value)); + EXPECT_FALSE((std::is_convertible<civil_second, civil_day>::value)); + EXPECT_FALSE((std::is_convertible<civil_second, civil_month>::value)); + EXPECT_FALSE((std::is_convertible<civil_second, civil_year>::value)); + + EXPECT_FALSE((std::is_convertible<civil_minute, civil_hour>::value)); + EXPECT_FALSE((std::is_convertible<civil_minute, civil_day>::value)); + EXPECT_FALSE((std::is_convertible<civil_minute, civil_month>::value)); + EXPECT_FALSE((std::is_convertible<civil_minute, civil_year>::value)); + + EXPECT_FALSE((std::is_convertible<civil_hour, civil_day>::value)); + EXPECT_FALSE((std::is_convertible<civil_hour, civil_month>::value)); + EXPECT_FALSE((std::is_convertible<civil_hour, civil_year>::value)); + + EXPECT_FALSE((std::is_convertible<civil_day, civil_month>::value)); + EXPECT_FALSE((std::is_convertible<civil_day, civil_year>::value)); + + EXPECT_FALSE((std::is_convertible<civil_month, civil_year>::value)); +} + +TEST(CivilTime, ExplicitCrossAlignment) { + // + // Assign from smaller units -> larger units + // + + civil_second second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ("2015-01-02T03:04:05", Format(second)); + + civil_minute minute(second); + EXPECT_EQ("2015-01-02T03:04", Format(minute)); + + civil_hour hour(minute); + EXPECT_EQ("2015-01-02T03", Format(hour)); + + civil_day day(hour); + EXPECT_EQ("2015-01-02", Format(day)); + + civil_month month(day); + EXPECT_EQ("2015-01", Format(month)); + + civil_year year(month); + EXPECT_EQ("2015", Format(year)); + + // + // Now assign from larger units -> smaller units + // + + month = civil_month(year); + EXPECT_EQ("2015-01", Format(month)); + + day = civil_day(month); + EXPECT_EQ("2015-01-01", Format(day)); + + hour = civil_hour(day); + EXPECT_EQ("2015-01-01T00", Format(hour)); + + minute = civil_minute(hour); + EXPECT_EQ("2015-01-01T00:00", Format(minute)); + + second = civil_second(minute); + EXPECT_EQ("2015-01-01T00:00:00", Format(second)); +} + +// Metafunction to test whether difference is allowed between two types. +template <typename T1, typename T2> +struct HasDifference { + template <typename U1, typename U2> + static std::false_type test(...); + template <typename U1, typename U2> + static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>())); + static constexpr bool value = decltype(test<T1, T2>(0))::value; +}; + +TEST(CivilTime, DisallowCrossAlignedDifference) { + // Difference is allowed between types with the same alignment. + static_assert(HasDifference<civil_second, civil_second>::value, ""); + static_assert(HasDifference<civil_minute, civil_minute>::value, ""); + static_assert(HasDifference<civil_hour, civil_hour>::value, ""); + static_assert(HasDifference<civil_day, civil_day>::value, ""); + static_assert(HasDifference<civil_month, civil_month>::value, ""); + static_assert(HasDifference<civil_year, civil_year>::value, ""); + + // Difference is disallowed between types with different alignments. + static_assert(!HasDifference<civil_second, civil_minute>::value, ""); + static_assert(!HasDifference<civil_second, civil_hour>::value, ""); + static_assert(!HasDifference<civil_second, civil_day>::value, ""); + static_assert(!HasDifference<civil_second, civil_month>::value, ""); + static_assert(!HasDifference<civil_second, civil_year>::value, ""); + + static_assert(!HasDifference<civil_minute, civil_hour>::value, ""); + static_assert(!HasDifference<civil_minute, civil_day>::value, ""); + static_assert(!HasDifference<civil_minute, civil_month>::value, ""); + static_assert(!HasDifference<civil_minute, civil_year>::value, ""); + + static_assert(!HasDifference<civil_hour, civil_day>::value, ""); + static_assert(!HasDifference<civil_hour, civil_month>::value, ""); + static_assert(!HasDifference<civil_hour, civil_year>::value, ""); + + static_assert(!HasDifference<civil_day, civil_month>::value, ""); + static_assert(!HasDifference<civil_day, civil_year>::value, ""); + + static_assert(!HasDifference<civil_month, civil_year>::value, ""); +} + +TEST(CivilTime, ValueSemantics) { + const civil_hour a(2015, 1, 2, 3); + const civil_hour b = a; + const civil_hour c(b); + civil_hour d; + d = c; + EXPECT_EQ("2015-01-02T03", Format(d)); +} + +TEST(CivilTime, Relational) { + // Tests that the alignment unit is ignored in comparison. + const civil_year year(2014); + const civil_month month(year); + EXPECT_EQ(year, month); + +#define TEST_RELATIONAL(OLDER, YOUNGER) \ + do { \ + EXPECT_FALSE(OLDER < OLDER); \ + EXPECT_FALSE(OLDER > OLDER); \ + EXPECT_TRUE(OLDER >= OLDER); \ + EXPECT_TRUE(OLDER <= OLDER); \ + EXPECT_FALSE(YOUNGER < YOUNGER); \ + EXPECT_FALSE(YOUNGER > YOUNGER); \ + EXPECT_TRUE(YOUNGER >= YOUNGER); \ + EXPECT_TRUE(YOUNGER <= YOUNGER); \ + EXPECT_EQ(OLDER, OLDER); \ + EXPECT_NE(OLDER, YOUNGER); \ + EXPECT_LT(OLDER, YOUNGER); \ + EXPECT_LE(OLDER, YOUNGER); \ + EXPECT_GT(YOUNGER, OLDER); \ + EXPECT_GE(YOUNGER, OLDER); \ + } while (0) + + // Alignment is ignored in comparison (verified above), so kSecond is used + // to test comparison in all field positions. + TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), + civil_second(2015, 1, 1, 0, 0, 0)); + TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), + civil_second(2014, 2, 1, 0, 0, 0)); + TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), + civil_second(2014, 1, 2, 0, 0, 0)); + TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0), + civil_second(2014, 1, 1, 1, 0, 0)); + TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 0, 0), + civil_second(2014, 1, 1, 1, 1, 0)); + TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 1, 0), + civil_second(2014, 1, 1, 1, 1, 1)); + + // Tests the relational operators of two different civil-time types. + TEST_RELATIONAL(civil_day(2014, 1, 1), civil_minute(2014, 1, 1, 1, 1)); + TEST_RELATIONAL(civil_day(2014, 1, 1), civil_month(2014, 2)); + +#undef TEST_RELATIONAL +} + +TEST(CivilTime, Arithmetic) { + civil_second second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ("2015-01-02T03:04:06", Format(second += 1)); + EXPECT_EQ("2015-01-02T03:04:07", Format(second + 1)); + EXPECT_EQ("2015-01-02T03:04:08", Format(2 + second)); + EXPECT_EQ("2015-01-02T03:04:05", Format(second - 1)); + EXPECT_EQ("2015-01-02T03:04:05", Format(second -= 1)); + EXPECT_EQ("2015-01-02T03:04:05", Format(second++)); + EXPECT_EQ("2015-01-02T03:04:07", Format(++second)); + EXPECT_EQ("2015-01-02T03:04:07", Format(second--)); + EXPECT_EQ("2015-01-02T03:04:05", Format(--second)); + + civil_minute minute(2015, 1, 2, 3, 4); + EXPECT_EQ("2015-01-02T03:05", Format(minute += 1)); + EXPECT_EQ("2015-01-02T03:06", Format(minute + 1)); + EXPECT_EQ("2015-01-02T03:07", Format(2 + minute)); + EXPECT_EQ("2015-01-02T03:04", Format(minute - 1)); + EXPECT_EQ("2015-01-02T03:04", Format(minute -= 1)); + EXPECT_EQ("2015-01-02T03:04", Format(minute++)); + EXPECT_EQ("2015-01-02T03:06", Format(++minute)); + EXPECT_EQ("2015-01-02T03:06", Format(minute--)); + EXPECT_EQ("2015-01-02T03:04", Format(--minute)); + + civil_hour hour(2015, 1, 2, 3); + EXPECT_EQ("2015-01-02T04", Format(hour += 1)); + EXPECT_EQ("2015-01-02T05", Format(hour + 1)); + EXPECT_EQ("2015-01-02T06", Format(2 + hour)); + EXPECT_EQ("2015-01-02T03", Format(hour - 1)); + EXPECT_EQ("2015-01-02T03", Format(hour -= 1)); + EXPECT_EQ("2015-01-02T03", Format(hour++)); + EXPECT_EQ("2015-01-02T05", Format(++hour)); + EXPECT_EQ("2015-01-02T05", Format(hour--)); + EXPECT_EQ("2015-01-02T03", Format(--hour)); + + civil_day day(2015, 1, 2); + EXPECT_EQ("2015-01-03", Format(day += 1)); + EXPECT_EQ("2015-01-04", Format(day + 1)); + EXPECT_EQ("2015-01-05", Format(2 + day)); + EXPECT_EQ("2015-01-02", Format(day - 1)); + EXPECT_EQ("2015-01-02", Format(day -= 1)); + EXPECT_EQ("2015-01-02", Format(day++)); + EXPECT_EQ("2015-01-04", Format(++day)); + EXPECT_EQ("2015-01-04", Format(day--)); + EXPECT_EQ("2015-01-02", Format(--day)); + + civil_month month(2015, 1); + EXPECT_EQ("2015-02", Format(month += 1)); + EXPECT_EQ("2015-03", Format(month + 1)); + EXPECT_EQ("2015-04", Format(2 + month)); + EXPECT_EQ("2015-01", Format(month - 1)); + EXPECT_EQ("2015-01", Format(month -= 1)); + EXPECT_EQ("2015-01", Format(month++)); + EXPECT_EQ("2015-03", Format(++month)); + EXPECT_EQ("2015-03", Format(month--)); + EXPECT_EQ("2015-01", Format(--month)); + + civil_year year(2015); + EXPECT_EQ("2016", Format(year += 1)); + EXPECT_EQ("2017", Format(year + 1)); + EXPECT_EQ("2018", Format(2 + year)); + EXPECT_EQ("2015", Format(year - 1)); + EXPECT_EQ("2015", Format(year -= 1)); + EXPECT_EQ("2015", Format(year++)); + EXPECT_EQ("2017", Format(++year)); + EXPECT_EQ("2017", Format(year--)); + EXPECT_EQ("2015", Format(--year)); +} + +TEST(CivilTime, ArithmeticLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + const int kIntMin = std::numeric_limits<int>::min(); + + civil_second second(1970, 1, 1, 0, 0, 0); + second += kIntMax; + EXPECT_EQ("2038-01-19T03:14:07", Format(second)); + second -= kIntMax; + EXPECT_EQ("1970-01-01T00:00:00", Format(second)); + second += kIntMin; + EXPECT_EQ("1901-12-13T20:45:52", Format(second)); + second -= kIntMin; + EXPECT_EQ("1970-01-01T00:00:00", Format(second)); + + civil_minute minute(1970, 1, 1, 0, 0); + minute += kIntMax; + EXPECT_EQ("6053-01-23T02:07", Format(minute)); + minute -= kIntMax; + EXPECT_EQ("1970-01-01T00:00", Format(minute)); + minute += kIntMin; + EXPECT_EQ("-2114-12-08T21:52", Format(minute)); + minute -= kIntMin; + EXPECT_EQ("1970-01-01T00:00", Format(minute)); + + civil_hour hour(1970, 1, 1, 0); + hour += kIntMax; + EXPECT_EQ("246953-10-09T07", Format(hour)); + hour -= kIntMax; + EXPECT_EQ("1970-01-01T00", Format(hour)); + hour += kIntMin; + EXPECT_EQ("-243014-03-24T16", Format(hour)); + hour -= kIntMin; + EXPECT_EQ("1970-01-01T00", Format(hour)); + + civil_day day(1970, 1, 1); + day += kIntMax; + EXPECT_EQ("5881580-07-11", Format(day)); + day -= kIntMax; + EXPECT_EQ("1970-01-01", Format(day)); + day += kIntMin; + EXPECT_EQ("-5877641-06-23", Format(day)); + day -= kIntMin; + EXPECT_EQ("1970-01-01", Format(day)); + + civil_month month(1970, 1); + month += kIntMax; + EXPECT_EQ("178958940-08", Format(month)); + month -= kIntMax; + EXPECT_EQ("1970-01", Format(month)); + month += kIntMin; + EXPECT_EQ("-178955001-05", Format(month)); + month -= kIntMin; + EXPECT_EQ("1970-01", Format(month)); + + civil_year year(0); + year += kIntMax; + EXPECT_EQ("2147483647", Format(year)); + year -= kIntMax; + EXPECT_EQ("0", Format(year)); + year += kIntMin; + EXPECT_EQ("-2147483648", Format(year)); + year -= kIntMin; + EXPECT_EQ("0", Format(year)); +} + +TEST(CivilTime, ArithmeticDifference) { + civil_second second(2015, 1, 2, 3, 4, 5); + EXPECT_EQ(0, second - second); + EXPECT_EQ(10, (second + 10) - second); + EXPECT_EQ(-10, (second - 10) - second); + + civil_minute minute(2015, 1, 2, 3, 4); + EXPECT_EQ(0, minute - minute); + EXPECT_EQ(10, (minute + 10) - minute); + EXPECT_EQ(-10, (minute - 10) - minute); + + civil_hour hour(2015, 1, 2, 3); + EXPECT_EQ(0, hour - hour); + EXPECT_EQ(10, (hour + 10) - hour); + EXPECT_EQ(-10, (hour - 10) - hour); + + civil_day day(2015, 1, 2); + EXPECT_EQ(0, day - day); + EXPECT_EQ(10, (day + 10) - day); + EXPECT_EQ(-10, (day - 10) - day); + + civil_month month(2015, 1); + EXPECT_EQ(0, month - month); + EXPECT_EQ(10, (month + 10) - month); + EXPECT_EQ(-10, (month - 10) - month); + + civil_year year(2015); + EXPECT_EQ(0, year - year); + EXPECT_EQ(10, (year + 10) - year); + EXPECT_EQ(-10, (year - 10) - year); +} + +TEST(CivilTime, DifferenceLimits) { + const int kIntMax = std::numeric_limits<int>::max(); + const int kIntMin = std::numeric_limits<int>::min(); + + // Check day arithmetic at the end of the year range. + const civil_day max_day(kIntMax, 12, 31); + EXPECT_EQ(1, max_day - (max_day - 1)); + EXPECT_EQ(-1, (max_day - 1) - max_day); + + // Check day arithmetic at the end of the year range. + const civil_day min_day(kIntMin, 1, 1); + EXPECT_EQ(1, (min_day + 1) - min_day); + EXPECT_EQ(-1, min_day - (min_day + 1)); + + // Check the limits of the return value. + const civil_day d1(1970, 1, 1); + const civil_day d2(5881580, 7, 11); + EXPECT_EQ(kIntMax, d2 - d1); + EXPECT_EQ(kIntMin, d1 - (d2 + 1)); +} + +TEST(CivilTime, Properties) { + civil_second ss(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, ss.year()); + EXPECT_EQ(2, ss.month()); + EXPECT_EQ(3, ss.day()); + EXPECT_EQ(4, ss.hour()); + EXPECT_EQ(5, ss.minute()); + EXPECT_EQ(6, ss.second()); + EXPECT_EQ(weekday::tuesday, get_weekday(ss)); + EXPECT_EQ(34, get_yearday(ss)); + + civil_minute mm(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, mm.year()); + EXPECT_EQ(2, mm.month()); + EXPECT_EQ(3, mm.day()); + EXPECT_EQ(4, mm.hour()); + EXPECT_EQ(5, mm.minute()); + EXPECT_EQ(0, mm.second()); + EXPECT_EQ(weekday::tuesday, get_weekday(mm)); + EXPECT_EQ(34, get_yearday(mm)); + + civil_hour hh(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, hh.year()); + EXPECT_EQ(2, hh.month()); + EXPECT_EQ(3, hh.day()); + EXPECT_EQ(4, hh.hour()); + EXPECT_EQ(0, hh.minute()); + EXPECT_EQ(0, hh.second()); + EXPECT_EQ(weekday::tuesday, get_weekday(hh)); + EXPECT_EQ(34, get_yearday(hh)); + + civil_day d(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, d.year()); + EXPECT_EQ(2, d.month()); + EXPECT_EQ(3, d.day()); + EXPECT_EQ(0, d.hour()); + EXPECT_EQ(0, d.minute()); + EXPECT_EQ(0, d.second()); + EXPECT_EQ(weekday::tuesday, get_weekday(d)); + EXPECT_EQ(34, get_yearday(d)); + + civil_month m(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, m.year()); + EXPECT_EQ(2, m.month()); + EXPECT_EQ(1, m.day()); + EXPECT_EQ(0, m.hour()); + EXPECT_EQ(0, m.minute()); + EXPECT_EQ(0, m.second()); + EXPECT_EQ(weekday::sunday, get_weekday(m)); + EXPECT_EQ(32, get_yearday(m)); + + civil_year y(2015, 2, 3, 4, 5, 6); + EXPECT_EQ(2015, y.year()); + EXPECT_EQ(1, y.month()); + EXPECT_EQ(1, y.day()); + EXPECT_EQ(0, y.hour()); + EXPECT_EQ(0, y.minute()); + EXPECT_EQ(0, y.second()); + EXPECT_EQ(weekday::thursday, get_weekday(y)); + EXPECT_EQ(1, get_yearday(y)); +} + +TEST(CivilTime, OutputStream) { + // Tests formatting of civil_year, which does not pad. + EXPECT_EQ("2016", Format(civil_year(2016))); + EXPECT_EQ("123", Format(civil_year(123))); + EXPECT_EQ("0", Format(civil_year(0))); + EXPECT_EQ("-1", Format(civil_year(-1))); + + // Tests formatting of sub-year types, which pad to 2 digits + EXPECT_EQ("2016-02", Format(civil_month(2016, 2))); + EXPECT_EQ("2016-02-03", Format(civil_day(2016, 2, 3))); + EXPECT_EQ("2016-02-03T04", Format(civil_hour(2016, 2, 3, 4))); + EXPECT_EQ("2016-02-03T04:05", Format(civil_minute(2016, 2, 3, 4, 5))); + EXPECT_EQ("2016-02-03T04:05:06", Format(civil_second(2016, 2, 3, 4, 5, 6))); + + // Tests formatting of weekday. + EXPECT_EQ("Monday", Format(weekday::monday)); + EXPECT_EQ("Tuesday", Format(weekday::tuesday)); + EXPECT_EQ("Wednesday", Format(weekday::wednesday)); + EXPECT_EQ("Thursday", Format(weekday::thursday)); + EXPECT_EQ("Friday", Format(weekday::friday)); + EXPECT_EQ("Saturday", Format(weekday::saturday)); + EXPECT_EQ("Sunday", Format(weekday::sunday)); +} + +TEST(CivilTime, OutputStreamLeftFillWidth) { + civil_second cs(2016, 2, 3, 4, 5, 6); + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << civil_year(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016.................X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << civil_month(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02..............X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << civil_day(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03...........X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << civil_hour(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04........X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << civil_minute(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str()); + } + { + std::stringstream ss; + ss << std::left << std::setfill('.'); + ss << std::setw(3) << 'X'; + ss << std::setw(21) << civil_second(cs); + ss << std::setw(3) << 'X'; + EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str()); + } +} + +TEST(CivilTime, NextPrevWeekday) { + // Jan 1, 1970 was a Thursday. + const civil_day thursday(1970, 1, 1); + EXPECT_EQ(weekday::thursday, get_weekday(thursday)); + + // Thursday -> Thursday + civil_day d = next_weekday(thursday, weekday::thursday); + EXPECT_EQ(7, d - thursday) << Format(d); + EXPECT_EQ(d - 14, prev_weekday(thursday, weekday::thursday)); + + // Thursday -> Friday + d = next_weekday(thursday, weekday::friday); + EXPECT_EQ(1, d - thursday) << Format(d); + EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::friday)); + + // Thursday -> Saturday + d = next_weekday(thursday, weekday::saturday); + EXPECT_EQ(2, d - thursday) << Format(d); + EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::saturday)); + + // Thursday -> Sunday + d = next_weekday(thursday, weekday::sunday); + EXPECT_EQ(3, d - thursday) << Format(d); + EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::sunday)); + + // Thursday -> Monday + d = next_weekday(thursday, weekday::monday); + EXPECT_EQ(4, d - thursday) << Format(d); + EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::monday)); + + // Thursday -> Tuesday + d = next_weekday(thursday, weekday::tuesday); + EXPECT_EQ(5, d - thursday) << Format(d); + EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::tuesday)); + + // Thursday -> Wednesday + d = next_weekday(thursday, weekday::wednesday); + EXPECT_EQ(6, d - thursday) << Format(d); + EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::wednesday)); +} + +TEST(CivilTime, NormalizeWithHugeYear) { + civil_month c(9223372036854775807, 1); + EXPECT_EQ("9223372036854775807-01", Format(c)); + c = c - 1; // Causes normalization + EXPECT_EQ("9223372036854775806-12", Format(c)); + + c = civil_month(-9223372036854775807 - 1, 1); + EXPECT_EQ("-9223372036854775808-01", Format(c)); + c = c + 12; // Causes normalization + EXPECT_EQ("-9223372036854775807-01", Format(c)); +} + +TEST(CivilTime, LeapYears) { + // Test data for leap years. + const struct { + int year; + int days; + struct { + int month; + int day; + } leap_day; // The date of the day after Feb 28. + } kLeapYearTable[]{ + {1900, 365, {3, 1}}, {1999, 365, {3, 1}}, + {2000, 366, {2, 29}}, // leap year + {2001, 365, {3, 1}}, {2002, 365, {3, 1}}, + {2003, 365, {3, 1}}, {2004, 366, {2, 29}}, // leap year + {2005, 365, {3, 1}}, {2006, 365, {3, 1}}, + {2007, 365, {3, 1}}, {2008, 366, {2, 29}}, // leap year + {2009, 365, {3, 1}}, {2100, 365, {3, 1}}, + }; + + for (const auto& e : kLeapYearTable) { + // Tests incrementing through the leap day. + const civil_day feb28(e.year, 2, 28); + const civil_day next_day = feb28 + 1; + EXPECT_EQ(e.leap_day.month, next_day.month()); + EXPECT_EQ(e.leap_day.day, next_day.day()); + + // Tests difference in days of leap years. + const civil_year year(feb28); + const civil_year next_year = year + 1; + EXPECT_EQ(e.days, civil_day(next_year) - civil_day(year)); + } +} + +TEST(CivilTime, FirstThursdayInMonth) { + const civil_day nov1(2014, 11, 1); + const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday); + EXPECT_EQ("2014-11-06", Format(thursday)); + + // Bonus: Date of Thanksgiving in the United States + // Rule: Fourth Thursday of November + const civil_day thanksgiving = thursday + 7 * 3; + EXPECT_EQ("2014-11-27", Format(thanksgiving)); +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_fixed.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_fixed.cc new file mode 100644 index 000000000000..303c0244a824 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_fixed.cc @@ -0,0 +1,140 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "time_zone_fixed.h" + +#include <algorithm> +#include <cassert> +#include <chrono> +#include <cstring> +#include <string> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +// The prefix used for the internal names of fixed-offset zones. +const char kFixedZonePrefix[] = "Fixed/UTC"; + +const char kDigits[] = "0123456789"; + +char* Format02d(char* p, int v) { + *p++ = kDigits[(v / 10) % 10]; + *p++ = kDigits[v % 10]; + return p; +} + +int Parse02d(const char* p) { + if (const char* ap = std::strchr(kDigits, *p)) { + int v = static_cast<int>(ap - kDigits); + if (const char* bp = std::strchr(kDigits, *++p)) { + return (v * 10) + static_cast<int>(bp - kDigits); + } + } + return -1; +} + +} // namespace + +bool FixedOffsetFromName(const std::string& name, seconds* offset) { + if (name.compare(0, std::string::npos, "UTC", 3) == 0) { + *offset = seconds::zero(); + return true; + } + + const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1; + const char* const ep = kFixedZonePrefix + prefix_len; + if (name.size() != prefix_len + 9) // <prefix>+99:99:99 + return false; + if (!std::equal(kFixedZonePrefix, ep, name.begin())) return false; + const char* np = name.data() + prefix_len; + if (np[0] != '+' && np[0] != '-') return false; + if (np[3] != ':' || np[6] != ':') // see note below about large offsets + return false; + + int hours = Parse02d(np + 1); + if (hours == -1) return false; + int mins = Parse02d(np + 4); + if (mins == -1) return false; + int secs = Parse02d(np + 7); + if (secs == -1) return false; + + secs += ((hours * 60) + mins) * 60; + if (secs > 24 * 60 * 60) return false; // outside supported offset range + *offset = seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west + return true; +} + +std::string FixedOffsetToName(const seconds& offset) { + if (offset == seconds::zero()) return "UTC"; + if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) { + // We don't support fixed-offset zones more than 24 hours + // away from UTC to avoid complications in rendering such + // offsets and to (somewhat) limit the total number of zones. + return "UTC"; + } + int offset_seconds = static_cast<int>(offset.count()); + const char sign = (offset_seconds < 0 ? '-' : '+'); + int offset_minutes = offset_seconds / 60; + offset_seconds %= 60; + if (sign == '-') { + if (offset_seconds > 0) { + offset_seconds -= 60; + offset_minutes += 1; + } + offset_seconds = -offset_seconds; + offset_minutes = -offset_minutes; + } + int offset_hours = offset_minutes / 60; + offset_minutes %= 60; + const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1; + char buf[prefix_len + sizeof("-24:00:00")]; + char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf); + *ep++ = sign; + ep = Format02d(ep, offset_hours); + *ep++ = ':'; + ep = Format02d(ep, offset_minutes); + *ep++ = ':'; + ep = Format02d(ep, offset_seconds); + *ep++ = '\0'; + assert(ep == buf + sizeof(buf)); + return buf; +} + +std::string FixedOffsetToAbbr(const seconds& offset) { + std::string abbr = FixedOffsetToName(offset); + const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1; + if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99 + abbr.erase(0, prefix_len); // +99:99:99 + abbr.erase(6, 1); // +99:9999 + abbr.erase(3, 1); // +999999 + if (abbr[5] == '0' && abbr[6] == '0') { // +999900 + abbr.erase(5, 2); // +9999 + if (abbr[3] == '0' && abbr[4] == '0') { // +9900 + abbr.erase(3, 2); // +99 + } + } + } + return abbr; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_fixed.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_fixed.h new file mode 100644 index 000000000000..e74a0bbd9dde --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_fixed.h @@ -0,0 +1,52 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_ + +#include <string> + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// Helper functions for dealing with the names and abbreviations +// of time zones that are a fixed offset (seconds east) from UTC. +// FixedOffsetFromName() extracts the offset from a valid fixed-offset +// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate +// the canonical zone name and abbreviation respectively for the given +// offset. +// +// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>". +// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the +// optional pieces are omitted when their values are zero. (Note that +// the sign is the opposite of that used in a POSIX TZ specification.) +// +// Note: FixedOffsetFromName() fails on syntax errors or when the parsed +// offset exceeds 24 hours. FixedOffsetToName() and FixedOffsetToAbbr() +// both produce "UTC" when the argument offset exceeds 24 hours. +bool FixedOffsetFromName(const std::string& name, seconds* offset); +std::string FixedOffsetToName(const seconds& offset); +std::string FixedOffsetToAbbr(const seconds& offset); + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_format.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_format.cc new file mode 100644 index 000000000000..d8cb047425ee --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_format.cc @@ -0,0 +1,1029 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if !defined(HAS_STRPTIME) +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#define HAS_STRPTIME 1 // assume everyone has strptime() except windows +#endif +#endif + +#if defined(HAS_STRPTIME) && HAS_STRPTIME +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE // Definedness suffices for strptime. +#endif +#endif + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +// Include time.h directly since, by C++ standards, ctime doesn't have to +// declare strptime. +#include <time.h> + +#include <cctype> +#include <chrono> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <ctime> +#include <limits> +#include <string> +#include <vector> +#if !HAS_STRPTIME +#include <iomanip> +#include <sstream> +#endif + +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "time_zone_if.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { +namespace detail { + +namespace { + +#if !HAS_STRPTIME +// Build a strptime() using C++11's std::get_time(). +char* strptime(const char* s, const char* fmt, std::tm* tm) { + std::istringstream input(s); + input >> std::get_time(tm, fmt); + if (input.fail()) return nullptr; + return const_cast<char*>(s) + + (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg())); +} +#endif + +// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0). +int ToTmWday(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*/ +} + +// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday. +weekday FromTmWday(int tm_wday) { + switch (tm_wday) { + case 0: + return weekday::sunday; + case 1: + return weekday::monday; + case 2: + return weekday::tuesday; + case 3: + return weekday::wednesday; + case 4: + return weekday::thursday; + case 5: + return weekday::friday; + case 6: + return weekday::saturday; + } + return weekday::sunday; /*NOTREACHED*/ +} + +std::tm ToTM(const time_zone::absolute_lookup& al) { + std::tm tm{}; + tm.tm_sec = al.cs.second(); + tm.tm_min = al.cs.minute(); + tm.tm_hour = al.cs.hour(); + tm.tm_mday = al.cs.day(); + tm.tm_mon = al.cs.month() - 1; + + // Saturate tm.tm_year is cases of over/underflow. + if (al.cs.year() < std::numeric_limits<int>::min() + 1900) { + tm.tm_year = std::numeric_limits<int>::min(); + } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) { + tm.tm_year = std::numeric_limits<int>::max(); + } else { + tm.tm_year = static_cast<int>(al.cs.year() - 1900); + } + + tm.tm_wday = ToTmWday(get_weekday(al.cs)); + tm.tm_yday = get_yearday(al.cs) - 1; + tm.tm_isdst = al.is_dst ? 1 : 0; + return tm; +} + +// Returns the week of the year [0:53] given a civil day and the day on +// which weeks are defined to start. +int ToWeek(const civil_day& cd, weekday week_start) { + const civil_day d(cd.year() % 400, cd.month(), cd.day()); + return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7); +} + +const char kDigits[] = "0123456789"; + +// Formats a 64-bit integer in the given field width. Note that it is up +// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure +// that there is sufficient space before ep to hold the conversion. +char* Format64(char* ep, int width, std::int_fast64_t v) { + bool neg = false; + if (v < 0) { + --width; + neg = true; + if (v == std::numeric_limits<std::int_fast64_t>::min()) { + // Avoid negating minimum value. + std::int_fast64_t last_digit = -(v % 10); + v /= 10; + if (last_digit < 0) { + ++v; + last_digit += 10; + } + --width; + *--ep = kDigits[last_digit]; + } + v = -v; + } + do { + --width; + *--ep = kDigits[v % 10]; + } while (v /= 10); + while (--width >= 0) *--ep = '0'; // zero pad + if (neg) *--ep = '-'; + return ep; +} + +// Formats [0 .. 99] as %02d. +char* Format02d(char* ep, int v) { + *--ep = kDigits[v % 10]; + *--ep = kDigits[(v / 10) % 10]; + return ep; +} + +// Formats a UTC offset, like +00:00. +char* FormatOffset(char* ep, int offset, const char* mode) { + // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and + // generate a "negative zero" when we're formatting a zero offset + // as the result of a failed load_time_zone(). + char sign = '+'; + if (offset < 0) { + offset = -offset; // bounded by 24h so no overflow + sign = '-'; + } + const int seconds = offset % 60; + const int minutes = (offset /= 60) % 60; + const int hours = offset /= 60; + const char sep = mode[0]; + const bool ext = (sep != '\0' && mode[1] == '*'); + const bool ccc = (ext && mode[2] == ':'); + if (ext && (!ccc || seconds != 0)) { + ep = Format02d(ep, seconds); + *--ep = sep; + } else { + // If we're not rendering seconds, sub-minute negative offsets + // should get a positive sign (e.g., offset=-10s => "+00:00"). + if (hours == 0 && minutes == 0) sign = '+'; + } + if (!ccc || minutes != 0 || seconds != 0) { + ep = Format02d(ep, minutes); + if (sep != '\0') *--ep = sep; + } + ep = Format02d(ep, hours); + *--ep = sign; + return ep; +} + +// Formats a std::tm using strftime(3). +void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) { + // strftime(3) returns the number of characters placed in the output + // array (which may be 0 characters). It also returns 0 to indicate + // an error, like the array wasn't large enough. To accommodate this, + // the following code grows the buffer size from 2x the format string + // length up to 32x. + for (std::size_t i = 2; i != 32; i *= 2) { + std::size_t buf_size = fmt.size() * i; + std::vector<char> buf(buf_size); + if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) { + out->append(&buf[0], len); + return; + } + } +} + +// Used for %E#S/%E#f specifiers and for data values in parse(). +template <typename T> +const char* ParseInt(const char* dp, int width, T min, T max, T* vp) { + if (dp != nullptr) { + const T kmin = std::numeric_limits<T>::min(); + bool erange = false; + bool neg = false; + T value = 0; + if (*dp == '-') { + neg = true; + if (width <= 0 || --width != 0) { + ++dp; + } else { + dp = nullptr; // width was 1 + } + } + if (const char* const bp = dp) { + while (const char* cp = strchr(kDigits, *dp)) { + int d = static_cast<int>(cp - kDigits); + if (d >= 10) break; + if (value < kmin / 10) { + erange = true; + break; + } + value *= 10; + if (value < kmin + d) { + erange = true; + break; + } + value -= d; + dp += 1; + if (width > 0 && --width == 0) break; + } + if (dp != bp && !erange && (neg || value != kmin)) { + if (!neg || value != 0) { + if (!neg) value = -value; // make positive + if (min <= value && value <= max) { + *vp = value; + } else { + dp = nullptr; + } + } else { + dp = nullptr; + } + } else { + dp = nullptr; + } + } + } + return dp; +} + +// The number of base-10 digits that can be represented by a signed 64-bit +// integer. That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1). +const int kDigits10_64 = 18; + +// 10^n for everything that can be represented by a signed 64-bit integer. +const std::int_fast64_t kExp10[kDigits10_64 + 1] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, +}; + +} // namespace + +// Uses strftime(3) to format the given Time. The following extended format +// specifiers are also supported: +// +// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) +// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) +// - %E#S - Seconds with # digits of fractional precision +// - %E*S - Seconds with full fractional precision (a literal '*') +// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// - %ET - The RFC3339 "date-time" separator "T" +// +// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are +// handled internally for performance reasons. strftime(3) is slow due to +// a POSIX requirement to respect changes to ${TZ}. +// +// The TZ/GNU %s extension is handled internally because strftime() has +// to use mktime() to generate it, and that assumes the local time zone. +// +// We also handle the %z and %Z specifiers to accommodate platforms that do +// not support the tm_gmtoff and tm_zone extensions to std::tm. +// +// Requires that zero() <= fs < seconds(1). +std::string format(const std::string& format, const time_point<seconds>& tp, + const detail::femtoseconds& fs, const time_zone& tz) { + std::string result; + result.reserve(format.size()); // A reasonable guess for the result size. + const time_zone::absolute_lookup al = tz.lookup(tp); + const std::tm tm = ToTM(al); + + // Scratch buffer for internal conversions. + char buf[3 + kDigits10_64]; // enough for longest conversion + char* const ep = buf + sizeof(buf); + char* bp; // works back from ep + + // Maintain three, disjoint subsequences that span format. + // [format.begin() ... pending) : already formatted into result + // [pending ... cur) : formatting pending, but no special cases + // [cur ... format.end()) : unexamined + // Initially, everything is in the unexamined part. + const char* pending = format.c_str(); // NUL terminated + const char* cur = pending; + const char* end = pending + format.length(); + + while (cur != end) { // while something is unexamined + // Moves cur to the next percent sign. + const char* start = cur; + while (cur != end && *cur != '%') ++cur; + + // If the new pending text is all ordinary, copy it out. + if (cur != start && pending == start) { + result.append(pending, static_cast<std::size_t>(cur - pending)); + pending = start = cur; + } + + // Span the sequential percent signs. + const char* percent = cur; + while (cur != end && *cur == '%') ++cur; + + // If the new pending text is all percents, copy out one + // percent for every matched pair, then skip those pairs. + if (cur != start && pending == start) { + std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2; + result.append(pending, escaped); + pending += escaped * 2; + // Also copy out a single trailing percent. + if (pending != cur && cur == end) { + result.push_back(*pending++); + } + } + + // Loop unless we have an unescaped percent. + if (cur == end || (cur - percent) % 2 == 0) continue; + + // Simple specifiers that we handle ourselves. + if (strchr("YmdeUuWwHMSzZs%", *cur)) { + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + switch (*cur) { + case 'Y': + // This avoids the tm.tm_year overflow problem for %Y, however + // tm.tm_year will still be used by other specifiers like %D. + bp = Format64(ep, 0, al.cs.year()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'm': + bp = Format02d(ep, al.cs.month()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'd': + case 'e': + bp = Format02d(ep, al.cs.day()); + if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'U': + bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday)); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'u': + bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'W': + bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday)); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'w': + bp = Format64(ep, 0, tm.tm_wday); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'H': + bp = Format02d(ep, al.cs.hour()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'M': + bp = Format02d(ep, al.cs.minute()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'S': + bp = Format02d(ep, al.cs.second()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'z': + bp = FormatOffset(ep, al.offset, ""); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case 'Z': + result.append(al.abbr); + break; + case 's': + bp = Format64(ep, 0, ToUnixSeconds(tp)); + result.append(bp, static_cast<std::size_t>(ep - bp)); + break; + case '%': + result.push_back('%'); + break; + } + pending = ++cur; + continue; + } + + // More complex specifiers that we handle ourselves. + if (*cur == ':' && cur + 1 != end) { + if (*(cur + 1) == 'z') { + // Formats %:z. + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + bp = FormatOffset(ep, al.offset, ":"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 2; + continue; + } + if (*(cur + 1) == ':' && cur + 2 != end) { + if (*(cur + 2) == 'z') { + // Formats %::z. + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + bp = FormatOffset(ep, al.offset, ":*"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 3; + continue; + } + if (*(cur + 2) == ':' && cur + 3 != end) { + if (*(cur + 3) == 'z') { + // Formats %:::z. + if (cur - 1 != pending) { + FormatTM(&result, std::string(pending, cur - 1), tm); + } + bp = FormatOffset(ep, al.offset, ":*:"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 4; + continue; + } + } + } + } + + // Loop if there is no E modifier. + if (*cur != 'E' || ++cur == end) continue; + + // Format our extensions. + if (*cur == 'T') { + // Formats %ET. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + result.append("T"); + pending = ++cur; + } else if (*cur == 'z') { + // Formats %Ez. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + bp = FormatOffset(ep, al.offset, ":"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = ++cur; + } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') { + // Formats %E*z. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + bp = FormatOffset(ep, al.offset, ":*"); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 2; + } else if (*cur == '*' && cur + 1 != end && + (*(cur + 1) == 'S' || *(cur + 1) == 'f')) { + // Formats %E*S or %E*F. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + char* cp = ep; + bp = Format64(cp, 15, fs.count()); + while (cp != bp && cp[-1] == '0') --cp; + switch (*(cur + 1)) { + case 'S': + if (cp != bp) *--bp = '.'; + bp = Format02d(bp, al.cs.second()); + break; + case 'f': + if (cp == bp) *--bp = '0'; + break; + } + result.append(bp, static_cast<std::size_t>(cp - bp)); + pending = cur += 2; + } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') { + // Formats %E4Y. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + bp = Format64(ep, 4, al.cs.year()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur += 2; + } else if (std::isdigit(*cur)) { + // Possibly found %E#S or %E#f. + int n = 0; + if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) { + if (*np == 'S' || *np == 'f') { + // Formats %E#S or %E#f. + if (cur - 2 != pending) { + FormatTM(&result, std::string(pending, cur - 2), tm); + } + bp = ep; + if (n > 0) { + if (n > kDigits10_64) n = kDigits10_64; + bp = Format64(bp, n, + (n > 15) ? fs.count() * kExp10[n - 15] + : fs.count() / kExp10[15 - n]); + if (*np == 'S') *--bp = '.'; + } + if (*np == 'S') bp = Format02d(bp, al.cs.second()); + result.append(bp, static_cast<std::size_t>(ep - bp)); + pending = cur = ++np; + } + } + } + } + + // Formats any remaining data. + if (end != pending) { + FormatTM(&result, std::string(pending, end), tm); + } + + return result; +} + +namespace { + +const char* ParseOffset(const char* dp, const char* mode, int* offset) { + if (dp != nullptr) { + const char first = *dp++; + if (first == '+' || first == '-') { + char sep = mode[0]; + int hours = 0; + int minutes = 0; + int seconds = 0; + const char* ap = ParseInt(dp, 2, 0, 23, &hours); + if (ap != nullptr && ap - dp == 2) { + dp = ap; + if (sep != '\0' && *ap == sep) ++ap; + const char* bp = ParseInt(ap, 2, 0, 59, &minutes); + if (bp != nullptr && bp - ap == 2) { + dp = bp; + if (sep != '\0' && *bp == sep) ++bp; + const char* cp = ParseInt(bp, 2, 0, 59, &seconds); + if (cp != nullptr && cp - bp == 2) dp = cp; + } + *offset = ((hours * 60 + minutes) * 60) + seconds; + if (first == '-') *offset = -*offset; + } else { + dp = nullptr; + } + } else if (first == 'Z' || first == 'z') { // Zulu + *offset = 0; + } else { + dp = nullptr; + } + } + return dp; +} + +const char* ParseZone(const char* dp, std::string* zone) { + zone->clear(); + if (dp != nullptr) { + while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++); + if (zone->empty()) dp = nullptr; + } + return dp; +} + +const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) { + if (dp != nullptr) { + std::int_fast64_t v = 0; + std::int_fast64_t exp = 0; + const char* const bp = dp; + while (const char* cp = strchr(kDigits, *dp)) { + int d = static_cast<int>(cp - kDigits); + if (d >= 10) break; + if (exp < 15) { + exp += 1; + v *= 10; + v += d; + } + ++dp; + } + if (dp != bp) { + v *= kExp10[15 - exp]; + *subseconds = detail::femtoseconds(v); + } else { + dp = nullptr; + } + } + return dp; +} + +// Parses a string into a std::tm using strptime(3). +const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) { + if (dp != nullptr) { + dp = strptime(dp, fmt, tm); + } + return dp; +} + +// 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. 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); + 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 + +// Uses strptime(3) to parse the given input. Supports the same extended +// format specifiers as format(), although %E#S and %E*S are treated +// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept +// the same inputs. %ET accepts either 'T' or 't'. +// +// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are +// handled internally so that we can normally avoid strptime() altogether +// (which is particularly helpful when the native implementation is broken). +// +// The TZ/GNU %s extension is handled internally because strptime() has to +// use localtime_r() to generate it, and that assumes the local time zone. +// +// We also handle the %z specifier to accommodate platforms that do not +// support the tm_gmtoff extension to std::tm. %Z is parsed but ignored. +bool parse(const std::string& format, const std::string& input, + const time_zone& tz, time_point<seconds>* sec, + detail::femtoseconds* fs, std::string* err) { + // The unparsed input. + const char* data = input.c_str(); // NUL terminated + + // Skips leading whitespace. + while (std::isspace(*data)) ++data; + + const year_t kyearmax = std::numeric_limits<year_t>::max(); + const year_t kyearmin = std::numeric_limits<year_t>::min(); + + // Sets default values for unspecified fields. + bool saw_year = false; + year_t year = 1970; + std::tm tm{}; + tm.tm_year = 1970 - 1900; + tm.tm_mon = 1 - 1; // Jan + tm.tm_mday = 1; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_wday = 4; // Thu + tm.tm_yday = 0; + tm.tm_isdst = 0; + auto subseconds = detail::femtoseconds::zero(); + bool saw_offset = false; + int offset = 0; // No offset from passed tz. + std::string zone = "UTC"; + + const char* fmt = format.c_str(); // NUL terminated + bool twelve_hour = false; + bool afternoon = false; + int week_num = -1; + weekday week_start = weekday::sunday; + + bool saw_percent_s = false; + std::int_fast64_t percent_s = 0; + + // Steps through format, one specifier at a time. + while (data != nullptr && *fmt != '\0') { + if (std::isspace(*fmt)) { + while (std::isspace(*data)) ++data; + while (std::isspace(*++fmt)) continue; + continue; + } + + if (*fmt != '%') { + if (*data == *fmt) { + ++data; + ++fmt; + } else { + data = nullptr; + } + continue; + } + + const char* percent = fmt; + if (*++fmt == '\0') { + data = nullptr; + continue; + } + switch (*fmt++) { + case 'Y': + // Symmetrically with FormatTime(), directly handing %Y avoids the + // tm.tm_year overflow problem. However, tm.tm_year will still be + // used by other specifiers like %D. + data = ParseInt(data, 0, kyearmin, kyearmax, &year); + if (data != nullptr) saw_year = true; + continue; + case 'm': + data = ParseInt(data, 2, 1, 12, &tm.tm_mon); + if (data != nullptr) tm.tm_mon -= 1; + week_num = -1; + continue; + case 'd': + case 'e': + data = ParseInt(data, 2, 1, 31, &tm.tm_mday); + week_num = -1; + continue; + case 'U': + data = ParseInt(data, 0, 0, 53, &week_num); + week_start = weekday::sunday; + continue; + case 'W': + data = ParseInt(data, 0, 0, 53, &week_num); + week_start = weekday::monday; + continue; + case 'u': + data = ParseInt(data, 0, 1, 7, &tm.tm_wday); + if (data != nullptr) tm.tm_wday %= 7; + continue; + case 'w': + data = ParseInt(data, 0, 0, 6, &tm.tm_wday); + continue; + case 'H': + data = ParseInt(data, 2, 0, 23, &tm.tm_hour); + twelve_hour = false; + continue; + case 'M': + data = ParseInt(data, 2, 0, 59, &tm.tm_min); + continue; + case 'S': + data = ParseInt(data, 2, 0, 60, &tm.tm_sec); + continue; + case 'I': + case 'l': + case 'r': // probably uses %I + twelve_hour = true; + break; + case 'R': // uses %H + case 'T': // uses %H + case 'c': // probably uses %H + case 'X': // probably uses %H + twelve_hour = false; + break; + case 'z': + data = ParseOffset(data, "", &offset); + if (data != nullptr) saw_offset = true; + continue; + case 'Z': // ignored; zone abbreviations are ambiguous + data = ParseZone(data, &zone); + continue; + case 's': + data = + ParseInt(data, 0, std::numeric_limits<std::int_fast64_t>::min(), + std::numeric_limits<std::int_fast64_t>::max(), &percent_s); + if (data != nullptr) saw_percent_s = true; + continue; + case ':': + if (fmt[0] == 'z' || + (fmt[0] == ':' && + (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) { + data = ParseOffset(data, ":", &offset); + if (data != nullptr) saw_offset = true; + fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3; + continue; + } + break; + case '%': + data = (*data == '%' ? data + 1 : nullptr); + continue; + case 'E': + if (fmt[0] == 'T') { + if (*data == 'T' || *data == 't') { + ++data; + ++fmt; + } else { + data = nullptr; + } + continue; + } + if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) { + data = ParseOffset(data, ":", &offset); + if (data != nullptr) saw_offset = true; + fmt += (fmt[0] == 'z') ? 1 : 2; + continue; + } + if (fmt[0] == '*' && fmt[1] == 'S') { + data = ParseInt(data, 2, 0, 60, &tm.tm_sec); + if (data != nullptr && *data == '.') { + data = ParseSubSeconds(data + 1, &subseconds); + } + fmt += 2; + continue; + } + if (fmt[0] == '*' && fmt[1] == 'f') { + if (data != nullptr && std::isdigit(*data)) { + data = ParseSubSeconds(data, &subseconds); + } + fmt += 2; + continue; + } + if (fmt[0] == '4' && fmt[1] == 'Y') { + const char* bp = data; + data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year); + if (data != nullptr) { + if (data - bp == 4) { + saw_year = true; + } else { + data = nullptr; // stopped too soon + } + } + fmt += 2; + continue; + } + if (std::isdigit(*fmt)) { + int n = 0; // value ignored + if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) { + if (*np == 'S') { + data = ParseInt(data, 2, 0, 60, &tm.tm_sec); + if (data != nullptr && *data == '.') { + data = ParseSubSeconds(data + 1, &subseconds); + } + fmt = ++np; + continue; + } + if (*np == 'f') { + if (data != nullptr && std::isdigit(*data)) { + data = ParseSubSeconds(data, &subseconds); + } + fmt = ++np; + continue; + } + } + } + if (*fmt == 'c') twelve_hour = false; // probably uses %H + if (*fmt == 'X') twelve_hour = false; // probably uses %H + if (*fmt != '\0') ++fmt; + break; + case 'O': + if (*fmt == 'H') twelve_hour = false; + if (*fmt == 'I') twelve_hour = true; + if (*fmt != '\0') ++fmt; + break; + } + + // Parses the current specifier. + const char* orig_data = data; + std::string spec(percent, static_cast<std::size_t>(fmt - percent)); + data = ParseTM(data, spec.c_str(), &tm); + + // If we successfully parsed %p we need to remember whether the result + // was AM or PM so that we can adjust tm_hour before time_zone::lookup(). + // So reparse the input with a known AM hour, and check if it is shifted + // to a PM hour. + if (spec == "%p" && data != nullptr) { + std::string test_input = "1"; + test_input.append(orig_data, static_cast<std::size_t>(data - orig_data)); + const char* test_data = test_input.c_str(); + std::tm tmp{}; + ParseTM(test_data, "%I%p", &tmp); + afternoon = (tmp.tm_hour == 13); + } + } + + // Adjust a 12-hour tm_hour value if it should be in the afternoon. + if (twelve_hour && afternoon && tm.tm_hour < 12) { + tm.tm_hour += 12; + } + + if (data == nullptr) { + if (err != nullptr) *err = "Failed to parse input"; + return false; + } + + // Skip any remaining whitespace. + while (std::isspace(*data)) ++data; + + // parse() must consume the entire input string. + if (*data != '\0') { + if (err != nullptr) *err = "Illegal trailing data in input string"; + return false; + } + + // If we saw %s then we ignore anything else and return that time. + if (saw_percent_s) { + *sec = FromUnixSeconds(percent_s); + *fs = detail::femtoseconds::zero(); + return true; + } + + // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields + // in UTC and then shift by that offset. Otherwise we want to interpret + // the fields directly in the passed time_zone. + time_zone ptz = saw_offset ? utc_time_zone() : tz; + + // Allows a leap second of 60 to normalize forward to the following ":00". + if (tm.tm_sec == 60) { + tm.tm_sec -= 1; + offset -= 1; + subseconds = detail::femtoseconds::zero(); + } + + if (!saw_year) { + year = year_t{tm.tm_year}; + if (year > kyearmax - 1900) { + // Platform-dependent, maybe unreachable. + if (err != nullptr) *err = "Out-of-range year"; + return false; + } + year += 1900; + } + + // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number. + 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); + + // parse() should not allow normalization. Due to the restricted field + // ranges above (see ParseInt()), the only possibility is for days to roll + // into months. That is, parsing "Sep 31" should not produce "Oct 1". + if (cs.month() != month || cs.day() != tm.tm_mday) { + if (err != nullptr) *err = "Out-of-range field"; + return false; + } + + // Accounts for the offset adjustment before converting to absolute time. + if ((offset < 0 && cs > civil_second::max() + offset) || + (offset > 0 && cs < civil_second::min() + offset)) { + if (err != nullptr) *err = "Out-of-range field"; + return false; + } + cs -= offset; + + const auto tp = ptz.lookup(cs).pre; + // Checks for overflow/underflow and returns an error as necessary. + if (tp == time_point<seconds>::max()) { + const auto al = ptz.lookup(time_point<seconds>::max()); + if (cs > al.cs) { + if (err != nullptr) *err = "Out-of-range field"; + return false; + } + } + if (tp == time_point<seconds>::min()) { + const auto al = ptz.lookup(time_point<seconds>::min()); + if (cs < al.cs) { + if (err != nullptr) *err = "Out-of-range field"; + return false; + } + } + + *sec = tp; + *fs = subseconds; + return true; +} + +} // namespace detail +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_format_test.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_format_test.cc new file mode 100644 index 000000000000..a11f93e2a597 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_format_test.cc @@ -0,0 +1,1603 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <chrono> +#include <iomanip> +#include <sstream> +#include <string> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +namespace chrono = std::chrono; + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +// This helper is a macro so that failed expectations show up with the +// correct line numbers. +#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \ + do { \ + time_zone::absolute_lookup al = tz.lookup(tp); \ + EXPECT_EQ(y, al.cs.year()); \ + EXPECT_EQ(m, al.cs.month()); \ + EXPECT_EQ(d, al.cs.day()); \ + EXPECT_EQ(hh, al.cs.hour()); \ + EXPECT_EQ(mm, al.cs.minute()); \ + EXPECT_EQ(ss, al.cs.second()); \ + EXPECT_EQ(off, al.offset); \ + EXPECT_TRUE(isdst == al.is_dst); \ + EXPECT_STREQ(zone, al.abbr); \ + } while (0) + +const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez"; +const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; + +const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z"; +const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z"; + +// A helper that tests the given format specifier by itself, and with leading +// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu"). +template <typename D> +void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt, + const std::string& ans) { + EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt; + EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz)); + EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz)); + EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz)); +} + +} // namespace + +// +// Testing format() +// + +TEST(Format, TimePointResolution) { + const char kFmt[] = "%H:%M:%E*S"; + const time_zone utc = utc_time_zone(); + const time_point<chrono::nanoseconds> t0 = + chrono::system_clock::from_time_t(1420167845) + + chrono::milliseconds(123) + chrono::microseconds(456) + + chrono::nanoseconds(789); + EXPECT_EQ( + "03:04:05.123456789", + format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc)); + EXPECT_EQ( + "03:04:05.123456", + format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc)); + EXPECT_EQ( + "03:04:05.123", + format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc)); + EXPECT_EQ("03:04:05", + format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc)); + EXPECT_EQ( + "03:04:05", + format(kFmt, + chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), + utc)); + EXPECT_EQ("03:04:00", + format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc)); + EXPECT_EQ("03:00:00", + format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc)); +} + +TEST(Format, TimePointExtendedResolution) { + const char kFmt[] = "%H:%M:%E*S"; + const time_zone utc = utc_time_zone(); + const time_point<absl::time_internal::cctz::seconds> tp = + chrono::time_point_cast<absl::time_internal::cctz::seconds>( + chrono::system_clock::from_time_t(0)) + + chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56); + + EXPECT_EQ( + "12:34:56.123456789012345", + detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc)); + EXPECT_EQ( + "12:34:56.012345678901234", + detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc)); + EXPECT_EQ("12:34:56.001234567890123", + detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc)); + EXPECT_EQ("12:34:56.000123456789012", + detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc)); + + EXPECT_EQ("12:34:56.000000000000123", + detail::format(kFmt, tp, detail::femtoseconds(123), utc)); + EXPECT_EQ("12:34:56.000000000000012", + detail::format(kFmt, tp, detail::femtoseconds(12), utc)); + EXPECT_EQ("12:34:56.000000000000001", + detail::format(kFmt, tp, detail::femtoseconds(1), utc)); +} + +TEST(Format, Basics) { + time_zone tz = utc_time_zone(); + time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); + + // Starts with a couple basic edge cases. + EXPECT_EQ("", format("", tp, tz)); + EXPECT_EQ(" ", format(" ", tp, tz)); + EXPECT_EQ(" ", format(" ", tp, tz)); + EXPECT_EQ("xxx", format("xxx", tp, tz)); + std::string big(128, 'x'); + EXPECT_EQ(big, format(big, tp, tz)); + // Cause the 1024-byte buffer to grow. + std::string bigger(100000, 'x'); + EXPECT_EQ(bigger, format(bigger, tp, tz)); + + tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5); + tp += chrono::milliseconds(6) + chrono::microseconds(7) + + chrono::nanoseconds(8); + EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz)); + EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz)); + EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz)); + EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz)); + EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz)); +} + +TEST(Format, PosixConversions) { + const time_zone tz = utc_time_zone(); + auto tp = chrono::system_clock::from_time_t(0); + + TestFormatSpecifier(tp, tz, "%d", "01"); + TestFormatSpecifier(tp, tz, "%e", " 1"); // extension but internal support + TestFormatSpecifier(tp, tz, "%H", "00"); + TestFormatSpecifier(tp, tz, "%I", "12"); + TestFormatSpecifier(tp, tz, "%j", "001"); + TestFormatSpecifier(tp, tz, "%m", "01"); + TestFormatSpecifier(tp, tz, "%M", "00"); + TestFormatSpecifier(tp, tz, "%S", "00"); + TestFormatSpecifier(tp, tz, "%U", "00"); +#if !defined(__EMSCRIPTEN__) + TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday +#endif + TestFormatSpecifier(tp, tz, "%W", "00"); + TestFormatSpecifier(tp, tz, "%y", "70"); + TestFormatSpecifier(tp, tz, "%Y", "1970"); + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%Z", "UTC"); + TestFormatSpecifier(tp, tz, "%%", "%"); + +#if defined(__linux__) + // SU/C99/TZ extensions + TestFormatSpecifier(tp, tz, "%C", "19"); + TestFormatSpecifier(tp, tz, "%D", "01/01/70"); + TestFormatSpecifier(tp, tz, "%F", "1970-01-01"); + TestFormatSpecifier(tp, tz, "%g", "70"); + TestFormatSpecifier(tp, tz, "%G", "1970"); + TestFormatSpecifier(tp, tz, "%k", " 0"); + TestFormatSpecifier(tp, tz, "%l", "12"); + TestFormatSpecifier(tp, tz, "%n", "\n"); + TestFormatSpecifier(tp, tz, "%R", "00:00"); + TestFormatSpecifier(tp, tz, "%t", "\t"); + TestFormatSpecifier(tp, tz, "%T", "00:00:00"); + TestFormatSpecifier(tp, tz, "%u", "4"); // 4=Thursday + TestFormatSpecifier(tp, tz, "%V", "01"); + TestFormatSpecifier(tp, tz, "%s", "0"); +#endif +} + +TEST(Format, LocaleSpecific) { + const time_zone tz = utc_time_zone(); + auto tp = chrono::system_clock::from_time_t(0); + + TestFormatSpecifier(tp, tz, "%a", "Thu"); + TestFormatSpecifier(tp, tz, "%A", "Thursday"); + TestFormatSpecifier(tp, tz, "%b", "Jan"); + TestFormatSpecifier(tp, tz, "%B", "January"); + + // %c should at least produce the numeric year and time-of-day. + const std::string s = format("%c", tp, utc_time_zone()); + EXPECT_THAT(s, testing::HasSubstr("1970")); + EXPECT_THAT(s, testing::HasSubstr("00:00:00")); + + TestFormatSpecifier(tp, tz, "%p", "AM"); + TestFormatSpecifier(tp, tz, "%x", "01/01/70"); + TestFormatSpecifier(tp, tz, "%X", "00:00:00"); + +#if defined(__linux__) + // SU/C99/TZ extensions + TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b + TestFormatSpecifier(tp, tz, "%P", "am"); + TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM"); + + // Modified conversion specifiers %E_ + TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan 1 00:00:00 1970"); + TestFormatSpecifier(tp, tz, "%EC", "19"); + TestFormatSpecifier(tp, tz, "%Ex", "01/01/70"); + TestFormatSpecifier(tp, tz, "%EX", "00:00:00"); + TestFormatSpecifier(tp, tz, "%Ey", "70"); + TestFormatSpecifier(tp, tz, "%EY", "1970"); + + // Modified conversion specifiers %O_ + TestFormatSpecifier(tp, tz, "%Od", "01"); + TestFormatSpecifier(tp, tz, "%Oe", " 1"); + TestFormatSpecifier(tp, tz, "%OH", "00"); + TestFormatSpecifier(tp, tz, "%OI", "12"); + TestFormatSpecifier(tp, tz, "%Om", "01"); + TestFormatSpecifier(tp, tz, "%OM", "00"); + TestFormatSpecifier(tp, tz, "%OS", "00"); + TestFormatSpecifier(tp, tz, "%Ou", "4"); // 4=Thursday + TestFormatSpecifier(tp, tz, "%OU", "00"); + TestFormatSpecifier(tp, tz, "%OV", "01"); + TestFormatSpecifier(tp, tz, "%Ow", "4"); // 4=Thursday + TestFormatSpecifier(tp, tz, "%OW", "00"); + TestFormatSpecifier(tp, tz, "%Oy", "70"); +#endif +} + +TEST(Format, Escaping) { + const time_zone tz = utc_time_zone(); + auto tp = chrono::system_clock::from_time_t(0); + + TestFormatSpecifier(tp, tz, "%%", "%"); + TestFormatSpecifier(tp, tz, "%%a", "%a"); + TestFormatSpecifier(tp, tz, "%%b", "%b"); + TestFormatSpecifier(tp, tz, "%%Ea", "%Ea"); + TestFormatSpecifier(tp, tz, "%%Es", "%Es"); + TestFormatSpecifier(tp, tz, "%%E3S", "%E3S"); + TestFormatSpecifier(tp, tz, "%%OS", "%OS"); + TestFormatSpecifier(tp, tz, "%%O3S", "%O3S"); + + // Multiple levels of escaping. + TestFormatSpecifier(tp, tz, "%%%Y", "%1970"); + TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000"); + TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S"); +} + +TEST(Format, ExtendedSeconds) { + const time_zone tz = utc_time_zone(); + + // No subseconds. + time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); + tp += chrono::seconds(5); + EXPECT_EQ("05", format("%E*S", tp, tz)); + EXPECT_EQ("05", format("%E0S", tp, tz)); + EXPECT_EQ("05.0", format("%E1S", tp, tz)); + EXPECT_EQ("05.00", format("%E2S", tp, tz)); + EXPECT_EQ("05.000", format("%E3S", tp, tz)); + EXPECT_EQ("05.0000", format("%E4S", tp, tz)); + EXPECT_EQ("05.00000", format("%E5S", tp, tz)); + EXPECT_EQ("05.000000", format("%E6S", tp, tz)); + EXPECT_EQ("05.0000000", format("%E7S", tp, tz)); + EXPECT_EQ("05.00000000", format("%E8S", tp, tz)); + EXPECT_EQ("05.000000000", format("%E9S", tp, tz)); + EXPECT_EQ("05.0000000000", format("%E10S", tp, tz)); + EXPECT_EQ("05.00000000000", format("%E11S", tp, tz)); + EXPECT_EQ("05.000000000000", format("%E12S", tp, tz)); + EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz)); + EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz)); + EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz)); + + // With subseconds. + tp += chrono::milliseconds(6) + chrono::microseconds(7) + + chrono::nanoseconds(8); + EXPECT_EQ("05.006007008", format("%E*S", tp, tz)); + EXPECT_EQ("05", format("%E0S", tp, tz)); + EXPECT_EQ("05.0", format("%E1S", tp, tz)); + EXPECT_EQ("05.00", format("%E2S", tp, tz)); + EXPECT_EQ("05.006", format("%E3S", tp, tz)); + EXPECT_EQ("05.0060", format("%E4S", tp, tz)); + EXPECT_EQ("05.00600", format("%E5S", tp, tz)); + EXPECT_EQ("05.006007", format("%E6S", tp, tz)); + EXPECT_EQ("05.0060070", format("%E7S", tp, tz)); + EXPECT_EQ("05.00600700", format("%E8S", tp, tz)); + EXPECT_EQ("05.006007008", format("%E9S", tp, tz)); + EXPECT_EQ("05.0060070080", format("%E10S", tp, tz)); + EXPECT_EQ("05.00600700800", format("%E11S", tp, tz)); + EXPECT_EQ("05.006007008000", format("%E12S", tp, tz)); + EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz)); + EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz)); + EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz)); + + // Times before the Unix epoch. + tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1); + EXPECT_EQ("1969-12-31 23:59:59.999999", + format("%Y-%m-%d %H:%M:%E*S", tp, tz)); + + // Here is a "%E*S" case we got wrong for a while. While the first + // instant below is correctly rendered as "...:07.333304", the second + // one used to appear as "...:07.33330499999999999". + tp = chrono::system_clock::from_time_t(0) + + chrono::microseconds(1395024427333304); + EXPECT_EQ("2014-03-17 02:47:07.333304", + format("%Y-%m-%d %H:%M:%E*S", tp, tz)); + tp += chrono::microseconds(1); + EXPECT_EQ("2014-03-17 02:47:07.333305", + format("%Y-%m-%d %H:%M:%E*S", tp, tz)); +} + +TEST(Format, ExtendedSubeconds) { + const time_zone tz = utc_time_zone(); + + // No subseconds. + time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); + tp += chrono::seconds(5); + EXPECT_EQ("0", format("%E*f", tp, tz)); + EXPECT_EQ("", format("%E0f", tp, tz)); + EXPECT_EQ("0", format("%E1f", tp, tz)); + EXPECT_EQ("00", format("%E2f", tp, tz)); + EXPECT_EQ("000", format("%E3f", tp, tz)); + EXPECT_EQ("0000", format("%E4f", tp, tz)); + EXPECT_EQ("00000", format("%E5f", tp, tz)); + EXPECT_EQ("000000", format("%E6f", tp, tz)); + EXPECT_EQ("0000000", format("%E7f", tp, tz)); + EXPECT_EQ("00000000", format("%E8f", tp, tz)); + EXPECT_EQ("000000000", format("%E9f", tp, tz)); + EXPECT_EQ("0000000000", format("%E10f", tp, tz)); + EXPECT_EQ("00000000000", format("%E11f", tp, tz)); + EXPECT_EQ("000000000000", format("%E12f", tp, tz)); + EXPECT_EQ("0000000000000", format("%E13f", tp, tz)); + EXPECT_EQ("00000000000000", format("%E14f", tp, tz)); + EXPECT_EQ("000000000000000", format("%E15f", tp, tz)); + + // With subseconds. + tp += chrono::milliseconds(6) + chrono::microseconds(7) + + chrono::nanoseconds(8); + EXPECT_EQ("006007008", format("%E*f", tp, tz)); + EXPECT_EQ("", format("%E0f", tp, tz)); + EXPECT_EQ("0", format("%E1f", tp, tz)); + EXPECT_EQ("00", format("%E2f", tp, tz)); + EXPECT_EQ("006", format("%E3f", tp, tz)); + EXPECT_EQ("0060", format("%E4f", tp, tz)); + EXPECT_EQ("00600", format("%E5f", tp, tz)); + EXPECT_EQ("006007", format("%E6f", tp, tz)); + EXPECT_EQ("0060070", format("%E7f", tp, tz)); + EXPECT_EQ("00600700", format("%E8f", tp, tz)); + EXPECT_EQ("006007008", format("%E9f", tp, tz)); + EXPECT_EQ("0060070080", format("%E10f", tp, tz)); + EXPECT_EQ("00600700800", format("%E11f", tp, tz)); + EXPECT_EQ("006007008000", format("%E12f", tp, tz)); + EXPECT_EQ("0060070080000", format("%E13f", tp, tz)); + EXPECT_EQ("00600700800000", format("%E14f", tp, tz)); + EXPECT_EQ("006007008000000", format("%E15f", tp, tz)); + + // Times before the Unix epoch. + tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1); + EXPECT_EQ("1969-12-31 23:59:59.999999", + format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); + + // Here is a "%E*S" case we got wrong for a while. While the first + // instant below is correctly rendered as "...:07.333304", the second + // one used to appear as "...:07.33330499999999999". + tp = chrono::system_clock::from_time_t(0) + + chrono::microseconds(1395024427333304); + EXPECT_EQ("2014-03-17 02:47:07.333304", + format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); + tp += chrono::microseconds(1); + EXPECT_EQ("2014-03-17 02:47:07.333305", + format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); +} + +TEST(Format, CompareExtendSecondsVsSubseconds) { + const time_zone tz = utc_time_zone(); + + // This test case illustrates the differences/similarities between: + // fmt_A: %E<prec>S + // fmt_B: %S.%E<prec>f + auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; }; + auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; }; + + // No subseconds: + time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0); + tp += chrono::seconds(5); + // ... %E*S and %S.%E*f are different. + EXPECT_EQ("05", format(fmt_A("*"), tp, tz)); + EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz)); + // ... %E0S and %S.%E0f are different. + EXPECT_EQ("05", format(fmt_A("0"), tp, tz)); + EXPECT_EQ("05.", format(fmt_B("0"), tp, tz)); + // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15]. + for (int prec = 1; prec <= 15; ++prec) { + const std::string a = format(fmt_A(std::to_string(prec)), tp, tz); + const std::string b = format(fmt_B(std::to_string(prec)), tp, tz); + EXPECT_EQ(a, b) << "prec=" << prec; + } + + // With subseconds: + // ... %E*S and %S.%E*f are the same. + tp += chrono::milliseconds(6) + chrono::microseconds(7) + + chrono::nanoseconds(8); + EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz)); + EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz)); + // ... %E0S and %S.%E0f are different. + EXPECT_EQ("05", format(fmt_A("0"), tp, tz)); + EXPECT_EQ("05.", format(fmt_B("0"), tp, tz)); + // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15]. + for (int prec = 1; prec <= 15; ++prec) { + const std::string a = format(fmt_A(std::to_string(prec)), tp, tz); + const std::string b = format(fmt_B(std::to_string(prec)), tp, tz); + EXPECT_EQ(a, b) << "prec=" << prec; + } +} + +TEST(Format, ExtendedOffset) { + const auto tp = chrono::system_clock::from_time_t(0); + + auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero()); + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%:z", "+00:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); + + tz = fixed_time_zone(chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%:z", "+00:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); + + tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00 + TestFormatSpecifier(tp, tz, "%z", "+0000"); + TestFormatSpecifier(tp, tz, "%:z", "+00:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); + + tz = fixed_time_zone(chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "+0034"); + TestFormatSpecifier(tp, tz, "%:z", "+00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:34"); + + tz = fixed_time_zone(-chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "-0034"); + TestFormatSpecifier(tp, tz, "%:z", "-00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-00:34"); + + tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+0034"); + TestFormatSpecifier(tp, tz, "%:z", "+00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+00:34"); + + tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "-0034"); + TestFormatSpecifier(tp, tz, "%:z", "-00:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-00:34"); + + tz = fixed_time_zone(chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%z", "+1200"); + TestFormatSpecifier(tp, tz, "%:z", "+12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:00"); + + tz = fixed_time_zone(-chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%z", "-1200"); + TestFormatSpecifier(tp, tz, "%:z", "-12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:00"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+1200"); + TestFormatSpecifier(tp, tz, "%:z", "+12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:00"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "-1200"); + TestFormatSpecifier(tp, tz, "%:z", "-12:00"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:00"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "+1234"); + TestFormatSpecifier(tp, tz, "%:z", "+12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:34"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%z", "-1234"); + TestFormatSpecifier(tp, tz, "%:z", "-12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:34"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) + + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "+1234"); + TestFormatSpecifier(tp, tz, "%:z", "+12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "+12:34"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) - + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%z", "-1234"); + TestFormatSpecifier(tp, tz, "%:z", "-12:34"); + TestFormatSpecifier(tp, tz, "%Ez", "-12:34"); +} + +TEST(Format, ExtendedSecondOffset) { + const auto tp = chrono::system_clock::from_time_t(0); + + auto tz = fixed_time_zone(absl::time_internal::cctz::seconds::zero()); + TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00"); + TestFormatSpecifier(tp, tz, "%::z", "+00:00:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+00"); + + tz = fixed_time_zone(chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "+00:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56"); + + tz = fixed_time_zone(-chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "-00:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56"); + + tz = fixed_time_zone(chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "+00:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+00:34"); + + tz = fixed_time_zone(-chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "-00:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "-00:34"); + + tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "+00:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56"); + + tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "-00:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56"); + + tz = fixed_time_zone(chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00"); + TestFormatSpecifier(tp, tz, "%::z", "+12:00:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+12"); + + tz = fixed_time_zone(-chrono::hours(12)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00"); + TestFormatSpecifier(tp, tz, "%::z", "-12:00:00"); + TestFormatSpecifier(tp, tz, "%:::z", "-12"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "+12:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56"); + TestFormatSpecifier(tp, tz, "%::z", "-12:00:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "+12:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "+12:34"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00"); + TestFormatSpecifier(tp, tz, "%::z", "-12:34:00"); + TestFormatSpecifier(tp, tz, "%:::z", "-12:34"); + + tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) + + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "+12:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56"); + + tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) - + chrono::seconds(56)); + TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56"); + TestFormatSpecifier(tp, tz, "%::z", "-12:34:56"); + TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56"); +} + +TEST(Format, ExtendedYears) { + const time_zone utc = utc_time_zone(); + const char e4y_fmt[] = "%E4Y%m%d"; // no separators + + // %E4Y zero-pads the year to produce at least 4 chars, including the sign. + auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("00001127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("00011127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("00091127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("00991127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("09991127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("99991127", format(e4y_fmt, tp, utc)); + + // When the year is outside [-999:9999], more than 4 chars are produced. + tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc)); + tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc); + EXPECT_EQ("100001127", format(e4y_fmt, tp, utc)); +} + +TEST(Format, RFC3339Format) { + time_zone tz; + EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); + + time_point<chrono::nanoseconds> tp = + convert(civil_second(1977, 6, 28, 9, 8, 7), tz); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::milliseconds(100); + EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::milliseconds(20); + EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::milliseconds(3); + EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::microseconds(400); + EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::microseconds(50); + EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::microseconds(6); + EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::nanoseconds(700); + EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::nanoseconds(80); + EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); + + tp += chrono::nanoseconds(9); + EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00", + format(RFC3339_full, tp, tz)); + EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz)); +} + +TEST(Format, RFC1123Format) { // locale specific + time_zone tz; + EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); + + auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); + EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz)); + EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz)); +} + +TEST(Format, Week) { + const time_zone utc = utc_time_zone(); + + auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc); + EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc)); + + tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc); + EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc)); + + tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc); + EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc)); + + tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc); + EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc)); + + tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc); + EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc)); + + tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc); + EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc)); + EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc)); +} + +// +// Testing parse() +// + +TEST(Parse, TimePointResolution) { + const char kFmt[] = "%H:%M:%E*S"; + const time_zone utc = utc_time_zone(); + + time_point<chrono::nanoseconds> tp_ns; + EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns)); + EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc)); + EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns)); + EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc)); + + time_point<chrono::microseconds> tp_us; + EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us)); + EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc)); + EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us)); + EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc)); + EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us)); + EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc)); + + time_point<chrono::milliseconds> tp_ms; + EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms)); + EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc)); + EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms)); + EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc)); + EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms)); + EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc)); + + time_point<chrono::seconds> tp_s; + EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s)); + EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc)); + EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s)); + EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc)); + + time_point<chrono::minutes> tp_m; + EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m)); + EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc)); + + time_point<chrono::hours> tp_h; + EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h)); + EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc)); +} + +TEST(Parse, TimePointExtendedResolution) { + const char kFmt[] = "%H:%M:%E*S"; + const time_zone utc = utc_time_zone(); + + time_point<absl::time_internal::cctz::seconds> tp; + detail::femtoseconds fs; + EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs)); + EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc)); + EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs)); + EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc)); + EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs)); + EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc)); + EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs)); + EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc)); + EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs)); + EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc)); + EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs)); + EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc)); +} + +TEST(Parse, Basics) { + time_zone tz = utc_time_zone(); + time_point<chrono::nanoseconds> tp = + chrono::system_clock::from_time_t(1234567890); + + // Simple edge cases. + EXPECT_TRUE(parse("", "", tz, &tp)); + EXPECT_EQ(chrono::system_clock::from_time_t(0), tp); // everything defaulted + EXPECT_TRUE(parse(" ", " ", tz, &tp)); + EXPECT_TRUE(parse(" ", " ", tz, &tp)); + EXPECT_TRUE(parse("x", "x", tz, &tp)); + EXPECT_TRUE(parse("xxx", "xxx", tz, &tp)); + + EXPECT_TRUE( + parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp)); + ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC"); +} + +TEST(Parse, WithTimeZone) { + time_zone tz; + EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); + time_point<chrono::nanoseconds> tp; + + // We can parse a string without a UTC offset if we supply a timezone. + EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp)); + ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT"); + + // But the timezone is ignored when a UTC offset is present. + EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800", + utc_time_zone(), &tp)); + ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT"); + + // Check a skipped time (a Spring DST transition). parse() uses the + // pre-transition offset. + EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp)); + ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT"); + + // Check a repeated time (a Fall DST transition). parse() uses the + // pre-transition offset. + EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp)); + ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT"); +} + +TEST(Parse, LeapSecond) { + time_zone tz; + EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); + time_point<chrono::nanoseconds> tp; + + // ":59" -> ":59" + EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp)); + ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT"); + + // ":59.5" -> ":59.5" + EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp)); + ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT"); + + // ":60" -> ":00" + EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp)); + ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT"); + + // ":60.5" -> ":00.0" + EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp)); + ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT"); + + // ":61" -> error + EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp)); +} + +TEST(Parse, ErrorCases) { + const time_zone tz = utc_time_zone(); + auto tp = chrono::system_clock::from_time_t(0); + + // Illegal trailing data. + EXPECT_FALSE(parse("%S", "123", tz, &tp)); + + // Can't parse an illegal format specifier. + EXPECT_FALSE(parse("%Q", "x", tz, &tp)); + + // Fails because of trailing, unparsed data "blah". + EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp)); + + // Trailing whitespace is allowed. + EXPECT_TRUE(parse("%m-%d", "2-3 ", tz, &tp)); + EXPECT_EQ(2, convert(tp, utc_time_zone()).month()); + EXPECT_EQ(3, convert(tp, utc_time_zone()).day()); + + // Feb 31 requires normalization. + EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp)); + + // Check that we cannot have spaces in UTC offsets. + EXPECT_TRUE(parse("%z", "-0203", tz, &tp)); + EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp)); + EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp)); + EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp)); + + // Check that we reject other malformed UTC offsets. + EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp)); + EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp)); + + // Check that we do not accept "-0" in fields that allow zero. + EXPECT_FALSE(parse("%Y", "-0", tz, &tp)); + EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp)); + EXPECT_FALSE(parse("%H", "-0", tz, &tp)); + EXPECT_FALSE(parse("%M", "-0", tz, &tp)); + EXPECT_FALSE(parse("%S", "-0", tz, &tp)); + EXPECT_FALSE(parse("%z", "+-000", tz, &tp)); + EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp)); + EXPECT_FALSE(parse("%z", "-00-0", tz, &tp)); + EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp)); +} + +TEST(Parse, PosixConversions) { + time_zone tz = utc_time_zone(); + auto tp = chrono::system_clock::from_time_t(0); + const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); + + tp = reset; + EXPECT_TRUE(parse("%d", "15", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).day()); + + // %e is an extension, but is supported internally. + tp = reset; + EXPECT_TRUE(parse("%e", "15", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d + + tp = reset; + EXPECT_TRUE(parse("%H", "17", tz, &tp)); + EXPECT_EQ(17, convert(tp, tz).hour()); + + tp = reset; + EXPECT_TRUE(parse("%I", "5", tz, &tp)); + EXPECT_EQ(5, convert(tp, tz).hour()); + + // %j is parsed but ignored. + EXPECT_TRUE(parse("%j", "32", tz, &tp)); + + tp = reset; + EXPECT_TRUE(parse("%m", "11", tz, &tp)); + EXPECT_EQ(11, convert(tp, tz).month()); + + tp = reset; + EXPECT_TRUE(parse("%M", "33", tz, &tp)); + EXPECT_EQ(33, convert(tp, tz).minute()); + + tp = reset; + EXPECT_TRUE(parse("%S", "55", tz, &tp)); + EXPECT_EQ(55, convert(tp, tz).second()); + + // %U is parsed but ignored. + EXPECT_TRUE(parse("%U", "15", tz, &tp)); + + // %w is parsed but ignored. + EXPECT_TRUE(parse("%w", "2", tz, &tp)); + + // %W is parsed but ignored. + EXPECT_TRUE(parse("%W", "22", tz, &tp)); + + tp = reset; + EXPECT_TRUE(parse("%y", "04", tz, &tp)); + EXPECT_EQ(2004, convert(tp, tz).year()); + + tp = reset; + EXPECT_TRUE(parse("%Y", "2004", tz, &tp)); + EXPECT_EQ(2004, convert(tp, tz).year()); + + EXPECT_TRUE(parse("%%", "%", tz, &tp)); + +#if defined(__linux__) + // SU/C99/TZ extensions + + // Because we handle each (non-internal) specifier in a separate call + // to strptime(), there is no way to group %C and %y together. So we + // just skip the %C/%y case. +#if 0 + tp = reset; + EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp)); + EXPECT_EQ(2004, convert(tp, tz).year()); +#endif + + tp = reset; + EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp)); + EXPECT_EQ(2, convert(tp, tz).month()); + EXPECT_EQ(3, convert(tp, tz).day()); + EXPECT_EQ(2004, convert(tp, tz).year()); + + EXPECT_TRUE(parse("%n", "\n", tz, &tp)); + + tp = reset; + EXPECT_TRUE(parse("%R", "03:44", tz, &tp)); + EXPECT_EQ(3, convert(tp, tz).hour()); + EXPECT_EQ(44, convert(tp, tz).minute()); + + EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp)); + + tp = reset; + EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp)); + EXPECT_EQ(3, convert(tp, tz).hour()); + EXPECT_EQ(44, convert(tp, tz).minute()); + EXPECT_EQ(55, convert(tp, tz).second()); + + tp = reset; + EXPECT_TRUE(parse("%s", "1234567890", tz, &tp)); + EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp); + + // %s conversion, like %z/%Ez, pays no heed to the optional zone. + time_zone lax; + EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax)); + tp = reset; + EXPECT_TRUE(parse("%s", "1234567890", lax, &tp)); + EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp); + + // This is most important when the time has the same YMDhms + // breakdown in the zone as some other time. For example, ... + // 1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT) + // 1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST) + tp = reset; + EXPECT_TRUE(parse("%s", "1414917000", lax, &tp)); + EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp); + tp = reset; + EXPECT_TRUE(parse("%s", "1414920600", lax, &tp)); + EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp); +#endif +} + +TEST(Parse, LocaleSpecific) { + time_zone tz = utc_time_zone(); + auto tp = chrono::system_clock::from_time_t(0); + const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz); + + // %a is parsed but ignored. + EXPECT_TRUE(parse("%a", "Mon", tz, &tp)); + + // %A is parsed but ignored. + EXPECT_TRUE(parse("%A", "Monday", tz, &tp)); + + tp = reset; + EXPECT_TRUE(parse("%b", "Feb", tz, &tp)); + EXPECT_EQ(2, convert(tp, tz).month()); + + tp = reset; + EXPECT_TRUE(parse("%B", "February", tz, &tp)); + EXPECT_EQ(2, convert(tp, tz).month()); + + // %p is parsed but ignored if it's alone. But it's used with %I. + EXPECT_TRUE(parse("%p", "AM", tz, &tp)); + tp = reset; + EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp)); + EXPECT_EQ(17, convert(tp, tz).hour()); + + tp = reset; + EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp)); + if (convert(tp, tz).month() == 2) { + EXPECT_EQ(3, convert(tp, tz).day()); + } else { + EXPECT_EQ(2, convert(tp, tz).day()); + EXPECT_EQ(3, convert(tp, tz).month()); + } + EXPECT_EQ(2004, convert(tp, tz).year()); + + tp = reset; + EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).hour()); + EXPECT_EQ(44, convert(tp, tz).minute()); + EXPECT_EQ(55, convert(tp, tz).second()); + +#if defined(__linux__) + // SU/C99/TZ extensions + + tp = reset; + EXPECT_TRUE(parse("%h", "Feb", tz, &tp)); + EXPECT_EQ(2, convert(tp, tz).month()); // Equivalent to %b + + tp = reset; + EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp)); + EXPECT_EQ(17, convert(tp, tz).hour()); + + tp = reset; + EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).hour()); + EXPECT_EQ(44, convert(tp, tz).minute()); + EXPECT_EQ(55, convert(tp, tz).second()); + + tp = reset; + EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp)); + EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp); + + // Modified conversion specifiers %E_ + + tp = reset; + EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp)); + EXPECT_EQ(2, convert(tp, tz).month()); + EXPECT_EQ(3, convert(tp, tz).day()); + EXPECT_EQ(2004, convert(tp, tz).year()); + + tp = reset; + EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).hour()); + EXPECT_EQ(44, convert(tp, tz).minute()); + EXPECT_EQ(55, convert(tp, tz).second()); + + // %Ey, the year offset from %EC, doesn't really make sense alone as there + // is no way to represent it in tm_year (%EC is not simply the century). + // Yet, because we handle each (non-internal) specifier in a separate call + // to strptime(), there is no way to group %EC and %Ey either. So we just + // skip the %EC and %Ey cases. + + tp = reset; + EXPECT_TRUE(parse("%EY", "2004", tz, &tp)); + EXPECT_EQ(2004, convert(tp, tz).year()); + + // Modified conversion specifiers %O_ + + tp = reset; + EXPECT_TRUE(parse("%Od", "15", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).day()); + + tp = reset; + EXPECT_TRUE(parse("%Oe", "15", tz, &tp)); + EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d + + tp = reset; + EXPECT_TRUE(parse("%OH", "17", tz, &tp)); + EXPECT_EQ(17, convert(tp, tz).hour()); + + tp = reset; + EXPECT_TRUE(parse("%OI", "5", tz, &tp)); + EXPECT_EQ(5, convert(tp, tz).hour()); + + tp = reset; + EXPECT_TRUE(parse("%Om", "11", tz, &tp)); + EXPECT_EQ(11, convert(tp, tz).month()); + + tp = reset; + EXPECT_TRUE(parse("%OM", "33", tz, &tp)); + EXPECT_EQ(33, convert(tp, tz).minute()); + + tp = reset; + EXPECT_TRUE(parse("%OS", "55", tz, &tp)); + EXPECT_EQ(55, convert(tp, tz).second()); + + // %OU is parsed but ignored. + EXPECT_TRUE(parse("%OU", "15", tz, &tp)); + + // %Ow is parsed but ignored. + EXPECT_TRUE(parse("%Ow", "2", tz, &tp)); + + // %OW is parsed but ignored. + EXPECT_TRUE(parse("%OW", "22", tz, &tp)); + + tp = reset; + EXPECT_TRUE(parse("%Oy", "04", tz, &tp)); + EXPECT_EQ(2004, convert(tp, tz).year()); +#endif +} + +TEST(Parse, ExtendedSeconds) { + const time_zone tz = utc_time_zone(); + const time_point<chrono::nanoseconds> unix_epoch = + chrono::system_clock::from_time_t(0); + + // All %E<prec>S cases are treated the same as %E*S on input. + auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15"}; + for (const std::string& prec : precisions) { + const std::string fmt = "%E" + prec + "S"; + SCOPED_TRACE(fmt); + time_point<chrono::nanoseconds> tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "5", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.0", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.00", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.6", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.60", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.600", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.67", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.670", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "05.678", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp); + } + + // Here is a "%E*S" case we got wrong for a while. The fractional + // part of the first instant is less than 2^31 and was correctly + // parsed, while the second (and any subsecond field >=2^31) failed. + time_point<chrono::nanoseconds> tp = unix_epoch; + EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); + tp = unix_epoch; + EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); + + // We should also be able to specify long strings of digits far + // beyond the current resolution and have them convert the same way. + tp = unix_epoch; + EXPECT_TRUE(parse( + "%E*S", "0.214748364801234567890123456789012345678901234567890123456789", + tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); +} + +TEST(Parse, ExtendedSecondsScan) { + const time_zone tz = utc_time_zone(); + time_point<chrono::nanoseconds> tp; + for (int ms = 0; ms < 1000; ms += 111) { + for (int us = 0; us < 1000; us += 27) { + const int micros = ms * 1000 + us; + for (int ns = 0; ns < 1000; ns += 9) { + const auto expected = chrono::system_clock::from_time_t(0) + + chrono::nanoseconds(micros * 1000 + ns); + std::ostringstream oss; + oss << "0." << std::setfill('0') << std::setw(3); + oss << ms << std::setw(3) << us << std::setw(3) << ns; + const std::string input = oss.str(); + EXPECT_TRUE(parse("%E*S", input, tz, &tp)); + EXPECT_EQ(expected, tp) << input; + } + } + } +} + +TEST(Parse, ExtendedSubeconds) { + const time_zone tz = utc_time_zone(); + const time_point<chrono::nanoseconds> unix_epoch = + chrono::system_clock::from_time_t(0); + + // All %E<prec>f cases are treated the same as %E*f on input. + auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", "10", "11", "12", "13", "14", "15"}; + for (const std::string& prec : precisions) { + const std::string fmt = "%E" + prec + "f"; + SCOPED_TRACE(fmt); + time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1); + EXPECT_TRUE(parse(fmt, "", tz, &tp)); + EXPECT_EQ(unix_epoch, tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "6", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "60", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "600", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "67", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "670", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "678", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp); + tp = unix_epoch; + EXPECT_TRUE(parse(fmt, "6789", tz, &tp)); + EXPECT_EQ( + unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp); + } + + // Here is a "%E*f" case we got wrong for a while. The fractional + // part of the first instant is less than 2^31 and was correctly + // parsed, while the second (and any subsecond field >=2^31) failed. + time_point<chrono::nanoseconds> tp = unix_epoch; + EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); + tp = unix_epoch; + EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); + + // We should also be able to specify long strings of digits far + // beyond the current resolution and have them convert the same way. + tp = unix_epoch; + EXPECT_TRUE(parse( + "%E*f", "214748364801234567890123456789012345678901234567890123456789", + tz, &tp)); + EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp); +} + +TEST(Parse, ExtendedSubecondsScan) { + time_point<chrono::nanoseconds> tp; + const time_zone tz = utc_time_zone(); + for (int ms = 0; ms < 1000; ms += 111) { + for (int us = 0; us < 1000; us += 27) { + const int micros = ms * 1000 + us; + for (int ns = 0; ns < 1000; ns += 9) { + std::ostringstream oss; + oss << std::setfill('0') << std::setw(3) << ms; + oss << std::setw(3) << us << std::setw(3) << ns; + const std::string nanos = oss.str(); + const auto expected = chrono::system_clock::from_time_t(0) + + chrono::nanoseconds(micros * 1000 + ns); + for (int ps = 0; ps < 1000; ps += 250) { + std::ostringstream ps_oss; + oss << std::setfill('0') << std::setw(3) << ps; + const std::string input = nanos + ps_oss.str() + "999"; + EXPECT_TRUE(parse("%E*f", input, tz, &tp)); + EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input; + } + } + } + } +} + +TEST(Parse, ExtendedOffset) { + const time_zone utc = utc_time_zone(); + time_point<absl::time_internal::cctz::seconds> tp; + + EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp)); + + for (auto fmt : {"%Ez", "%z"}) { + EXPECT_TRUE(parse(fmt, "+0000", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-123", utc, &tp)); + + EXPECT_TRUE(parse(fmt, "+00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-1", utc, &tp)); + } +} + +TEST(Parse, ExtendedSecondOffset) { + const time_zone utc = utc_time_zone(); + time_point<absl::time_internal::cctz::seconds> tp; + + for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) { + EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); + EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); + EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp)); + + EXPECT_TRUE(parse(fmt, "+000000", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-123456", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp); + EXPECT_TRUE(parse(fmt, "+123456", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp); + EXPECT_FALSE(parse(fmt, "-12345", utc, &tp)); + + EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp)); + + EXPECT_TRUE(parse(fmt, "+0000", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+1234", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-123", utc, &tp)); + + EXPECT_TRUE(parse(fmt, "+00", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "-12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); + EXPECT_TRUE(parse(fmt, "+12", utc, &tp)); + EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); + EXPECT_FALSE(parse(fmt, "-1", utc, &tp)); + } +} + +TEST(Parse, ExtendedYears) { + const time_zone utc = utc_time_zone(); + const char e4y_fmt[] = "%E4Y%m%d"; // no separators + time_point<absl::time_internal::cctz::seconds> tp; + + // %E4Y consumes exactly four chars, including any sign. + EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp)); + EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp)); + EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp)); + EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp)); + EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp)); + EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp)); + EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp)); + EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp)); + EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp)); + EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp); + EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp)); + EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp); + + // When the year is outside [-999:9999], the parse fails. + EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp)); + EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp)); +} + +TEST(Parse, RFC3339Format) { + const time_zone tz = utc_time_zone(); + time_point<chrono::nanoseconds> tp; + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp)); + ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC"); + + // Check that %ET also accepts "t". + time_point<chrono::nanoseconds> tp2; + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2)); + EXPECT_EQ(tp, tp2); + + // Check that %Ez also accepts "Z" as a synonym for "+00:00". + time_point<chrono::nanoseconds> tp3; + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3)); + EXPECT_EQ(tp, tp3); + + // Check that %Ez also accepts "z" as a synonym for "+00:00". + time_point<chrono::nanoseconds> tp4; + EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4)); + EXPECT_EQ(tp, tp4); +} + +TEST(Parse, Week) { + const time_zone utc = utc_time_zone(); + time_point<absl::time_internal::cctz::seconds> tp; + + auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp)); + EXPECT_EQ(exp, tp); + + exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp)); + EXPECT_EQ(exp, tp); + + exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp)); + EXPECT_EQ(exp, tp); + + exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp)); + EXPECT_EQ(exp, tp); + + exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp)); + EXPECT_EQ(exp, tp); + + exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp)); + EXPECT_EQ(exp, tp); +} + +TEST(Parse, WeekYearShift) { + // %U/%W conversions with week values in {0, 52, 53} can slip + // into the previous/following calendar years. + const time_zone utc = utc_time_zone(); + time_point<absl::time_internal::cctz::seconds> tp; + + auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp)); + EXPECT_EQ(exp, tp); + EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp)); + EXPECT_EQ(exp, tp); + + exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc); + EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp)); + 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) { + const time_zone utc = utc_time_zone(); + time_point<absl::time_internal::cctz::seconds> tp; + + // tests the upper limit using +00:00 offset + EXPECT_TRUE( + parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::max()); + EXPECT_FALSE( + parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp)); + + // tests the upper limit using -01:00 offset + EXPECT_TRUE( + parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp)); + EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::max()); + EXPECT_FALSE( + parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp)); + + // tests the lower limit using +00:00 offset + EXPECT_TRUE( + parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp)); + EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::min()); + EXPECT_FALSE( + parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp)); + + // tests the lower limit using +01:00 offset + EXPECT_TRUE( + parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp)); + EXPECT_EQ(tp, time_point<absl::time_internal::cctz::seconds>::min()); + EXPECT_FALSE( + parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp)); + + // tests max/min civil-second overflow + EXPECT_FALSE( + parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01", utc, &tp)); + EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01", + utc, &tp)); + + // TODO: Add tests that parsing times with fractional seconds overflow + // appropriately. This can't be done until cctz::parse() properly detects + // overflow when combining the chrono seconds and femto. +} + +// +// Roundtrip test for format()/parse(). +// + +TEST(FormatParse, RoundTrip) { + time_zone lax; + EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax)); + const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax); + const auto subseconds = chrono::nanoseconds(654321); + + // RFC3339, which renders subseconds. + { + time_point<chrono::nanoseconds> out; + const std::string s = format(RFC3339_full, in + subseconds, lax); + EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s; + EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez + } + + // RFC1123, which only does whole seconds. + { + time_point<chrono::nanoseconds> out; + const std::string s = format(RFC1123_full, in, lax); + EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s; + EXPECT_EQ(in, out); // RFC1123_full includes %z + } + +#if defined(_WIN32) || defined(_WIN64) + // Initial investigations indicate the %c does not roundtrip on Windows. + // TODO: Figure out what is going on here (perhaps a locale problem). +#elif defined(__EMSCRIPTEN__) + // strftime() and strptime() use different defintions for "%c" under + // emscripten (see https://github.com/kripken/emscripten/pull/7491), + // causing its round-trip test to fail. +#else + // Even though we don't know what %c will produce, it should roundtrip, + // but only in the 0-offset timezone. + { + time_point<chrono::nanoseconds> out; + time_zone utc = utc_time_zone(); + const std::string s = format("%c", in, utc); + EXPECT_TRUE(parse("%c", s, utc, &out)) << s; + EXPECT_EQ(in, out); + } +#endif +} + +TEST(FormatParse, RoundTripDistantFuture) { + const time_zone utc = utc_time_zone(); + const time_point<absl::time_internal::cctz::seconds> in = + time_point<absl::time_internal::cctz::seconds>::max(); + const std::string s = format(RFC3339_full, in, utc); + time_point<absl::time_internal::cctz::seconds> out; + EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; + EXPECT_EQ(in, out); +} + +TEST(FormatParse, RoundTripDistantPast) { + const time_zone utc = utc_time_zone(); + const time_point<absl::time_internal::cctz::seconds> in = + time_point<absl::time_internal::cctz::seconds>::min(); + const std::string s = format(RFC3339_full, in, utc); + time_point<absl::time_internal::cctz::seconds> out; + EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; + EXPECT_EQ(in, out); +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_if.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_if.cc new file mode 100644 index 000000000000..0319b2f98e67 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_if.cc @@ -0,0 +1,45 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "time_zone_if.h" + +#include "absl/base/config.h" +#include "time_zone_info.h" +#include "time_zone_libc.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +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. + if (name.compare(0, 5, "libc:") == 0) { + return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5))); + } + + // Otherwise use the "zoneinfo" implementation by default. + std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo); + if (!tz->Load(name)) tz.reset(); + return std::unique_ptr<TimeZoneIf>(tz.release()); +} + +// Defined out-of-line to avoid emitting a weak vtable in all TUs. +TimeZoneIf::~TimeZoneIf() {} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_if.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_if.h new file mode 100644 index 000000000000..32c0891c1e77 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_if.h @@ -0,0 +1,76 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_ + +#include <chrono> +#include <cstdint> +#include <memory> +#include <string> + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// A simple interface used to hide time-zone complexities from time_zone::Impl. +// Subclasses implement the functions for civil-time conversions in the zone. +class TimeZoneIf { + public: + // A factory function for TimeZoneIf implementations. + static std::unique_ptr<TimeZoneIf> Load(const std::string& name); + + virtual ~TimeZoneIf(); + + virtual time_zone::absolute_lookup BreakTime( + const time_point<seconds>& tp) const = 0; + virtual time_zone::civil_lookup MakeTime(const civil_second& cs) const = 0; + + virtual bool NextTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const = 0; + virtual bool PrevTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const = 0; + + virtual std::string Version() const = 0; + virtual std::string Description() const = 0; + + protected: + TimeZoneIf() {} +}; + +// Convert between time_point<seconds> and a count of seconds since the +// Unix epoch. We assume that the std::chrono::system_clock and the +// Unix clock are second aligned, but not that they share an epoch. +inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) { + return (tp - std::chrono::time_point_cast<seconds>( + std::chrono::system_clock::from_time_t(0))) + .count(); +} +inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) { + return std::chrono::time_point_cast<seconds>( + std::chrono::system_clock::from_time_t(0)) + + seconds(t); +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_impl.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_impl.cc new file mode 100644 index 000000000000..f34e3aec84d6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_impl.cc @@ -0,0 +1,113 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "time_zone_impl.h" + +#include <deque> +#include <memory> +#include <mutex> +#include <string> +#include <unordered_map> +#include <utility> + +#include "absl/base/config.h" +#include "time_zone_fixed.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +// time_zone::Impls are linked into a map to support fast lookup by name. +using TimeZoneImplByName = + std::unordered_map<std::string, const time_zone::Impl*>; +TimeZoneImplByName* time_zone_map = nullptr; + +// Mutual exclusion for time_zone_map. +std::mutex& TimeZoneMutex() { + // This mutex is intentionally "leaked" to avoid the static deinitialization + // order fiasco (std::mutex's destructor is not trivial on many platforms). + static std::mutex* time_zone_mutex = new std::mutex; + return *time_zone_mutex; +} + +} // namespace + +time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); } + +bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) { + const Impl* const utc_impl = UTCImpl(); + + // Check for UTC (which is never a key in time_zone_map). + auto offset = seconds::zero(); + if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) { + *tz = time_zone(utc_impl); + return true; + } + + // Check whether the time zone has already been loaded. + { + std::lock_guard<std::mutex> lock(TimeZoneMutex()); + if (time_zone_map != nullptr) { + TimeZoneImplByName::const_iterator itr = time_zone_map->find(name); + if (itr != time_zone_map->end()) { + *tz = time_zone(itr->second); + return itr->second != utc_impl; + } + } + } + + // Load the new time zone (outside the lock). + std::unique_ptr<const Impl> new_impl(new Impl(name)); + + // Add the new time zone to the map. + std::lock_guard<std::mutex> lock(TimeZoneMutex()); + if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName; + const Impl*& impl = (*time_zone_map)[name]; + if (impl == nullptr) { // this thread won any load race + impl = new_impl->zone_ ? new_impl.release() : utc_impl; + } + *tz = time_zone(impl); + return impl != utc_impl; +} + +void time_zone::Impl::ClearTimeZoneMapTestOnly() { + std::lock_guard<std::mutex> lock(TimeZoneMutex()); + if (time_zone_map != nullptr) { + // Existing time_zone::Impl* entries are in the wild, so we can't delete + // them. Instead, we move them to a private container, where they are + // logically unreachable but not "leaked". Future requests will result + // in reloading the data. + static auto* cleared = new std::deque<const time_zone::Impl*>; + for (const auto& element : *time_zone_map) { + cleared->push_back(element.second); + } + time_zone_map->clear(); + } +} + +time_zone::Impl::Impl(const std::string& name) + : name_(name), zone_(TimeZoneIf::Load(name_)) {} + +const time_zone::Impl* time_zone::Impl::UTCImpl() { + static const Impl* utc_impl = new Impl("UTC"); // never fails + return utc_impl; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_impl.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_impl.h new file mode 100644 index 000000000000..7d747ba96617 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_impl.h @@ -0,0 +1,93 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_ + +#include <memory> +#include <string> + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" +#include "time_zone_if.h" +#include "time_zone_info.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// time_zone::Impl is the internal object referenced by a cctz::time_zone. +class time_zone::Impl { + public: + // The UTC time zone. Also used for other time zones that fail to load. + static time_zone UTC(); + + // Load a named time zone. Returns false if the name is invalid, or if + // some other kind of error occurs. Note that loading "UTC" never fails. + static bool LoadTimeZone(const std::string& name, time_zone* tz); + + // Clears the map of cached time zones. Primarily for use in benchmarks + // that gauge the performance of loading/parsing the time-zone data. + static void ClearTimeZoneMapTestOnly(); + + // The primary key is the time-zone ID (e.g., "America/New_York"). + const std::string& Name() const { + // TODO: It would nice if the zoneinfo data included the zone name. + return name_; + } + + // Breaks a time_point down to civil-time components in this time zone. + time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const { + return zone_->BreakTime(tp); + } + + // Converts the civil-time components in this time zone into a time_point. + // That is, the opposite of BreakTime(). The requested civil time may be + // ambiguous or illegal due to a change of UTC offset. + time_zone::civil_lookup MakeTime(const civil_second& cs) const { + return zone_->MakeTime(cs); + } + + // Finds the time of the next/previous offset change in this time zone. + bool NextTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const { + return zone_->NextTransition(tp, trans); + } + bool PrevTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const { + return zone_->PrevTransition(tp, trans); + } + + // Returns an implementation-defined version string for this time zone. + std::string Version() const { return zone_->Version(); } + + // Returns an implementation-defined description of this time zone. + std::string Description() const { return zone_->Description(); } + + private: + explicit Impl(const std::string& name); + static const Impl* UTCImpl(); + + const std::string name_; + std::unique_ptr<TimeZoneIf> zone_; +}; + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_info.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_info.cc new file mode 100644 index 000000000000..8039353e585e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_info.cc @@ -0,0 +1,965 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file implements the TimeZoneIf interface using the "zoneinfo" +// data provided by the IANA Time Zone Database (i.e., the only real game +// in town). +// +// TimeZoneInfo represents the history of UTC-offset changes within a time +// zone. Most changes are due to daylight-saving rules, but occasionally +// shifts are made to the time-zone's base offset. The database only attempts +// to be definitive for times since 1970, so be wary of local-time conversions +// before that. Also, rule and zone-boundary changes are made at the whim +// of governments, so the conversion of future times needs to be taken with +// a grain of salt. +// +// For more information see tzfile(5), http://www.iana.org/time-zones, or +// https://en.wikipedia.org/wiki/Zoneinfo. +// +// Note that we assume the proleptic Gregorian calendar and 60-second +// minutes throughout. + +#include "time_zone_info.h" + +#include <algorithm> +#include <cassert> +#include <chrono> +#include <cstdint> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <functional> +#include <memory> +#include <sstream> +#include <string> + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "time_zone_fixed.h" +#include "time_zone_posix.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +inline bool IsLeap(year_t year) { + return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); +} + +// The number of days in non-leap and leap years respectively. +const std::int_least32_t kDaysPerYear[2] = {365, 366}; + +// The day offsets of the beginning of each (1-based) month in non-leap and +// leap years respectively (e.g., 335 days before December in a leap year). +const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = { + {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, + {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}, +}; + +// We reject leap-second encoded zoneinfo and so assume 60-second minutes. +const std::int_least32_t kSecsPerDay = 24 * 60 * 60; + +// 400-year chunks always have 146097 days (20871 weeks). +const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay; + +// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay. +const std::int_least32_t kSecsPerYear[2] = { + 365 * kSecsPerDay, + 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; +} + +// Multi-byte, numeric values are encoded using a MSB first, +// twos-complement representation. These helpers decode, from +// the given address, 4-byte and 8-byte values respectively. +// Note: If int_fastXX_t == intXX_t and this machine is not +// twos complement, then there will be at least one input value +// we cannot represent. +std::int_fast32_t Decode32(const char* cp) { + std::uint_fast32_t v = 0; + for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++); + const std::int_fast32_t s32max = 0x7fffffff; + const auto s32maxU = static_cast<std::uint_fast32_t>(s32max); + if (v <= s32maxU) return static_cast<std::int_fast32_t>(v); + return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1; +} + +std::int_fast64_t Decode64(const char* cp) { + std::uint_fast64_t v = 0; + for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++); + const std::int_fast64_t s64max = 0x7fffffffffffffff; + const auto s64maxU = static_cast<std::uint_fast64_t>(s64max); + if (v <= s64maxU) return static_cast<std::int_fast64_t>(v); + return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1; +} + +// Generate a year-relative offset for a PosixTransition. +std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday, + const PosixTransition& pt) { + std::int_fast64_t days = 0; + switch (pt.date.fmt) { + case PosixTransition::J: { + days = pt.date.j.day; + if (!leap_year || days < kMonthOffsets[1][3]) days -= 1; + break; + } + case PosixTransition::N: { + days = pt.date.n.day; + break; + } + case PosixTransition::M: { + const bool last_week = (pt.date.m.week == 5); + days = kMonthOffsets[leap_year][pt.date.m.month + last_week]; + const std::int_fast64_t weekday = (jan1_weekday + days) % 7; + if (last_week) { + days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1; + } else { + days += (pt.date.m.weekday + 7 - weekday) % 7; + days += (pt.date.m.week - 1) * 7; + } + break; + } + } + return (days * kSecsPerDay) + pt.time.offset; +} + +inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) { + time_zone::civil_lookup cl; + cl.kind = time_zone::civil_lookup::UNIQUE; + cl.pre = cl.trans = cl.post = tp; + return cl; +} + +inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) { + return MakeUnique(FromUnixSeconds(unix_time)); +} + +inline time_zone::civil_lookup MakeSkipped(const Transition& tr, + const civil_second& cs) { + time_zone::civil_lookup cl; + cl.kind = time_zone::civil_lookup::SKIPPED; + cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec)); + cl.trans = FromUnixSeconds(tr.unix_time); + cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs)); + return cl; +} + +inline time_zone::civil_lookup MakeRepeated(const Transition& tr, + const civil_second& cs) { + time_zone::civil_lookup cl; + cl.kind = time_zone::civil_lookup::REPEATED; + cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs)); + cl.trans = FromUnixSeconds(tr.unix_time); + cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec)); + return cl; +} + +inline civil_second YearShift(const civil_second& cs, year_t shift) { + return civil_second(cs.year() + shift, cs.month(), cs.day(), cs.hour(), + cs.minute(), cs.second()); +} + +} // namespace + +// What (no leap-seconds) UTC+seconds zoneinfo would look like. +bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { + transition_types_.resize(1); + TransitionType& tt(transition_types_.back()); + tt.utc_offset = static_cast<std::int_least32_t>(offset.count()); + tt.is_dst = false; + tt.abbr_index = 0; + + // 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), // 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 + 1514764800LL, // 2018-01-01T00:00:00+00:00 + 1546300800LL, // 2019-01-01T00:00:00+00:00 + 1577836800LL, // 2020-01-01T00:00:00+00:00 + 1609459200LL, // 2021-01-01T00:00:00+00:00 + 1640995200LL, // 2022-01-01T00:00:00+00:00 + 1672531200LL, // 2023-01-01T00:00:00+00:00 + 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; + tr.type_index = 0; + tr.civil_sec = LocalTime(tr.unix_time, tt).cs; + tr.prev_civil_sec = tr.civil_sec - 1; + } + + default_transition_type_ = 0; + abbreviations_ = FixedOffsetToAbbr(offset); + 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; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + + transitions_.shrink_to_fit(); + return true; +} + +// Builds the in-memory header using the raw bytes from the file. +bool TimeZoneInfo::Header::Build(const tzhead& tzh) { + std::int_fast32_t v; + if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false; + timecnt = static_cast<std::size_t>(v); + if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false; + typecnt = static_cast<std::size_t>(v); + if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false; + charcnt = static_cast<std::size_t>(v); + if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false; + leapcnt = static_cast<std::size_t>(v); + if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false; + ttisstdcnt = static_cast<std::size_t>(v); + if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false; + ttisutcnt = static_cast<std::size_t>(v); + return true; +} + +// How many bytes of data are associated with this header. The result +// depends upon whether this is a section with 4-byte or 8-byte times. +std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const { + std::size_t len = 0; + len += (time_len + 1) * timecnt; // unix_time + type_index + len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index + len += 1 * charcnt; // abbreviations + len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC + len += 1 * ttisstdcnt; // UTC/local indicators + len += 1 * ttisutcnt; // standard/wall indicators + return len; +} + +// 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). +bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index, + std::uint_fast8_t tt2_index) const { + if (tt1_index == tt2_index) return true; + const TransitionType& tt1(transition_types_[tt1_index]); + const TransitionType& tt2(transition_types_[tt2_index]); + 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. +bool TimeZoneInfo::ExtendTransitions() { + extended_ = false; + if (future_spec_.empty()) return true; // last transition prevails + + PosixTimeZone posix; + 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); + } + + // 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. + // We may need two additional transitions for the current year. + transitions_.reserve(transitions_.size() + 400 * 2 + 2); + extended_ = true; + + 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_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_ + 1); + } + + return true; +} + +bool TimeZoneInfo::Load(ZoneInfoSource* zip) { + // Read and validate the header. + tzhead tzh; + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + Header hdr; + if (!hdr.Build(tzh)) return false; + std::size_t time_len = 4; + if (tzh.tzh_version[0] != '\0') { + // Skip the 4-byte data. + if (zip->Skip(hdr.DataLength(time_len)) != 0) return false; + // Read and validate the header for the 8-byte data. + if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false; + if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0) + return false; + if (tzh.tzh_version[0] == '\0') return false; + if (!hdr.Build(tzh)) return false; + time_len = 8; + } + if (hdr.typecnt == 0) return false; + if (hdr.leapcnt != 0) { + // This code assumes 60-second minutes so we do not want + // the leap-second encoded zoneinfo. We could reverse the + // compensation, but the "right" encoding is rarely used + // so currently we simply reject such data. + return false; + } + if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false; + if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false; + + // Read the data into a local buffer. + std::size_t len = hdr.DataLength(time_len); + std::vector<char> tbuf(len); + if (zip->Read(tbuf.data(), len) != len) return false; + const char* bp = tbuf.data(); + + // Decode and validate the transitions. + 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); + bp += time_len; + if (i != 0) { + // Check that the transitions are ordered by time (as zic guarantees). + if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i])) + return false; // out of order + } + } + bool seen_type_0 = false; + for (std::size_t i = 0; i != hdr.timecnt; ++i) { + transitions_[i].type_index = Decode8(bp++); + if (transitions_[i].type_index >= hdr.typecnt) return false; + if (transitions_[i].type_index == 0) seen_type_0 = true; + } + + // 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 = + static_cast<std::int_least32_t>(Decode32(bp)); + if (transition_types_[i].utc_offset >= kSecsPerDay || + transition_types_[i].utc_offset <= -kSecsPerDay) + return false; + bp += 4; + transition_types_[i].is_dst = (Decode8(bp++) != 0); + transition_types_[i].abbr_index = Decode8(bp++); + if (transition_types_[i].abbr_index >= hdr.charcnt) return false; + } + + // Determine the before-first-transition type. + default_transition_type_ = 0; + if (seen_type_0 && hdr.timecnt != 0) { + std::uint_fast8_t index = 0; + if (transition_types_[0].is_dst) { + index = transitions_[0].type_index; + while (index != 0 && transition_types_[index].is_dst) --index; + } + while (index != hdr.typecnt && transition_types_[index].is_dst) ++index; + if (index != hdr.typecnt) default_transition_type_ = index; + } + + // Copy all the abbreviations. + abbreviations_.reserve(hdr.charcnt + 10); + abbreviations_.assign(bp, hdr.charcnt); + bp += hdr.charcnt; + + // Skip the unused portions. We've already dispensed with leap-second + // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when + // interpreting a POSIX spec that does not include start/end rules, and + // that isn't the case here (see "zic -p"). + bp += (8 + 4) * hdr.leapcnt; // leap-time + TAI-UTC + bp += 1 * hdr.ttisstdcnt; // UTC/local indicators + bp += 1 * hdr.ttisutcnt; // standard/wall indicators + assert(bp == tbuf.data() + tbuf.size()); + + future_spec_.clear(); + if (tzh.tzh_version[0] != '\0') { + // Snarf up the NL-enclosed future POSIX spec. Note + // that version '3' files utilize an extended format. + auto get_char = [](ZoneInfoSource* azip) -> int { + unsigned char ch; // all non-EOF results are positive + return (azip->Read(&ch, 1) == 1) ? ch : EOF; + }; + if (get_char(zip) != '\n') return false; + for (int c = get_char(zip); c != '\n'; c = get_char(zip)) { + if (c == EOF) return false; + future_spec_.push_back(static_cast<char>(c)); + } + } + + // We don't check for EOF so that we're forwards compatible. + + // If we did not find version information during the standard loading + // process (as of tzh_version '3' that is unsupported), then ask the + // ZoneInfoSource for any out-of-bound version string it may be privy to. + if (version_.empty()) { + version_ = zip->Version(); + } + + // Trim redundant transitions. zic may have added these to work around + // differences between the glibc and reference implementations (see + // zic.c:dontmerge) and the Qt library (see zic.c:WORK_AROUND_QTBUG_53071). + // For us, they just get in the way when we do future_spec_ extension. + while (hdr.timecnt > 1) { + if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index, + transitions_[hdr.timecnt - 2].type_index)) { + break; + } + hdr.timecnt -= 1; + } + transitions_.resize(hdr.timecnt); + + // Ensure that there is always a transition in the first half of the + // 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); // -18267312070-10-26T17:01:52+00:00 + tr.type_index = default_transition_type_; + } + + // Extend the transitions using the future specification. + 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(). + const TransitionType* ttp = &transition_types_[default_transition_type_]; + for (std::size_t i = 0; i != transitions_.size(); ++i) { + Transition& tr(transitions_[i]); + tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1; + ttp = &transition_types_[tr.type_index]; + tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs; + if (i != 0) { + // Check that the transitions are ordered by civil time. Essentially + // this means that an offset change cannot cross another such change. + // No one does this in practice, and we depend on it in MakeTime(). + if (!Transition::ByCivilTime()(transitions_[i - 1], tr)) + return false; // out of order + } + } + + // Compute the maximum/minimum civil times that can be converted to a + // time_point<seconds> for each of the zone's transition types. + for (auto& tt : transition_types_) { + tt.civil_max = LocalTime(seconds::max().count(), tt).cs; + tt.civil_min = LocalTime(seconds::min().count(), tt).cs; + } + + transitions_.shrink_to_fit(); + return true; +} + +namespace { + +// fopen(3) adaptor. +inline FILE* FOpen(const char* path, const char* mode) { +#if defined(_MSC_VER) + FILE* fp; + if (fopen_s(&fp, path, mode) != 0) fp = nullptr; + return fp; +#else + return fopen(path, mode); // TODO: Enable the close-on-exec flag. +#endif +} + +// A stdio(3)-backed implementation of ZoneInfoSource. +class FileZoneInfoSource : public ZoneInfoSource { + public: + static std::unique_ptr<ZoneInfoSource> Open(const std::string& name); + + std::size_t Read(void* ptr, std::size_t size) override { + size = std::min(size, len_); + std::size_t nread = fread(ptr, 1, size, fp_.get()); + len_ -= nread; + return nread; + } + int Skip(std::size_t offset) override { + offset = std::min(offset, len_); + int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR); + if (rc == 0) len_ -= offset; + return rc; + } + std::string Version() const override { + // TODO: It would nice if the zoneinfo data included the tzdb version. + return std::string(); + } + + protected: + explicit FileZoneInfoSource( + FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max()) + : fp_(fp, fclose), len_(len) {} + + private: + std::unique_ptr<FILE, int (*)(FILE*)> fp_; + std::size_t len_; +}; + +std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open( + const std::string& name) { + // Use of the "file:" prefix is intended for testing purposes only. + const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0; + + // Map the time-zone name to a path name. + std::string path; + if (pos == name.size() || name[pos] != '/') { + const char* tzdir = "/usr/share/zoneinfo"; + char* tzdir_env = nullptr; +#if defined(_MSC_VER) + _dupenv_s(&tzdir_env, nullptr, "TZDIR"); +#else + tzdir_env = std::getenv("TZDIR"); +#endif + if (tzdir_env && *tzdir_env) tzdir = tzdir_env; + path += tzdir; + path += '/'; +#if defined(_MSC_VER) + free(tzdir_env); +#endif + } + path.append(name, pos, std::string::npos); + + // Open the zoneinfo file. + FILE* fp = FOpen(path.c_str(), "rb"); + if (fp == nullptr) return nullptr; + std::size_t length = 0; + if (fseek(fp, 0, SEEK_END) == 0) { + long offset = ftell(fp); + if (offset >= 0) { + length = static_cast<std::size_t>(offset); + } + rewind(fp); + } + return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length)); +} + +class AndroidZoneInfoSource : public FileZoneInfoSource { + public: + static std::unique_ptr<ZoneInfoSource> Open(const std::string& name); + std::string Version() const override { return version_; } + + private: + explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers) + : FileZoneInfoSource(fp, len), version_(vers) {} + std::string version_; +}; + +std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open( + const std::string& name) { + // Use of the "file:" prefix is intended for testing purposes only. + const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0; + + // See Android's libc/tzcode/bionic.cpp for additional information. + for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata", + "/system/usr/share/zoneinfo/tzdata"}) { + std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose); + if (fp.get() == nullptr) continue; + + char hbuf[24]; // covers header.zonetab_offset too + if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue; + if (strncmp(hbuf, "tzdata", 6) != 0) continue; + const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : ""; + const std::int_fast32_t index_offset = Decode32(hbuf + 12); + const std::int_fast32_t data_offset = Decode32(hbuf + 16); + if (index_offset < 0 || data_offset < index_offset) continue; + if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0) + continue; + + char ebuf[52]; // covers entry.unused too + const std::size_t index_size = + static_cast<std::size_t>(data_offset - index_offset); + const std::size_t zonecnt = index_size / sizeof(ebuf); + if (zonecnt * sizeof(ebuf) != index_size) continue; + for (std::size_t i = 0; i != zonecnt; ++i) { + if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break; + const std::int_fast32_t start = data_offset + Decode32(ebuf + 40); + const std::int_fast32_t length = Decode32(ebuf + 44); + if (start < 0 || length < 0) break; + ebuf[40] = '\0'; // ensure zone name is NUL terminated + if (strcmp(name.c_str() + pos, ebuf) == 0) { + if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break; + return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource( + fp.release(), static_cast<std::size_t>(length), vers)); + } + } + } + + return nullptr; +} + +} // namespace + +bool TimeZoneInfo::Load(const std::string& name) { + // We can ensure that the loading of UTC or any other fixed-offset + // zone never fails because the simple, fixed-offset state can be + // internally generated. Note that this depends on our choice to not + // accept leap-second encoded ("right") zoneinfo. + auto offset = seconds::zero(); + if (FixedOffsetFromName(name, &offset)) { + return ResetToBuiltinUTC(offset); + } + + // Find and use a ZoneInfoSource to load the named zone. + auto zip = cctz_extension::zone_info_source_factory( + 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(zip.get()); +} + +// BreakTime() translation for a particular transition type. +time_zone::absolute_lookup TimeZoneInfo::LocalTime( + std::int_fast64_t unix_time, const TransitionType& tt) const { + // A civil time in "+offset" looks like (time+offset) in UTC. + // Note: We perform two additions in the civil_second domain to + // sidestep the chance of overflow in (unix_time + tt.utc_offset). + return {(civil_second() + unix_time) + tt.utc_offset, tt.utc_offset, + tt.is_dst, &abbreviations_[tt.abbr_index]}; +} + +// BreakTime() translation for a particular transition. +time_zone::absolute_lookup TimeZoneInfo::LocalTime(std::int_fast64_t unix_time, + const Transition& tr) const { + const TransitionType& tt = transition_types_[tr.type_index]; + // Note: (unix_time - tr.unix_time) will never overflow as we + // have ensured that there is always a "nearby" transition. + return {tr.civil_sec + (unix_time - tr.unix_time), // TODO: Optimize. + tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]}; +} + +// MakeTime() translation with a conversion-preserving +N * 400-year shift. +time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs, + year_t c4_shift) const { + assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_); + time_zone::civil_lookup cl = MakeTime(cs); + if (c4_shift > seconds::max().count() / kSecsPer400Years) { + cl.pre = cl.trans = cl.post = time_point<seconds>::max(); + } else { + const auto offset = seconds(c4_shift * kSecsPer400Years); + const auto limit = time_point<seconds>::max() - offset; + for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) { + if (*tp > limit) { + *tp = time_point<seconds>::max(); + } else { + *tp += offset; + } + } + } + return cl; +} + +time_zone::absolute_lookup TimeZoneInfo::BreakTime( + const time_point<seconds>& tp) const { + std::int_fast64_t unix_time = ToUnixSeconds(tp); + const std::size_t timecnt = transitions_.size(); + assert(timecnt != 0); // We always add a transition. + + if (unix_time < transitions_[0].unix_time) { + return LocalTime(unix_time, transition_types_[default_transition_type_]); + } + if (unix_time >= transitions_[timecnt - 1].unix_time) { + // After the last transition. If we extended the transitions using + // future_spec_, shift back to a supported year using the 400-year + // cycle of calendaric equivalence and then compensate accordingly. + if (extended_) { + const std::int_fast64_t diff = + unix_time - transitions_[timecnt - 1].unix_time; + const year_t shift = diff / kSecsPer400Years + 1; + const auto d = seconds(shift * kSecsPer400Years); + time_zone::absolute_lookup al = BreakTime(tp - d); + al.cs = YearShift(al.cs, shift * 400); + return al; + } + return LocalTime(unix_time, transitions_[timecnt - 1]); + } + + const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed); + if (0 < hint && hint < timecnt) { + if (transitions_[hint - 1].unix_time <= unix_time) { + if (unix_time < transitions_[hint].unix_time) { + return LocalTime(unix_time, transitions_[hint - 1]); + } + } + } + + const Transition target = {unix_time, 0, civil_second(), civil_second()}; + const Transition* begin = &transitions_[0]; + const Transition* tr = std::upper_bound(begin, begin + timecnt, target, + Transition::ByUnixTime()); + local_time_hint_.store(static_cast<std::size_t>(tr - begin), + std::memory_order_relaxed); + return LocalTime(unix_time, *--tr); +} + +time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const { + const std::size_t timecnt = transitions_.size(); + assert(timecnt != 0); // We always add a transition. + + // Find the first transition after our target civil time. + const Transition* tr = nullptr; + const Transition* begin = &transitions_[0]; + const Transition* end = begin + timecnt; + if (cs < begin->civil_sec) { + tr = begin; + } else if (cs >= transitions_[timecnt - 1].civil_sec) { + tr = end; + } else { + const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed); + if (0 < hint && hint < timecnt) { + if (transitions_[hint - 1].civil_sec <= cs) { + if (cs < transitions_[hint].civil_sec) { + tr = begin + hint; + } + } + } + if (tr == nullptr) { + const Transition target = {0, 0, cs, civil_second()}; + tr = std::upper_bound(begin, end, target, Transition::ByCivilTime()); + time_local_hint_.store(static_cast<std::size_t>(tr - begin), + std::memory_order_relaxed); + } + } + + if (tr == begin) { + if (tr->prev_civil_sec >= cs) { + // Before first transition, so use the default offset. + const TransitionType& tt(transition_types_[default_transition_type_]); + if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min()); + return MakeUnique(cs - (civil_second() + tt.utc_offset)); + } + // tr->prev_civil_sec < cs < tr->civil_sec + return MakeSkipped(*tr, cs); + } + + if (tr == end) { + if (cs > (--tr)->prev_civil_sec) { + // After the last transition. If we extended the transitions using + // future_spec_, shift back to a supported year using the 400-year + // cycle of calendaric equivalence and then compensate accordingly. + if (extended_ && cs.year() > last_year_) { + const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1; + return TimeLocal(YearShift(cs, shift * -400), shift); + } + const TransitionType& tt(transition_types_[tr->type_index]); + if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max()); + return MakeUnique(tr->unix_time + (cs - tr->civil_sec)); + } + // tr->civil_sec <= cs <= tr->prev_civil_sec + return MakeRepeated(*tr, cs); + } + + if (tr->prev_civil_sec < cs) { + // tr->prev_civil_sec < cs < tr->civil_sec + return MakeSkipped(*tr, cs); + } + + if (cs <= (--tr)->prev_civil_sec) { + // tr->civil_sec <= cs <= tr->prev_civil_sec + return MakeRepeated(*tr, cs); + } + + // In between transitions. + return MakeUnique(tr->unix_time + (cs - tr->civil_sec)); +} + +std::string TimeZoneInfo::Version() const { return version_; } + +std::string TimeZoneInfo::Description() const { + std::ostringstream oss; + oss << "#trans=" << transitions_.size(); + oss << " #types=" << transition_types_.size(); + oss << " spec='" << future_spec_ << "'"; + return oss.str(); +} + +bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const { + if (transitions_.empty()) return false; + 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 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); + const Transition target = {unix_time, 0, civil_second(), civil_second()}; + const Transition* tr = + std::upper_bound(begin, end, target, Transition::ByUnixTime()); + for (; tr != end; ++tr) { // skip no-op transitions + std::uint_fast8_t prev_type_index = + (tr == begin) ? default_transition_type_ : tr[-1].type_index; + if (!EquivTransitions(prev_type_index, tr[0].type_index)) break; + } + // When tr == end we return false, ignoring future_spec_. + if (tr == end) return false; + trans->from = tr->prev_civil_sec + 1; + trans->to = tr->civil_sec; + return true; +} + +bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const { + if (transitions_.empty()) return false; + 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 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); + if (FromUnixSeconds(unix_time) != tp) { + if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) { + if (end == begin) return false; // Ignore future_spec_. + trans->from = (--end)->prev_civil_sec + 1; + trans->to = end->civil_sec; + return true; + } + unix_time += 1; // ceils + } + const Transition target = {unix_time, 0, civil_second(), civil_second()}; + const Transition* tr = + std::lower_bound(begin, end, target, Transition::ByUnixTime()); + for (; tr != begin; --tr) { // skip no-op transitions + std::uint_fast8_t prev_type_index = + (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index; + if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break; + } + // When tr == end we return the "last" transition, ignoring future_spec_. + if (tr == begin) return false; + trans->from = (--tr)->prev_civil_sec + 1; + trans->to = tr->civil_sec; + return true; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_info.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_info.h new file mode 100644 index 000000000000..2467ff559d35 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_info.h @@ -0,0 +1,137 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_ + +#include <atomic> +#include <cstddef> +#include <cstdint> +#include <string> +#include <vector> + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" +#include "absl/time/internal/cctz/include/cctz/zone_info_source.h" +#include "time_zone_if.h" +#include "tzfile.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// A transition to a new UTC offset. +struct Transition { + std::int_least64_t unix_time; // the instant of this transition + std::uint_least8_t type_index; // index of the transition type + civil_second civil_sec; // local civil time of transition + civil_second prev_civil_sec; // local civil time one second earlier + + struct ByUnixTime { + inline bool operator()(const Transition& lhs, const Transition& rhs) const { + return lhs.unix_time < rhs.unix_time; + } + }; + struct ByCivilTime { + inline bool operator()(const Transition& lhs, const Transition& rhs) const { + return lhs.civil_sec < rhs.civil_sec; + } + }; +}; + +// The characteristics of a particular transition. +struct TransitionType { + std::int_least32_t utc_offset; // the new prevailing UTC offset + civil_second civil_max; // max convertible civil time for offset + civil_second civil_min; // min convertible civil time for offset + bool is_dst; // did we move into daylight-saving time + std::uint_least8_t abbr_index; // index of the new abbreviation +}; + +// A time zone backed by the IANA Time Zone Database (zoneinfo). +class TimeZoneInfo : public TimeZoneIf { + public: + TimeZoneInfo() = default; + TimeZoneInfo(const TimeZoneInfo&) = delete; + TimeZoneInfo& operator=(const TimeZoneInfo&) = delete; + + // Loads the zoneinfo for the given name, returning true if successful. + bool Load(const std::string& name); + + // TimeZoneIf implementations. + time_zone::absolute_lookup BreakTime( + const time_point<seconds>& tp) const override; + time_zone::civil_lookup MakeTime(const civil_second& cs) const override; + bool NextTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const override; + bool PrevTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const override; + std::string Version() const override; + std::string Description() const override; + + private: + struct Header { // counts of: + std::size_t timecnt; // transition times + std::size_t typecnt; // transition types + std::size_t charcnt; // zone abbreviation characters + std::size_t leapcnt; // leap seconds (we expect none) + std::size_t ttisstdcnt; // UTC/local indicators (unused) + std::size_t ttisutcnt; // standard/wall indicators (unused) + + bool Build(const tzhead& tzh); + std::size_t DataLength(std::size_t time_len) 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; + bool ExtendTransitions(); + + bool ResetToBuiltinUTC(const seconds& offset); + bool Load(ZoneInfoSource* zip); + + // Helpers for BreakTime() and MakeTime(). + time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time, + const TransitionType& tt) const; + time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time, + const Transition& tr) const; + time_zone::civil_lookup TimeLocal(const civil_second& cs, + year_t c4_shift) const; + + std::vector<Transition> transitions_; // ordered by unix_time and civil_sec + std::vector<TransitionType> transition_types_; // distinct transition types + std::uint_fast8_t default_transition_type_; // for before first transition + std::string abbreviations_; // all the NUL-terminated abbreviations + + std::string version_; // the tzdata version if available + std::string future_spec_; // for after the last zic transition + bool extended_; // future_spec_ was used to generate transitions + year_t last_year_; // the final year of the generated transitions + + // We remember the transitions found during the last BreakTime() and + // MakeTime() calls. If the next request is for the same transition we + // will avoid re-searching. + mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint + mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint +}; + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_libc.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_libc.cc new file mode 100644 index 000000000000..887dd097c650 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_libc.cc @@ -0,0 +1,315 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if defined(_WIN32) || defined(_WIN64) +#define _CRT_SECURE_NO_WARNINGS 1 +#endif + +#include "time_zone_libc.h" + +#include <chrono> +#include <ctime> +#include <limits> +#include <utility> + +#include "absl/base/config.h" +#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 { +namespace cctz { + +namespace { + +#if defined(_WIN32) || defined(_WIN64) +// Uses the globals: '_timezone', '_dstbias' and '_tzname'. +auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) { + const bool is_dst = tm.tm_isdst > 0; + return _timezone + (is_dst ? _dstbias : 0); +} +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) || 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; + return is_dst ? altzone : timezone; +} +auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { + const bool is_dst = tm.tm_isdst > 0; + return tzname[is_dst]; +} +#elif defined(__native_client__) || defined(__myriad2__) || \ + defined(__EMSCRIPTEN__) +// Uses the globals: 'timezone' and 'tzname'. +auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) { + const bool is_dst = tm.tm_isdst > 0; + return _timezone + (is_dst ? 60 * 60 : 0); +} +auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) { + const bool is_dst = tm.tm_isdst > 0; + return tzname[is_dst]; +} +#else +// Adapt to different spellings of the struct std::tm extension fields. +#if defined(tm_gmtoff) +auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) { + return tm.tm_gmtoff; +} +#elif defined(__tm_gmtoff) +auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) { + return tm.__tm_gmtoff; +} +#else +template <typename T> +auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) { + return tm.tm_gmtoff; +} +template <typename T> +auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) { + return tm.__tm_gmtoff; +} +#endif // tm_gmtoff +#if defined(tm_zone) +auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) { return tm.tm_zone; } +#elif defined(__tm_zone) +auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) { + return tm.__tm_zone; +} +#else +template <typename T> +auto tm_zone(const T& tm) -> decltype(tm.tm_zone) { + return tm.tm_zone; +} +template <typename T> +auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) { + return tm.__tm_zone; +} +#endif // tm_zone +#endif + +inline std::tm* gm_time(const std::time_t* timep, std::tm* result) { +#if defined(_WIN32) || defined(_WIN64) + return gmtime_s(result, timep) ? nullptr : result; +#else + return gmtime_r(timep, result); +#endif +} + +inline std::tm* local_time(const std::time_t* timep, std::tm* result) { +#if defined(_WIN32) || defined(_WIN64) + return localtime_s(result, timep) ? nullptr : result; +#else + return localtime_r(timep, result); +#endif +} + +// Converts a civil second and "dst" flag into a time_t and UTC offset. +// 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); + 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) { + // A true error (not just one second before the epoch). + return false; + } + } + *off = static_cast<int>(tm_gmtoff(tm)); + return true; +} + +// Find the least time_t in [lo:hi] where local time matches offset, given: +// (1) lo doesn't match, (2) hi does, and (3) there is only one transition. +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; + std::tm* tmp = local_time(&mid, &tm); + if (tmp != nullptr) { + if (tm_gmtoff(*tmp) == offset) { + hi = mid; + } else { + lo = mid; + } + } else { + // 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) { + tmp = local_time(&lo, &tm); + if (tmp != nullptr) { + if (tm_gmtoff(*tmp) == offset) break; + } + } + return lo; + } + } + return hi; +} + +} // namespace + +TimeZoneLibC::TimeZoneLibC(const std::string& name) + : local_(name == "localtime") {} + +time_zone::absolute_lookup TimeZoneLibC::BreakTime( + const time_point<seconds>& tp) const { + time_zone::absolute_lookup al; + al.offset = 0; + al.is_dst = false; + al.abbr = "-00"; + + const std::int_fast64_t s = ToUnixSeconds(tp); + + // If std::time_t cannot hold the input we saturate the output. + if (s < std::numeric_limits<std::time_t>::min()) { + al.cs = civil_second::min(); + return al; + } + if (s > std::numeric_limits<std::time_t>::max()) { + al.cs = civil_second::max(); + return al; + } + + const std::time_t t = static_cast<std::time_t>(s); + std::tm tm; + std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm); + + // If std::tm cannot hold the result we saturate the output. + if (tmp == nullptr) { + al.cs = (s < 0) ? civil_second::min() : civil_second::max(); + return al; + } + + const year_t year = tmp->tm_year + year_t{1900}; + al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, + tmp->tm_min, tmp->tm_sec); + al.offset = static_cast<int>(tm_gmtoff(*tmp)); + al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz + al.is_dst = tmp->tm_isdst > 0; + return al; +} + +time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { + if (!local_) { + // If time_point<seconds> cannot hold the result we saturate. + static const civil_second min_tp_cs = + 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()); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + + // If tm_year cannot hold the requested year we saturate the result. + if (cs.year() < 0) { + if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) { + const time_point<seconds> tp = time_point<seconds>::min(); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + } else { + if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) { + const time_point<seconds> tp = time_point<seconds>::max(); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + } + + // 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. + std::time_t t0, t1; + int offset0, offset1; + if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) { + if (t0 == t1) { + // The civil time was singular (pre == trans == post). + const time_point<seconds> tp = FromUnixSeconds(t0); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; + } + + if (t0 > t1) { + std::swap(t0, t1); + std::swap(offset0, offset1); + } + const std::time_t tt = find_trans(t0, t1, offset1); + const time_point<seconds> trans = FromUnixSeconds(tt); + + if (offset0 < offset1) { + // The civil time did not exist (pre >= trans > post). + const time_point<seconds> pre = FromUnixSeconds(t1); + const time_point<seconds> post = FromUnixSeconds(t0); + 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); + return {time_zone::civil_lookup::REPEATED, pre, trans, post}; + } + + // make_time() failed somehow so we saturate the result. + const time_point<seconds> tp = (cs < civil_second()) + ? time_point<seconds>::min() + : time_point<seconds>::max(); + return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; +} + +bool TimeZoneLibC::NextTransition(const time_point<seconds>&, + time_zone::civil_transition*) const { + return false; +} + +bool TimeZoneLibC::PrevTransition(const time_point<seconds>&, + time_zone::civil_transition*) const { + return false; +} + +std::string TimeZoneLibC::Version() const { + return std::string(); // unknown +} + +std::string TimeZoneLibC::Description() const { + return local_ ? "localtime" : "UTC"; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_libc.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_libc.h new file mode 100644 index 000000000000..1da9039a15ee --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_libc.h @@ -0,0 +1,55 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ + +#include <string> + +#include "absl/base/config.h" +#include "time_zone_if.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3), +// and which therefore only supports UTC and the local time zone. +// TODO: Add support for fixed offsets from UTC. +class TimeZoneLibC : public TimeZoneIf { + public: + explicit TimeZoneLibC(const std::string& name); + + // TimeZoneIf implementations. + time_zone::absolute_lookup BreakTime( + const time_point<seconds>& tp) const override; + time_zone::civil_lookup MakeTime(const civil_second& cs) const override; + bool NextTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const override; + bool PrevTransition(const time_point<seconds>& tp, + time_zone::civil_transition* trans) const override; + std::string Version() const override; + std::string Description() const override; + + private: + const bool local_; // localtime or UTC +}; + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_lookup.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_lookup.cc new file mode 100644 index 000000000000..efdea64b4eb1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_lookup.cc @@ -0,0 +1,187 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +#if defined(__ANDROID__) +#include <sys/system_properties.h> +#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21 +#include <dlfcn.h> +#endif +#endif + +#if defined(__APPLE__) +#include <CoreFoundation/CFTimeZone.h> + +#include <vector> +#endif + +#include <cstdlib> +#include <cstring> +#include <string> + +#include "time_zone_fixed.h" +#include "time_zone_impl.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21 +namespace { +// Android 'L' removes __system_property_get() from the NDK, however +// it is still a hidden symbol in libc so we use dlsym() to access it. +// See Chromium's base/sys_info_android.cc for a similar example. + +using property_get_func = int (*)(const char*, char*); + +property_get_func LoadSystemPropertyGet() { + int flag = RTLD_LAZY | RTLD_GLOBAL; +#if defined(RTLD_NOLOAD) + flag |= RTLD_NOLOAD; // libc.so should already be resident +#endif + if (void* handle = dlopen("libc.so", flag)) { + void* sym = dlsym(handle, "__system_property_get"); + dlclose(handle); + return reinterpret_cast<property_get_func>(sym); + } + return nullptr; +} + +int __system_property_get(const char* name, char* value) { + static property_get_func system_property_get = LoadSystemPropertyGet(); + return system_property_get ? system_property_get(name, value) : -1; +} + +} // namespace +#endif + +std::string time_zone::name() const { return effective_impl().Name(); } + +time_zone::absolute_lookup time_zone::lookup( + const time_point<seconds>& tp) const { + return effective_impl().BreakTime(tp); +} + +time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const { + return effective_impl().MakeTime(cs); +} + +bool time_zone::next_transition(const time_point<seconds>& tp, + civil_transition* trans) const { + return effective_impl().NextTransition(tp, trans); +} + +bool time_zone::prev_transition(const time_point<seconds>& tp, + civil_transition* trans) const { + return effective_impl().PrevTransition(tp, trans); +} + +std::string time_zone::version() const { return effective_impl().Version(); } + +std::string time_zone::description() const { + return effective_impl().Description(); +} + +const time_zone::Impl& time_zone::effective_impl() const { + if (impl_ == nullptr) { + // Dereferencing an implicit-UTC time_zone is expected to be + // rare, so we don't mind paying a small synchronization cost. + return *time_zone::Impl::UTC().impl_; + } + return *impl_; +} + +bool load_time_zone(const std::string& name, time_zone* tz) { + return time_zone::Impl::LoadTimeZone(name, tz); +} + +time_zone utc_time_zone() { + return time_zone::Impl::UTC(); // avoid name lookup +} + +time_zone fixed_time_zone(const seconds& offset) { + time_zone tz; + load_time_zone(FixedOffsetToName(offset), &tz); + return tz; +} + +time_zone local_time_zone() { + const char* zone = ":localtime"; +#if defined(__ANDROID__) + char sysprop[PROP_VALUE_MAX]; + if (__system_property_get("persist.sys.timezone", sysprop) > 0) { + zone = sysprop; + } +#endif +#if defined(__APPLE__) + std::vector<char> buffer; + CFTimeZoneRef tz_default = CFTimeZoneCopyDefault(); + if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) { + CFStringEncoding encoding = kCFStringEncodingUTF8; + CFIndex length = CFStringGetLength(tz_name); + buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1); + if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) { + zone = &buffer[0]; + } + } + CFRelease(tz_default); +#endif + + // Allow ${TZ} to override to default zone. + char* tz_env = nullptr; +#if defined(_MSC_VER) + _dupenv_s(&tz_env, nullptr, "TZ"); +#else + tz_env = std::getenv("TZ"); +#endif + if (tz_env) zone = tz_env; + + // We only support the "[:]<zone-name>" form. + if (*zone == ':') ++zone; + + // Map "localtime" to a system-specific name, but + // allow ${LOCALTIME} to override the default name. + char* localtime_env = nullptr; + if (strcmp(zone, "localtime") == 0) { +#if defined(_MSC_VER) + // System-specific default is just "localtime". + _dupenv_s(&localtime_env, nullptr, "LOCALTIME"); +#else + zone = "/etc/localtime"; // System-specific default. + localtime_env = std::getenv("LOCALTIME"); +#endif + if (localtime_env) zone = localtime_env; + } + + const std::string name = zone; +#if defined(_MSC_VER) + free(localtime_env); + free(tz_env); +#endif + + time_zone tz; + load_time_zone(name, &tz); // Falls back to UTC. + // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and + // arrange for %z to generate "-0000" when we don't know the local + // offset because the load_time_zone() failed and we're using UTC. + return tz; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc new file mode 100644 index 000000000000..9a1a8d6e400c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_lookup_test.cc @@ -0,0 +1,1442 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <chrono> +#include <cstddef> +#include <cstdlib> +#include <future> +#include <limits> +#include <string> +#include <thread> +#include <vector> + +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +namespace chrono = std::chrono; + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +// A list of known time-zone names. +const char* const kTimeZoneNames[] = {"Africa/Abidjan", + "Africa/Accra", + "Africa/Addis_Ababa", + "Africa/Algiers", + "Africa/Asmara", + "Africa/Asmera", + "Africa/Bamako", + "Africa/Bangui", + "Africa/Banjul", + "Africa/Bissau", + "Africa/Blantyre", + "Africa/Brazzaville", + "Africa/Bujumbura", + "Africa/Cairo", + "Africa/Casablanca", + "Africa/Ceuta", + "Africa/Conakry", + "Africa/Dakar", + "Africa/Dar_es_Salaam", + "Africa/Djibouti", + "Africa/Douala", + "Africa/El_Aaiun", + "Africa/Freetown", + "Africa/Gaborone", + "Africa/Harare", + "Africa/Johannesburg", + "Africa/Juba", + "Africa/Kampala", + "Africa/Khartoum", + "Africa/Kigali", + "Africa/Kinshasa", + "Africa/Lagos", + "Africa/Libreville", + "Africa/Lome", + "Africa/Luanda", + "Africa/Lubumbashi", + "Africa/Lusaka", + "Africa/Malabo", + "Africa/Maputo", + "Africa/Maseru", + "Africa/Mbabane", + "Africa/Mogadishu", + "Africa/Monrovia", + "Africa/Nairobi", + "Africa/Ndjamena", + "Africa/Niamey", + "Africa/Nouakchott", + "Africa/Ouagadougou", + "Africa/Porto-Novo", + "Africa/Sao_Tome", + "Africa/Timbuktu", + "Africa/Tripoli", + "Africa/Tunis", + "Africa/Windhoek", + "America/Adak", + "America/Anchorage", + "America/Anguilla", + "America/Antigua", + "America/Araguaina", + "America/Argentina/Buenos_Aires", + "America/Argentina/Catamarca", + "America/Argentina/ComodRivadavia", + "America/Argentina/Cordoba", + "America/Argentina/Jujuy", + "America/Argentina/La_Rioja", + "America/Argentina/Mendoza", + "America/Argentina/Rio_Gallegos", + "America/Argentina/Salta", + "America/Argentina/San_Juan", + "America/Argentina/San_Luis", + "America/Argentina/Tucuman", + "America/Argentina/Ushuaia", + "America/Aruba", + "America/Asuncion", + "America/Atikokan", + "America/Atka", + "America/Bahia", + "America/Bahia_Banderas", + "America/Barbados", + "America/Belem", + "America/Belize", + "America/Blanc-Sablon", + "America/Boa_Vista", + "America/Bogota", + "America/Boise", + "America/Buenos_Aires", + "America/Cambridge_Bay", + "America/Campo_Grande", + "America/Cancun", + "America/Caracas", + "America/Catamarca", + "America/Cayenne", + "America/Cayman", + "America/Chicago", + "America/Chihuahua", + "America/Coral_Harbour", + "America/Cordoba", + "America/Costa_Rica", + "America/Creston", + "America/Cuiaba", + "America/Curacao", + "America/Danmarkshavn", + "America/Dawson", + "America/Dawson_Creek", + "America/Denver", + "America/Detroit", + "America/Dominica", + "America/Edmonton", + "America/Eirunepe", + "America/El_Salvador", + "America/Ensenada", + "America/Fort_Nelson", + "America/Fort_Wayne", + "America/Fortaleza", + "America/Glace_Bay", + "America/Godthab", + "America/Goose_Bay", + "America/Grand_Turk", + "America/Grenada", + "America/Guadeloupe", + "America/Guatemala", + "America/Guayaquil", + "America/Guyana", + "America/Halifax", + "America/Havana", + "America/Hermosillo", + "America/Indiana/Indianapolis", + "America/Indiana/Knox", + "America/Indiana/Marengo", + "America/Indiana/Petersburg", + "America/Indiana/Tell_City", + "America/Indiana/Vevay", + "America/Indiana/Vincennes", + "America/Indiana/Winamac", + "America/Indianapolis", + "America/Inuvik", + "America/Iqaluit", + "America/Jamaica", + "America/Jujuy", + "America/Juneau", + "America/Kentucky/Louisville", + "America/Kentucky/Monticello", + "America/Knox_IN", + "America/Kralendijk", + "America/La_Paz", + "America/Lima", + "America/Los_Angeles", + "America/Louisville", + "America/Lower_Princes", + "America/Maceio", + "America/Managua", + "America/Manaus", + "America/Marigot", + "America/Martinique", + "America/Matamoros", + "America/Mazatlan", + "America/Mendoza", + "America/Menominee", + "America/Merida", + "America/Metlakatla", + "America/Mexico_City", + "America/Miquelon", + "America/Moncton", + "America/Monterrey", + "America/Montevideo", + "America/Montreal", + "America/Montserrat", + "America/Nassau", + "America/New_York", + "America/Nipigon", + "America/Nome", + "America/Noronha", + "America/North_Dakota/Beulah", + "America/North_Dakota/Center", + "America/North_Dakota/New_Salem", + "America/Nuuk", + "America/Ojinaga", + "America/Panama", + "America/Pangnirtung", + "America/Paramaribo", + "America/Phoenix", + "America/Port-au-Prince", + "America/Port_of_Spain", + "America/Porto_Acre", + "America/Porto_Velho", + "America/Puerto_Rico", + "America/Punta_Arenas", + "America/Rainy_River", + "America/Rankin_Inlet", + "America/Recife", + "America/Regina", + "America/Resolute", + "America/Rio_Branco", + "America/Rosario", + "America/Santa_Isabel", + "America/Santarem", + "America/Santiago", + "America/Santo_Domingo", + "America/Sao_Paulo", + "America/Scoresbysund", + "America/Shiprock", + "America/Sitka", + "America/St_Barthelemy", + "America/St_Johns", + "America/St_Kitts", + "America/St_Lucia", + "America/St_Thomas", + "America/St_Vincent", + "America/Swift_Current", + "America/Tegucigalpa", + "America/Thule", + "America/Thunder_Bay", + "America/Tijuana", + "America/Toronto", + "America/Tortola", + "America/Vancouver", + "America/Virgin", + "America/Whitehorse", + "America/Winnipeg", + "America/Yakutat", + "America/Yellowknife", + "Antarctica/Casey", + "Antarctica/Davis", + "Antarctica/DumontDUrville", + "Antarctica/Macquarie", + "Antarctica/Mawson", + "Antarctica/McMurdo", + "Antarctica/Palmer", + "Antarctica/Rothera", + "Antarctica/South_Pole", + "Antarctica/Syowa", + "Antarctica/Troll", + "Antarctica/Vostok", + "Arctic/Longyearbyen", + "Asia/Aden", + "Asia/Almaty", + "Asia/Amman", + "Asia/Anadyr", + "Asia/Aqtau", + "Asia/Aqtobe", + "Asia/Ashgabat", + "Asia/Ashkhabad", + "Asia/Atyrau", + "Asia/Baghdad", + "Asia/Bahrain", + "Asia/Baku", + "Asia/Bangkok", + "Asia/Barnaul", + "Asia/Beirut", + "Asia/Bishkek", + "Asia/Brunei", + "Asia/Calcutta", + "Asia/Chita", + "Asia/Choibalsan", + "Asia/Chongqing", + "Asia/Chungking", + "Asia/Colombo", + "Asia/Dacca", + "Asia/Damascus", + "Asia/Dhaka", + "Asia/Dili", + "Asia/Dubai", + "Asia/Dushanbe", + "Asia/Famagusta", + "Asia/Gaza", + "Asia/Harbin", + "Asia/Hebron", + "Asia/Ho_Chi_Minh", + "Asia/Hong_Kong", + "Asia/Hovd", + "Asia/Irkutsk", + "Asia/Istanbul", + "Asia/Jakarta", + "Asia/Jayapura", + "Asia/Jerusalem", + "Asia/Kabul", + "Asia/Kamchatka", + "Asia/Karachi", + "Asia/Kashgar", + "Asia/Kathmandu", + "Asia/Katmandu", + "Asia/Khandyga", + "Asia/Kolkata", + "Asia/Krasnoyarsk", + "Asia/Kuala_Lumpur", + "Asia/Kuching", + "Asia/Kuwait", + "Asia/Macao", + "Asia/Macau", + "Asia/Magadan", + "Asia/Makassar", + "Asia/Manila", + "Asia/Muscat", + "Asia/Nicosia", + "Asia/Novokuznetsk", + "Asia/Novosibirsk", + "Asia/Omsk", + "Asia/Oral", + "Asia/Phnom_Penh", + "Asia/Pontianak", + "Asia/Pyongyang", + "Asia/Qatar", + "Asia/Qostanay", + "Asia/Qyzylorda", + "Asia/Rangoon", + "Asia/Riyadh", + "Asia/Saigon", + "Asia/Sakhalin", + "Asia/Samarkand", + "Asia/Seoul", + "Asia/Shanghai", + "Asia/Singapore", + "Asia/Srednekolymsk", + "Asia/Taipei", + "Asia/Tashkent", + "Asia/Tbilisi", + "Asia/Tehran", + "Asia/Tel_Aviv", + "Asia/Thimbu", + "Asia/Thimphu", + "Asia/Tokyo", + "Asia/Tomsk", + "Asia/Ujung_Pandang", + "Asia/Ulaanbaatar", + "Asia/Ulan_Bator", + "Asia/Urumqi", + "Asia/Ust-Nera", + "Asia/Vientiane", + "Asia/Vladivostok", + "Asia/Yakutsk", + "Asia/Yangon", + "Asia/Yekaterinburg", + "Asia/Yerevan", + "Atlantic/Azores", + "Atlantic/Bermuda", + "Atlantic/Canary", + "Atlantic/Cape_Verde", + "Atlantic/Faeroe", + "Atlantic/Faroe", + "Atlantic/Jan_Mayen", + "Atlantic/Madeira", + "Atlantic/Reykjavik", + "Atlantic/South_Georgia", + "Atlantic/St_Helena", + "Atlantic/Stanley", + "Australia/ACT", + "Australia/Adelaide", + "Australia/Brisbane", + "Australia/Broken_Hill", + "Australia/Canberra", + "Australia/Currie", + "Australia/Darwin", + "Australia/Eucla", + "Australia/Hobart", + "Australia/LHI", + "Australia/Lindeman", + "Australia/Lord_Howe", + "Australia/Melbourne", + "Australia/NSW", + "Australia/North", + "Australia/Perth", + "Australia/Queensland", + "Australia/South", + "Australia/Sydney", + "Australia/Tasmania", + "Australia/Victoria", + "Australia/West", + "Australia/Yancowinna", + "Brazil/Acre", + "Brazil/DeNoronha", + "Brazil/East", + "Brazil/West", + "CET", + "CST6CDT", + "Canada/Atlantic", + "Canada/Central", + "Canada/Eastern", + "Canada/Mountain", + "Canada/Newfoundland", + "Canada/Pacific", + "Canada/Saskatchewan", + "Canada/Yukon", + "Chile/Continental", + "Chile/EasterIsland", + "Cuba", + "EET", + "EST", + "EST5EDT", + "Egypt", + "Eire", + "Etc/GMT", + "Etc/GMT+0", + "Etc/GMT+1", + "Etc/GMT+10", + "Etc/GMT+11", + "Etc/GMT+12", + "Etc/GMT+2", + "Etc/GMT+3", + "Etc/GMT+4", + "Etc/GMT+5", + "Etc/GMT+6", + "Etc/GMT+7", + "Etc/GMT+8", + "Etc/GMT+9", + "Etc/GMT-0", + "Etc/GMT-1", + "Etc/GMT-10", + "Etc/GMT-11", + "Etc/GMT-12", + "Etc/GMT-13", + "Etc/GMT-14", + "Etc/GMT-2", + "Etc/GMT-3", + "Etc/GMT-4", + "Etc/GMT-5", + "Etc/GMT-6", + "Etc/GMT-7", + "Etc/GMT-8", + "Etc/GMT-9", + "Etc/GMT0", + "Etc/Greenwich", + "Etc/UCT", + "Etc/UTC", + "Etc/Universal", + "Etc/Zulu", + "Europe/Amsterdam", + "Europe/Andorra", + "Europe/Astrakhan", + "Europe/Athens", + "Europe/Belfast", + "Europe/Belgrade", + "Europe/Berlin", + "Europe/Bratislava", + "Europe/Brussels", + "Europe/Bucharest", + "Europe/Budapest", + "Europe/Busingen", + "Europe/Chisinau", + "Europe/Copenhagen", + "Europe/Dublin", + "Europe/Gibraltar", + "Europe/Guernsey", + "Europe/Helsinki", + "Europe/Isle_of_Man", + "Europe/Istanbul", + "Europe/Jersey", + "Europe/Kaliningrad", + "Europe/Kiev", + "Europe/Kirov", + "Europe/Lisbon", + "Europe/Ljubljana", + "Europe/London", + "Europe/Luxembourg", + "Europe/Madrid", + "Europe/Malta", + "Europe/Mariehamn", + "Europe/Minsk", + "Europe/Monaco", + "Europe/Moscow", + "Europe/Nicosia", + "Europe/Oslo", + "Europe/Paris", + "Europe/Podgorica", + "Europe/Prague", + "Europe/Riga", + "Europe/Rome", + "Europe/Samara", + "Europe/San_Marino", + "Europe/Sarajevo", + "Europe/Saratov", + "Europe/Simferopol", + "Europe/Skopje", + "Europe/Sofia", + "Europe/Stockholm", + "Europe/Tallinn", + "Europe/Tirane", + "Europe/Tiraspol", + "Europe/Ulyanovsk", + "Europe/Uzhgorod", + "Europe/Vaduz", + "Europe/Vatican", + "Europe/Vienna", + "Europe/Vilnius", + "Europe/Volgograd", + "Europe/Warsaw", + "Europe/Zagreb", + "Europe/Zaporozhye", + "Europe/Zurich", + "GB", + "GB-Eire", + "GMT", + "GMT+0", + "GMT-0", + "GMT0", + "Greenwich", + "HST", + "Hongkong", + "Iceland", + "Indian/Antananarivo", + "Indian/Chagos", + "Indian/Christmas", + "Indian/Cocos", + "Indian/Comoro", + "Indian/Kerguelen", + "Indian/Mahe", + "Indian/Maldives", + "Indian/Mauritius", + "Indian/Mayotte", + "Indian/Reunion", + "Iran", + "Israel", + "Jamaica", + "Japan", + "Kwajalein", + "Libya", + "MET", + "MST", + "MST7MDT", + "Mexico/BajaNorte", + "Mexico/BajaSur", + "Mexico/General", + "NZ", + "NZ-CHAT", + "Navajo", + "PRC", + "PST8PDT", + "Pacific/Apia", + "Pacific/Auckland", + "Pacific/Bougainville", + "Pacific/Chatham", + "Pacific/Chuuk", + "Pacific/Easter", + "Pacific/Efate", + "Pacific/Enderbury", + "Pacific/Fakaofo", + "Pacific/Fiji", + "Pacific/Funafuti", + "Pacific/Galapagos", + "Pacific/Gambier", + "Pacific/Guadalcanal", + "Pacific/Guam", + "Pacific/Honolulu", + "Pacific/Johnston", + "Pacific/Kiritimati", + "Pacific/Kosrae", + "Pacific/Kwajalein", + "Pacific/Majuro", + "Pacific/Marquesas", + "Pacific/Midway", + "Pacific/Nauru", + "Pacific/Niue", + "Pacific/Norfolk", + "Pacific/Noumea", + "Pacific/Pago_Pago", + "Pacific/Palau", + "Pacific/Pitcairn", + "Pacific/Pohnpei", + "Pacific/Ponape", + "Pacific/Port_Moresby", + "Pacific/Rarotonga", + "Pacific/Saipan", + "Pacific/Samoa", + "Pacific/Tahiti", + "Pacific/Tarawa", + "Pacific/Tongatapu", + "Pacific/Truk", + "Pacific/Wake", + "Pacific/Wallis", + "Pacific/Yap", + "Poland", + "Portugal", + "ROC", + "ROK", + "Singapore", + "Turkey", + "UCT", + "US/Alaska", + "US/Aleutian", + "US/Arizona", + "US/Central", + "US/East-Indiana", + "US/Eastern", + "US/Hawaii", + "US/Indiana-Starke", + "US/Michigan", + "US/Mountain", + "US/Pacific", + "US/Samoa", + "UTC", + "Universal", + "W-SU", + "WET", + "Zulu", + nullptr}; + +// Helper to return a loaded time zone by value (UTC on error). +time_zone LoadZone(const std::string& name) { + time_zone tz; + load_time_zone(name, &tz); + return tz; +} + +// This helper is a macro so that failed expectations show up with the +// correct line numbers. +#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \ + do { \ + time_zone::absolute_lookup al = tz.lookup(tp); \ + EXPECT_EQ(y, al.cs.year()); \ + EXPECT_EQ(m, al.cs.month()); \ + EXPECT_EQ(d, al.cs.day()); \ + EXPECT_EQ(hh, al.cs.hour()); \ + EXPECT_EQ(mm, al.cs.minute()); \ + EXPECT_EQ(ss, al.cs.second()); \ + EXPECT_EQ(off, al.offset); \ + EXPECT_TRUE(isdst == al.is_dst); \ + /* EXPECT_STREQ(zone, al.abbr); */ \ + } while (0) + +// These tests sometimes run on platforms that have zoneinfo data so old +// that the transition we are attempting to check does not exist, most +// notably Android emulators. Fortunately, AndroidZoneInfoSource supports +// time_zone::version() so, in cases where we've learned that it matters, +// we can make the check conditionally. +int VersionCmp(time_zone tz, const std::string& target) { + std::string version = tz.version(); + if (version.empty() && !target.empty()) return 1; // unknown > known + return version.compare(target); +} + +} // namespace + +#if !defined(__EMSCRIPTEN__) +TEST(TimeZones, LoadZonesConcurrently) { + std::promise<void> ready_promise; + std::shared_future<void> ready_future(ready_promise.get_future()); + auto load_zones = [ready_future](std::promise<void>* started, + std::set<std::string>* failures) { + started->set_value(); + ready_future.wait(); + for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) { + std::string zone = *np; + time_zone tz; + if (load_time_zone(zone, &tz)) { + EXPECT_EQ(zone, tz.name()); + } else { + failures->insert(zone); + } + } + }; + + const std::size_t n_threads = 128; + std::vector<std::thread> threads; + std::vector<std::set<std::string>> thread_failures(n_threads); + for (std::size_t i = 0; i != n_threads; ++i) { + std::promise<void> started; + threads.emplace_back(load_zones, &started, &thread_failures[i]); + started.get_future().wait(); + } + ready_promise.set_value(); + for (auto& thread : threads) { + thread.join(); + } + + // Allow a small number of failures to account for skew between + // the contents of kTimeZoneNames and the zoneinfo data source. +#if defined(__ANDROID__) + // Cater to the possibility of using an even older zoneinfo data + // source when running on Android, where it is difficult to override + // the bionic tzdata provided by the test environment. + const std::size_t max_failures = 20; +#else + const std::size_t max_failures = 3; +#endif + std::set<std::string> failures; + for (const auto& thread_failure : thread_failures) { + failures.insert(thread_failure.begin(), thread_failure.end()); + } + EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures); +} +#endif + +TEST(TimeZone, NamedTimeZones) { + const time_zone utc = utc_time_zone(); + EXPECT_EQ("UTC", utc.name()); + const time_zone nyc = LoadZone("America/New_York"); + EXPECT_EQ("America/New_York", nyc.name()); + const time_zone syd = LoadZone("Australia/Sydney"); + EXPECT_EQ("Australia/Sydney", syd.name()); + const time_zone fixed0 = + fixed_time_zone(absl::time_internal::cctz::seconds::zero()); + EXPECT_EQ("UTC", fixed0.name()); + const time_zone fixed_pos = fixed_time_zone( + chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45)); + EXPECT_EQ("Fixed/UTC+03:25:45", fixed_pos.name()); + const time_zone fixed_neg = fixed_time_zone( + -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56))); + EXPECT_EQ("Fixed/UTC-12:34:56", fixed_neg.name()); +} + +TEST(TimeZone, Failures) { + time_zone tz; + EXPECT_FALSE(load_time_zone(":America/Los_Angeles", &tz)); + + tz = LoadZone("America/Los_Angeles"); + EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz)); + EXPECT_EQ(chrono::system_clock::from_time_t(0), + convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC + + // Ensures that the load still fails on a subsequent attempt. + tz = LoadZone("America/Los_Angeles"); + EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz)); + EXPECT_EQ(chrono::system_clock::from_time_t(0), + convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC + + // Loading an empty string timezone should fail. + tz = LoadZone("America/Los_Angeles"); + EXPECT_FALSE(load_time_zone("", &tz)); + EXPECT_EQ(chrono::system_clock::from_time_t(0), + convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC +} + +TEST(TimeZone, Equality) { + const time_zone a; + const time_zone b; + EXPECT_EQ(a, b); + EXPECT_EQ(a.name(), b.name()); + + const time_zone implicit_utc; + const time_zone explicit_utc = utc_time_zone(); + EXPECT_EQ(implicit_utc, explicit_utc); + EXPECT_EQ(implicit_utc.name(), explicit_utc.name()); + + const time_zone fixed_zero = + fixed_time_zone(absl::time_internal::cctz::seconds::zero()); + EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name())); + EXPECT_EQ(fixed_zero, explicit_utc); + + const time_zone fixed_utc = LoadZone("Fixed/UTC+00:00:00"); + EXPECT_EQ(fixed_utc, LoadZone(fixed_utc.name())); + EXPECT_EQ(fixed_utc, explicit_utc); + + const time_zone fixed_pos = fixed_time_zone( + chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45)); + EXPECT_EQ(fixed_pos, LoadZone(fixed_pos.name())); + EXPECT_NE(fixed_pos, explicit_utc); + const time_zone fixed_neg = fixed_time_zone( + -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56))); + EXPECT_EQ(fixed_neg, LoadZone(fixed_neg.name())); + EXPECT_NE(fixed_neg, explicit_utc); + + const time_zone fixed_lim = fixed_time_zone(chrono::hours(24)); + EXPECT_EQ(fixed_lim, LoadZone(fixed_lim.name())); + EXPECT_NE(fixed_lim, explicit_utc); + const time_zone fixed_ovfl = + fixed_time_zone(chrono::hours(24) + chrono::seconds(1)); + EXPECT_EQ(fixed_ovfl, LoadZone(fixed_ovfl.name())); + EXPECT_EQ(fixed_ovfl, explicit_utc); + + EXPECT_EQ(fixed_time_zone(chrono::seconds(1)), + fixed_time_zone(chrono::seconds(1))); + + const time_zone local = local_time_zone(); + EXPECT_EQ(local, LoadZone(local.name())); + + time_zone la = LoadZone("America/Los_Angeles"); + time_zone nyc = LoadZone("America/New_York"); + EXPECT_NE(la, nyc); +} + +TEST(StdChronoTimePoint, TimeTAlignment) { + // Ensures that the Unix epoch and the system clock epoch are an integral + // number of seconds apart. This simplifies conversions to/from time_t. + auto diff = + chrono::system_clock::time_point() - chrono::system_clock::from_time_t(0); + EXPECT_EQ(chrono::system_clock::time_point::duration::zero(), + diff % chrono::seconds(1)); +} + +TEST(BreakTime, TimePointResolution) { + const time_zone utc = utc_time_zone(); + const auto t0 = chrono::system_clock::from_time_t(0); + + ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc, 1970, 1, 1, + 0, 0, 0, 0, false, "UTC"); + ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc, 1970, 1, 1, + 0, 0, 0, 0, false, "UTC"); + ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc, 1970, 1, 1, + 0, 0, 0, 0, false, "UTC"); + ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc, 1970, 1, 1, 0, + 0, 0, 0, false, "UTC"); + ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), + utc, 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); + ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc, 1970, 1, 1, 0, + 0, 0, 0, false, "UTC"); + ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc, 1970, 1, 1, 0, 0, + 0, 0, false, "UTC"); +} + +TEST(BreakTime, LocalTimeInUTC) { + const time_zone tz = utc_time_zone(); + const auto tp = chrono::system_clock::from_time_t(0); + ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); + EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz))); +} + +TEST(BreakTime, LocalTimeInUTCUnaligned) { + const time_zone tz = utc_time_zone(); + const auto tp = + chrono::system_clock::from_time_t(0) - chrono::milliseconds(500); + ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC"); + EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz))); +} + +TEST(BreakTime, LocalTimePosix) { + // See IEEE Std 1003.1-1988 B.2.3 General Terms, Epoch. + const time_zone tz = utc_time_zone(); + const auto tp = chrono::system_clock::from_time_t(536457599); + ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC"); + EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz))); +} + +TEST(TimeZoneImpl, LocalTimeInFixed) { + const absl::time_internal::cctz::seconds offset = + -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47)); + const time_zone tz = fixed_time_zone(offset); + const auto tp = chrono::system_clock::from_time_t(0); + ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false, + "-083347"); + EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz))); +} + +TEST(BreakTime, LocalTimeInNewYork) { + const time_zone tz = LoadZone("America/New_York"); + const auto tp = chrono::system_clock::from_time_t(45); + ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST"); + EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz))); +} + +TEST(BreakTime, LocalTimeInMTV) { + const time_zone tz = LoadZone("America/Los_Angeles"); + const auto tp = chrono::system_clock::from_time_t(1380855729); + ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT"); + EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz))); +} + +TEST(BreakTime, LocalTimeInSydney) { + const time_zone tz = LoadZone("Australia/Sydney"); + const auto tp = chrono::system_clock::from_time_t(90); + ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST"); + EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz))); +} + +TEST(MakeTime, TimePointResolution) { + const time_zone utc = utc_time_zone(); + const time_point<chrono::nanoseconds> tp_ns = + convert(civil_second(2015, 1, 2, 3, 4, 5), utc); + EXPECT_EQ("04:05", format("%M:%E*S", tp_ns, utc)); + const time_point<chrono::microseconds> tp_us = + convert(civil_second(2015, 1, 2, 3, 4, 5), utc); + EXPECT_EQ("04:05", format("%M:%E*S", tp_us, utc)); + const time_point<chrono::milliseconds> tp_ms = + convert(civil_second(2015, 1, 2, 3, 4, 5), utc); + EXPECT_EQ("04:05", format("%M:%E*S", tp_ms, utc)); + const time_point<chrono::seconds> tp_s = + convert(civil_second(2015, 1, 2, 3, 4, 5), utc); + EXPECT_EQ("04:05", format("%M:%E*S", tp_s, utc)); + const time_point<absl::time_internal::cctz::seconds> tp_s64 = + convert(civil_second(2015, 1, 2, 3, 4, 5), utc); + EXPECT_EQ("04:05", format("%M:%E*S", tp_s64, utc)); + + // These next two require chrono::time_point_cast because the conversion + // from a resolution of seconds (the return value of convert()) to a + // coarser resolution requires an explicit cast. + const time_point<chrono::minutes> tp_m = + chrono::time_point_cast<chrono::minutes>( + convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); + EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc)); + const time_point<chrono::hours> tp_h = chrono::time_point_cast<chrono::hours>( + convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); + EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc)); +} + +TEST(MakeTime, Normalization) { + const time_zone tz = LoadZone("America/New_York"); + const auto tp = convert(civil_second(2009, 2, 13, 18, 31, 30), tz); + EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp); + + // Now requests for the same time_point but with out-of-range fields. + EXPECT_EQ(tp, convert(civil_second(2008, 14, 13, 18, 31, 30), tz)); // month + EXPECT_EQ(tp, convert(civil_second(2009, 1, 44, 18, 31, 30), tz)); // day + EXPECT_EQ(tp, convert(civil_second(2009, 2, 12, 42, 31, 30), tz)); // hour + EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 17, 91, 30), tz)); // minute + EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz)); // second +} + +// NOTE: Run this with -ftrapv to detect overflow problems. +TEST(MakeTime, SysSecondsLimits) { + const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez"; + const time_zone utc = utc_time_zone(); + const time_zone east = fixed_time_zone(chrono::hours(14)); + const time_zone west = fixed_time_zone(-chrono::hours(14)); + time_point<absl::time_internal::cctz::seconds> tp; + + // Approach the maximal time_point<cctz::seconds> value from below. + tp = convert(civil_second(292277026596, 12, 4, 15, 30, 6), utc); + EXPECT_EQ("292277026596-12-04T15:30:06+00:00", format(RFC3339, tp, utc)); + tp = convert(civil_second(292277026596, 12, 4, 15, 30, 7), utc); + EXPECT_EQ("292277026596-12-04T15:30:07+00:00", format(RFC3339, tp, utc)); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + tp = convert(civil_second(292277026596, 12, 4, 15, 30, 8), utc); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + tp = convert(civil_second::max(), utc); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + + // Checks that we can also get the maximal value for a far-east zone. + tp = convert(civil_second(292277026596, 12, 5, 5, 30, 7), east); + EXPECT_EQ("292277026596-12-05T05:30:07+14:00", format(RFC3339, tp, east)); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + tp = convert(civil_second(292277026596, 12, 5, 5, 30, 8), east); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + tp = convert(civil_second::max(), east); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + + // Checks that we can also get the maximal value for a far-west zone. + tp = convert(civil_second(292277026596, 12, 4, 1, 30, 7), west); + EXPECT_EQ("292277026596-12-04T01:30:07-14:00", format(RFC3339, tp, west)); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + tp = convert(civil_second(292277026596, 12, 4, 7, 30, 8), west); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + tp = convert(civil_second::max(), west); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::max(), tp); + + // Approach the minimal time_point<cctz::seconds> value from above. + tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 53), utc); + EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", format(RFC3339, tp, utc)); + tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 52), utc); + EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", format(RFC3339, tp, utc)); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 51), utc); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + tp = convert(civil_second::min(), utc); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + + // Checks that we can also get the minimal value for a far-east zone. + tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 52), east); + EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", format(RFC3339, tp, east)); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 51), east); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + tp = convert(civil_second::min(), east); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + + // Checks that we can also get the minimal value for a far-west zone. + tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 52), west); + EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", format(RFC3339, tp, west)); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 51), west); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + tp = convert(civil_second::min(), west); + EXPECT_EQ(time_point<absl::time_internal::cctz::seconds>::min(), tp); + + // Some similar checks for the "libc" time-zone implementation. + 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 outside [1970:3000]. +#else + 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. +#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), cut); + EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut)); +#endif + } +} + +TEST(MakeTime, LocalTimeLibC) { + // Checks that cctz and libc agree on transition points in [1970:2037]. + // + // We limit this test case to environments where: + // 1) we know how to change the time zone used by localtime()/mktime(), + // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and + // 3) we have some idea about how mktime() behaves during transitions. +#if defined(__linux__) && !defined(__ANDROID__) + const char* const ep = getenv("TZ"); + std::string tz_name = (ep != nullptr) ? ep : ""; + for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) { + ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means + const auto zi = local_time_zone(); + const auto lc = LoadZone("libc:localtime"); + time_zone::civil_transition transition; + for (auto tp = zi.lookup(civil_second()).trans; + zi.next_transition(tp, &transition); + 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 + 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. + ASSERT_EQ(transition.from, transition.to); + const auto trans = fcl.trans; + const auto tal = zi.lookup(trans); + const auto tprev = trans - absl::time_internal::cctz::seconds(1); + const auto pal = zi.lookup(tprev); + if (pal.is_dst == tal.is_dst) { + ASSERT_STRNE(pal.abbr, tal.abbr); + } + continue; + } + ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind); + cs = transition.to; + } else { + ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind); + ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind); + cs = transition.from; + } + if (cs.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 + // that don't change the "tm_isdst" flag. In Europe/Volgograd, for + // example, there is a SKIPPED transition from +03 to +04 with dst=F + // on both sides ... + // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800] + // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400] + // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike, + // say, the similar Europe/Chisinau transition from +02 to +03 ... + // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200] + // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800] + // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and + // returns 1521936000. + continue; + } + if (cs == civil_second(2037, 10, 4, 2, 0, 0)) { + const std::string tzname = *np; + if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") { + // The "libc" implementation gets this transition wrong (at least + // until 2018g when it was removed), returning an offset of 3600 + // instead of 0. TODO: Revert this when 2018g is ubiquitous. + continue; + } + } + const auto cl_lc = lc.lookup(cs); + SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np); + EXPECT_EQ(cl_zi.kind, cl_lc.kind); + EXPECT_EQ(cl_zi.pre, cl_lc.pre); + EXPECT_EQ(cl_zi.trans, cl_lc.trans); + EXPECT_EQ(cl_zi.post, cl_lc.post); + } + } + if (ep == nullptr) { + ASSERT_EQ(0, unsetenv("TZ")); + } else { + ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1)); + } +#endif +} + +TEST(NextTransition, UTC) { + const auto tz = utc_time_zone(); + time_zone::civil_transition trans; + + auto tp = time_point<absl::time_internal::cctz::seconds>::min(); + EXPECT_FALSE(tz.next_transition(tp, &trans)); + + tp = time_point<absl::time_internal::cctz::seconds>::max(); + EXPECT_FALSE(tz.next_transition(tp, &trans)); +} + +TEST(PrevTransition, UTC) { + const auto tz = utc_time_zone(); + time_zone::civil_transition trans; + + auto tp = time_point<absl::time_internal::cctz::seconds>::max(); + EXPECT_FALSE(tz.prev_transition(tp, &trans)); + + tp = time_point<absl::time_internal::cctz::seconds>::min(); + EXPECT_FALSE(tz.prev_transition(tp, &trans)); +} + +TEST(NextTransition, AmericaNewYork) { + const auto tz = LoadZone("America/New_York"); + time_zone::civil_transition trans; + + auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz); + EXPECT_TRUE(tz.next_transition(tp, &trans)); + EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from); + EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to); + + tp = time_point<absl::time_internal::cctz::seconds>::max(); + EXPECT_FALSE(tz.next_transition(tp, &trans)); + + tp = time_point<absl::time_internal::cctz::seconds>::min(); + EXPECT_TRUE(tz.next_transition(tp, &trans)); + if (trans.from == civil_second(1918, 3, 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(civil_second(1918, 3, 31, 3, 0, 0), trans.to); + } else { + EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from); + EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to); + } +} + +TEST(PrevTransition, AmericaNewYork) { + const auto tz = LoadZone("America/New_York"); + time_zone::civil_transition trans; + + auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz); + EXPECT_TRUE(tz.prev_transition(tp, &trans)); + EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from); + EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to); + + tp = time_point<absl::time_internal::cctz::seconds>::min(); + EXPECT_FALSE(tz.prev_transition(tp, &trans)); + + tp = time_point<absl::time_internal::cctz::seconds>::max(); + EXPECT_TRUE(tz.prev_transition(tp, &trans)); + // We have a transition but we don't know which one. +} + +TEST(TimeZoneEdgeCase, AmericaNewYork) { + const time_zone tz = LoadZone("America/New_York"); + + // Spring 1:59:59 -> 3:00:00 + auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -5 * 3600, false, "EST"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -4 * 3600, true, "EDT"); + + // Fall 1:59:59 -> 1:00:00 + tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -4 * 3600, true, "EDT"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -5 * 3600, false, "EST"); +} + +TEST(TimeZoneEdgeCase, AmericaLosAngeles) { + const time_zone tz = LoadZone("America/Los_Angeles"); + + // Spring 1:59:59 -> 3:00:00 + auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -8 * 3600, false, "PST"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -7 * 3600, true, "PDT"); + + // Fall 1:59:59 -> 1:00:00 + tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, true, "PDT"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -8 * 3600, false, "PST"); +} + +TEST(TimeZoneEdgeCase, ArizonaNoTransition) { + const time_zone tz = LoadZone("America/Phoenix"); + + // No transition in Spring. + auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -7 * 3600, false, "MST"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 3, 10, 2, 0, 0, -7 * 3600, false, "MST"); + + // No transition in Fall. + tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, false, "MST"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 11, 3, 2, 0, 0, -7 * 3600, false, "MST"); +} + +TEST(TimeZoneEdgeCase, AsiaKathmandu) { + const time_zone tz = LoadZone("Asia/Kathmandu"); + + // A non-DST offset change from +0530 to +0545 + // + // 504901799 == Tue, 31 Dec 1985 23:59:59 +0530 (+0530) + // 504901800 == Wed, 1 Jan 1986 00:15:00 +0545 (+0545) + auto tp = convert(civil_second(1985, 12, 31, 23, 59, 59), tz); + ExpectTime(tp, tz, 1985, 12, 31, 23, 59, 59, 5.5 * 3600, false, "+0530"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 1986, 1, 1, 0, 15, 0, 5.75 * 3600, false, "+0545"); +} + +TEST(TimeZoneEdgeCase, PacificChatham) { + const time_zone tz = LoadZone("Pacific/Chatham"); + + // One-hour DST offset changes, but at atypical values + // + // 1365256799 == Sun, 7 Apr 2013 03:44:59 +1345 (+1345) + // 1365256800 == Sun, 7 Apr 2013 02:45:00 +1245 (+1245) + auto tp = convert(civil_second(2013, 4, 7, 3, 44, 59), tz); + ExpectTime(tp, tz, 2013, 4, 7, 3, 44, 59, 13.75 * 3600, true, "+1345"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 4, 7, 2, 45, 0, 12.75 * 3600, false, "+1245"); + + // 1380376799 == Sun, 29 Sep 2013 02:44:59 +1245 (+1245) + // 1380376800 == Sun, 29 Sep 2013 03:45:00 +1345 (+1345) + tp = convert(civil_second(2013, 9, 29, 2, 44, 59), tz); + ExpectTime(tp, tz, 2013, 9, 29, 2, 44, 59, 12.75 * 3600, false, "+1245"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 9, 29, 3, 45, 0, 13.75 * 3600, true, "+1345"); +} + +TEST(TimeZoneEdgeCase, AustraliaLordHowe) { + const time_zone tz = LoadZone("Australia/Lord_Howe"); + + // Half-hour DST offset changes + // + // 1365260399 == Sun, 7 Apr 2013 01:59:59 +1100 (+11) + // 1365260400 == Sun, 7 Apr 2013 01:30:00 +1030 (+1030) + auto tp = convert(civil_second(2013, 4, 7, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 4, 7, 1, 59, 59, 11 * 3600, true, "+11"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 4, 7, 1, 30, 0, 10.5 * 3600, false, "+1030"); + + // 1380986999 == Sun, 6 Oct 2013 01:59:59 +1030 (+1030) + // 1380987000 == Sun, 6 Oct 2013 02:30:00 +1100 (+11) + tp = convert(civil_second(2013, 10, 6, 1, 59, 59), tz); + ExpectTime(tp, tz, 2013, 10, 6, 1, 59, 59, 10.5 * 3600, false, "+1030"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2013, 10, 6, 2, 30, 0, 11 * 3600, true, "+11"); +} + +TEST(TimeZoneEdgeCase, PacificApia) { + const time_zone tz = LoadZone("Pacific/Apia"); + + // At the end of December 2011, Samoa jumped forward by one day, + // skipping 30 December from the local calendar, when the nation + // moved to the west of the International Date Line. + // + // A one-day, non-DST offset change + // + // 1325239199 == Thu, 29 Dec 2011 23:59:59 -1000 (-10) + // 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14) + auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz); + ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10"); + EXPECT_EQ(363, get_yearday(convert(tp, tz))); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14"); + EXPECT_EQ(365, get_yearday(convert(tp, tz))); +} + +TEST(TimeZoneEdgeCase, AfricaCairo) { + const time_zone tz = LoadZone("Africa/Cairo"); + + if (VersionCmp(tz, "2014c") >= 0) { + // An interesting case of midnight not existing. + // + // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET) + // 1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST) + auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz); + ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST"); + } +} + +TEST(TimeZoneEdgeCase, AfricaMonrovia) { + const time_zone tz = LoadZone("Africa/Monrovia"); + + if (VersionCmp(tz, "2017b") >= 0) { + // Strange offset change -00:44:30 -> +00:00:00 (non-DST) + // + // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT) + // 63593070 == Fri, 7 Jan 1972 00:44:30 +0000 (GMT) + auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz); + ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT"); + } +} + +TEST(TimeZoneEdgeCase, AmericaJamaica) { + // Jamaica discontinued DST transitions in 1983, and is now at a + // constant -0500. This makes it an interesting edge-case target. + // Note that the 32-bit times used in a (tzh_version == 0) zoneinfo + // file cannot represent the abbreviation-only transition of 1890, + // so we ignore the abbreviation by expecting what we received. + const time_zone tz = LoadZone("America/Jamaica"); + + // Before the first transition. + if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) { + // We avoid the expectations on the -18430 offset below unless we are + // certain we have commit 907241e (Fix off-by-1 error for Jamaica and + // T&C before 1913) from 2018d. TODO: Remove the "version() not empty" + // part when 2018d is generally available from /usr/share/zoneinfo. + auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz); + ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false, + tz.lookup(tp).abbr); + + // Over the first (abbreviation-change only) transition. + // -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT) + // -2524503169 == Wed, 1 Jan 1890 00:00:00 -0507 (KMT) + tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz); + ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false, + tz.lookup(tp).abbr); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT"); + } + + // Over the last (DST) transition. + // 436341599 == Sun, 30 Oct 1983 01:59:59 -0400 (EDT) + // 436341600 == Sun, 30 Oct 1983 01:00:00 -0500 (EST) + auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz); + ExpectTime(tp, tz, 1983, 10, 30, 1, 59, 59, -4 * 3600, true, "EDT"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 1983, 10, 30, 1, 0, 0, -5 * 3600, false, "EST"); + + // After the last transition. + tp = convert(civil_second(1983, 12, 31, 23, 59, 59), tz); + ExpectTime(tp, tz, 1983, 12, 31, 23, 59, 59, -5 * 3600, false, "EST"); +} + +TEST(TimeZoneEdgeCase, WET) { + // Cover some non-existent times within forward transitions. + const time_zone tz = LoadZone("WET"); + + // Before the first transition. + auto tp = convert(civil_second(1977, 1, 1, 0, 0, 0), tz); + ExpectTime(tp, tz, 1977, 1, 1, 0, 0, 0, 0, false, "WET"); + + // Over the first transition. + // 228877199 == Sun, 3 Apr 1977 00:59:59 +0000 (WET) + // 228877200 == Sun, 3 Apr 1977 02:00:00 +0100 (WEST) + tp = convert(civil_second(1977, 4, 3, 0, 59, 59), tz); + ExpectTime(tp, tz, 1977, 4, 3, 0, 59, 59, 0, false, "WET"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST"); + + // A non-existent time within the first transition. + time_zone::civil_lookup cl1 = tz.lookup(civil_second(1977, 4, 3, 1, 15, 0)); + EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl1.kind); + ExpectTime(cl1.pre, tz, 1977, 4, 3, 2, 15, 0, 1 * 3600, true, "WEST"); + ExpectTime(cl1.trans, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST"); + ExpectTime(cl1.post, tz, 1977, 4, 3, 0, 15, 0, 0 * 3600, false, "WET"); + + // A non-existent time within the second forward transition. + time_zone::civil_lookup cl2 = tz.lookup(civil_second(1978, 4, 2, 1, 15, 0)); + EXPECT_EQ(time_zone::civil_lookup::SKIPPED, cl2.kind); + ExpectTime(cl2.pre, tz, 1978, 4, 2, 2, 15, 0, 1 * 3600, true, "WEST"); + ExpectTime(cl2.trans, tz, 1978, 4, 2, 2, 0, 0, 1 * 3600, true, "WEST"); + ExpectTime(cl2.post, tz, 1978, 4, 2, 0, 15, 0, 0 * 3600, false, "WET"); +} + +TEST(TimeZoneEdgeCase, FixedOffsets) { + const time_zone gmtm5 = LoadZone("Etc/GMT+5"); // -0500 + auto tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtm5); + ExpectTime(tp, gmtm5, 1970, 1, 1, 0, 0, 0, -5 * 3600, false, "-05"); + EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp); + + const time_zone gmtp5 = LoadZone("Etc/GMT-5"); // +0500 + tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtp5); + ExpectTime(tp, gmtp5, 1970, 1, 1, 0, 0, 0, 5 * 3600, false, "+05"); + EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp); +} + +TEST(TimeZoneEdgeCase, NegativeYear) { + // Tests transition from year 0 (aka 1BCE) to year -1. + const time_zone tz = utc_time_zone(); + auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz); + ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC"); + EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz))); + tp -= absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC"); + EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz))); +} + +TEST(TimeZoneEdgeCase, UTC32bitLimit) { + const time_zone tz = utc_time_zone(); + + // Limits of signed 32-bit time_t + // + // 2147483647 == Tue, 19 Jan 2038 03:14:07 +0000 (UTC) + // 2147483648 == Tue, 19 Jan 2038 03:14:08 +0000 (UTC) + auto tp = convert(civil_second(2038, 1, 19, 3, 14, 7), tz); + ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 7, 0 * 3600, false, "UTC"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 8, 0 * 3600, false, "UTC"); +} + +TEST(TimeZoneEdgeCase, UTC5DigitYear) { + const time_zone tz = utc_time_zone(); + + // Rollover to 5-digit year + // + // 253402300799 == Fri, 31 Dec 9999 23:59:59 +0000 (UTC) + // 253402300800 == Sat, 1 Jan 1000 00:00:00 +0000 (UTC) + auto tp = convert(civil_second(9999, 12, 31, 23, 59, 59), tz); + ExpectTime(tp, tz, 9999, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC"); + tp += absl::time_internal::cctz::seconds(1); + ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC"); +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_posix.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_posix.cc new file mode 100644 index 000000000000..5cdd09e89d0e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_posix.cc @@ -0,0 +1,159 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "time_zone_posix.h" + +#include <cstddef> +#include <cstring> +#include <limits> +#include <string> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +namespace { + +const char kDigits[] = "0123456789"; + +const char* ParseInt(const char* p, int min, int max, int* vp) { + int value = 0; + const char* op = p; + const int kMaxInt = std::numeric_limits<int>::max(); + for (; const char* dp = strchr(kDigits, *p); ++p) { + int d = static_cast<int>(dp - kDigits); + if (d >= 10) break; // '\0' + if (value > kMaxInt / 10) return nullptr; + value *= 10; + if (value > kMaxInt - d) return nullptr; + value += d; + } + if (p == op || value < min || value > max) return nullptr; + *vp = value; + return p; +} + +// abbr = <.*?> | [^-+,\d]{3,} +const char* ParseAbbr(const char* p, std::string* abbr) { + const char* op = p; + if (*p == '<') { // special zoneinfo <...> form + while (*++p != '>') { + if (*p == '\0') return nullptr; + } + abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1); + return ++p; + } + while (*p != '\0') { + if (strchr("-+,", *p)) break; + if (strchr(kDigits, *p)) break; + ++p; + } + if (p - op < 3) return nullptr; + abbr->assign(op, static_cast<std::size_t>(p - op)); + return p; +} + +// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value) +const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign, + std::int_fast32_t* offset) { + if (p == nullptr) return nullptr; + if (*p == '+' || *p == '-') { + if (*p++ == '-') sign = -sign; + } + int hours = 0; + int minutes = 0; + int seconds = 0; + + p = ParseInt(p, min_hour, max_hour, &hours); + if (p == nullptr) return nullptr; + if (*p == ':') { + p = ParseInt(p + 1, 0, 59, &minutes); + if (p == nullptr) return nullptr; + if (*p == ':') { + p = ParseInt(p + 1, 0, 59, &seconds); + if (p == nullptr) return nullptr; + } + } + *offset = sign * ((((hours * 60) + minutes) * 60) + seconds); + return p; +} + +// datetime = ( Jn | n | Mm.w.d ) [ / offset ] +const char* ParseDateTime(const char* p, PosixTransition* res) { + if (p != nullptr && *p == ',') { + if (*++p == 'M') { + int month = 0; + if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') { + int week = 0; + if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') { + int weekday = 0; + if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) { + res->date.fmt = PosixTransition::M; + res->date.m.month = static_cast<std::int_fast8_t>(month); + res->date.m.week = static_cast<std::int_fast8_t>(week); + res->date.m.weekday = static_cast<std::int_fast8_t>(weekday); + } + } + } + } else if (*p == 'J') { + int day = 0; + if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) { + res->date.fmt = PosixTransition::J; + res->date.j.day = static_cast<std::int_fast16_t>(day); + } + } else { + int day = 0; + if ((p = ParseInt(p, 0, 365, &day)) != nullptr) { + res->date.fmt = PosixTransition::N; + res->date.n.day = static_cast<std::int_fast16_t>(day); + } + } + } + if (p != nullptr) { + res->time.offset = 2 * 60 * 60; // default offset is 02:00:00 + if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset); + } + return p; +} + +} // namespace + +// spec = std offset [ dst [ offset ] , datetime , datetime ] +bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) { + const char* p = spec.c_str(); + if (*p == ':') return false; + + p = ParseAbbr(p, &res->std_abbr); + p = ParseOffset(p, 0, 24, -1, &res->std_offset); + if (p == nullptr) return false; + if (*p == '\0') return true; + + p = ParseAbbr(p, &res->dst_abbr); + if (p == nullptr) return false; + res->dst_offset = res->std_offset + (60 * 60); // default + if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset); + + p = ParseDateTime(p, &res->dst_start); + p = ParseDateTime(p, &res->dst_end); + + return p != nullptr && *p == '\0'; +} + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_posix.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_posix.h new file mode 100644 index 000000000000..0cf29055f56a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/time_zone_posix.h @@ -0,0 +1,132 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in +// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html. +// +// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0", +// which would be broken down as ... +// +// PosixTimeZone { +// std_abbr = "PST" +// std_offset = -28800 +// dst_abbr = "PDT" +// dst_offset = -25200 +// dst_start = PosixTransition { +// date { +// m { +// month = 3 +// week = 2 +// weekday = 0 +// } +// } +// time { +// offset = 7200 +// } +// } +// dst_end = PosixTransition { +// date { +// m { +// month = 11 +// week = 1 +// weekday = 0 +// } +// } +// time { +// offset = 7200 +// } +// } +// } + +#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_ +#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_ + +#include <cstdint> +#include <string> + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// The date/time of the transition. The date is specified as either: +// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or +// (N) the Nth day of the year (0 <= N <= 365), including leap days, or +// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March). +// The time, specified as a day offset, identifies the particular moment +// of the transition, and may be negative or >= 24h, and in which case +// it would take us to another day, and perhaps week, or even month. +struct PosixTransition { + enum DateFormat { J, N, M }; + + struct Date { + struct NonLeapDay { + std::int_fast16_t day; // day of non-leap year [1:365] + }; + struct Day { + std::int_fast16_t day; // day of year [0:365] + }; + struct MonthWeekWeekday { + std::int_fast8_t month; // month of year [1:12] + std::int_fast8_t week; // week of month [1:5] (5==last) + std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat + }; + + DateFormat fmt; + + union { + NonLeapDay j; + Day n; + MonthWeekWeekday m; + }; + }; + + struct Time { + std::int_fast32_t offset; // seconds before/after 00:00:00 + }; + + Date date; + Time time; +}; + +// The entirety of a POSIX-string specified time-zone rule. The standard +// abbreviation and offset are always given. If the time zone includes +// daylight saving, then the daylight abbrevation is non-empty and the +// remaining fields are also valid. Note that the start/end transitions +// are not ordered---in the southern hemisphere the transition to end +// daylight time occurs first in any particular year. +struct PosixTimeZone { + std::string std_abbr; + std::int_fast32_t std_offset; + + std::string dst_abbr; + std::int_fast32_t dst_offset; + PosixTransition dst_start; + PosixTransition dst_end; +}; + +// Breaks down a POSIX time-zone specification into its constituent pieces, +// filling in any missing values (DST offset, or start/end transition times) +// with the standard-defined defaults. Returns false if the specification +// could not be parsed (although some fields of *res may have been altered). +bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res); + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/tzfile.h b/third_party/abseil_cpp/absl/time/internal/cctz/src/tzfile.h new file mode 100644 index 000000000000..269fa36c537a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/tzfile.h @@ -0,0 +1,122 @@ +/* Layout and location of TZif files. */ + +#ifndef TZFILE_H + +#define TZFILE_H + +/* +** This file is in the public domain, so clarified as of +** 1996-06-05 by Arthur David Olson. +*/ + +/* +** This header is for use ONLY with the time conversion code. +** There is no guarantee that it will remain unchanged, +** or that it will remain at all. +** Do NOT copy it to any system include directory. +** Thank you! +*/ + +/* +** Information about time zone files. +*/ + +#ifndef TZDIR +#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */ +#endif /* !defined TZDIR */ + +#ifndef TZDEFAULT +#define TZDEFAULT "/etc/localtime" +#endif /* !defined TZDEFAULT */ + +#ifndef TZDEFRULES +#define TZDEFRULES "posixrules" +#endif /* !defined TZDEFRULES */ + +/* See Internet RFC 8536 for more details about the following format. */ + +/* +** Each file begins with. . . +*/ + +#define TZ_MAGIC "TZif" + +struct tzhead { + char tzh_magic[4]; /* TZ_MAGIC */ + char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */ + char tzh_reserved[15]; /* reserved; must be zero */ + char tzh_ttisutcnt[4]; /* coded number of trans. time flags */ + char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ + char tzh_leapcnt[4]; /* coded number of leap seconds */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ +}; + +/* +** . . .followed by. . . +** +** tzh_timecnt (char [4])s coded transition times a la time(2) +** tzh_timecnt (unsigned char)s types of local time starting at above +** tzh_typecnt repetitions of +** one (char [4]) coded UT offset in seconds +** one (unsigned char) used to set tm_isdst +** one (unsigned char) that's an abbreviation list index +** tzh_charcnt (char)s '\0'-terminated zone abbreviations +** tzh_leapcnt repetitions of +** one (char [4]) coded leap second transition times +** one (char [4]) total correction after above +** tzh_ttisstdcnt (char)s indexed by type; if 1, transition +** time is standard time, if 0, +** transition time is local (wall clock) +** time; if absent, transition times are +** assumed to be local time +** tzh_ttisutcnt (char)s indexed by type; if 1, transition +** time is UT, if 0, transition time is +** local time; if absent, transition +** times are assumed to be local time. +** When this is 1, the corresponding +** std/wall indicator must also be 1. +*/ + +/* +** If tzh_version is '2' or greater, the above is followed by a second instance +** of tzhead and a second instance of the data in which each coded transition +** time uses 8 rather than 4 chars, +** then a POSIX-TZ-environment-variable-style string for use in handling +** instants after the last transition time stored in the file +** (with nothing between the newlines if there is no POSIX representation for +** such instants). +** +** If tz_version is '3' or greater, the above is extended as follows. +** First, the POSIX TZ string's hour offset may range from -167 +** through 167 as compared to the POSIX-required 0 through 24. +** Second, its DST start time may be January 1 at 00:00 and its stop +** time December 31 at 24:00 plus the difference between DST and +** standard time, indicating DST all year. +*/ + +/* +** In the current implementation, "tzset()" refuses to deal with files that +** exceed any of the limits below. +*/ + +#ifndef TZ_MAX_TIMES +#define TZ_MAX_TIMES 2000 +#endif /* !defined TZ_MAX_TIMES */ + +#ifndef TZ_MAX_TYPES +/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */ +#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ +#endif /* !defined TZ_MAX_TYPES */ + +#ifndef TZ_MAX_CHARS +#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ + /* (limited by what unsigned chars can hold) */ +#endif /* !defined TZ_MAX_CHARS */ + +#ifndef TZ_MAX_LEAPS +#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ +#endif /* !defined TZ_MAX_LEAPS */ + +#endif /* !defined TZFILE_H */ diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/src/zone_info_source.cc b/third_party/abseil_cpp/absl/time/internal/cctz/src/zone_info_source.cc new file mode 100644 index 000000000000..72095339c3c1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/src/zone_info_source.cc @@ -0,0 +1,116 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/internal/cctz/include/cctz/zone_info_source.h" + +#include "absl/base/config.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz { + +// Defined out-of-line to avoid emitting a weak vtable in all TUs. +ZoneInfoSource::~ZoneInfoSource() {} +std::string ZoneInfoSource::Version() const { return std::string(); } + +} // namespace cctz +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz_extension { + +namespace { + +// A default for cctz_extension::zone_info_source_factory, which simply +// defers to the fallback factory. +std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory( + const std::string& name, + const std::function< + std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>( + const std::string& name)>& fallback_factory) { + return fallback_factory(name); +} + +} // namespace + +// A "weak" definition for cctz_extension::zone_info_source_factory. +// The user may override this with their own "strong" definition (see +// zone_info_source.h). +#if !defined(__has_attribute) +#define __has_attribute(x) 0 +#endif +// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the +// Windows linker cannot handle that. Nor does the MinGW compiler know how to +// pass "#pragma comment(linker, ...)" to the Windows linker. +#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__) +ZoneInfoSourceFactory zone_info_source_factory __attribute__((weak)) = + DefaultFactory; +#elif defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_LIBCPP_VERSION) +extern ZoneInfoSourceFactory zone_info_source_factory; +extern ZoneInfoSourceFactory default_factory; +ZoneInfoSourceFactory default_factory = DefaultFactory; +#if defined(_M_IX86) +#pragma comment( \ + linker, \ + "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@@ZA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@@ZA") +#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \ + defined(_M_ARM64) +#pragma comment( \ + linker, \ + "/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@@ZEA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \ + "@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \ + "@@ZEA") +#else +#error Unsupported MSVC platform +#endif // _M_<PLATFORM> +#else +// Make it a "strong" definition if we have no other choice. +ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory; +#endif + +} // namespace cctz_extension +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/README.zoneinfo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/README.zoneinfo new file mode 100644 index 000000000000..95fb4a91d17e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/README.zoneinfo @@ -0,0 +1,37 @@ +testdata/zoneinfo contains time-zone data files that may be used with CCTZ. +Install them in a location referenced by the ${TZDIR} environment variable. +Symbolic and hard links have been eliminated for portability. + +On Linux systems the distribution's versions of these files can probably +already be found in the default ${TZDIR} location, /usr/share/zoneinfo. + +New versions can be generated using the following shell script. + + #!/bin/sh - + set -e + DESTDIR=$(mktemp -d) + trap "rm -fr ${DESTDIR}" 0 2 15 + ( + cd ${DESTDIR} + git clone https://github.com/eggert/tz.git + make --directory=tz \ + install DESTDIR=${DESTDIR} \ + DATAFORM=vanguard \ + TZDIR=/zoneinfo \ + REDO=posix_only \ + LOCALTIME=Factory \ + TZDATA_TEXT= \ + ZONETABLES=zone1970.tab + tar --create --dereference --hard-dereference --file tzfile.tar \ + --directory=tz tzfile.h + tar --create --dereference --hard-dereference --file zoneinfo.tar \ + --exclude=zoneinfo/posixrules zoneinfo \ + --directory=tz version + ) + tar --extract --directory src --file ${DESTDIR}/tzfile.tar + tar --extract --directory testdata --file ${DESTDIR}/zoneinfo.tar + exit 0 + +To run the CCTZ tests using the testdata/zoneinfo files, execute: + + bazel test --test_env=TZDIR=${PWD}/testdata/zoneinfo ... diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/version b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/version new file mode 100644 index 000000000000..b4410dce16a3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/version @@ -0,0 +1 @@ +2020d diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Abidjan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra new file mode 100644 index 000000000000..9ca907bf9bb1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Accra Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Addis_Ababa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers new file mode 100644 index 000000000000..56a4dd2a19fa --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Algiers Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmara Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Asmera Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bamako Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bangui Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Banjul Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau new file mode 100644 index 000000000000..0da1d1e211bc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bissau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Blantyre Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Brazzaville Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Bujumbura Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo new file mode 100644 index 000000000000..ea38c970086c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Cairo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca new file mode 100644 index 000000000000..0263c90bd0d8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta new file mode 100644 index 000000000000..a461dceaa2ad --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ceuta Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Conakry Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dakar Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Dar_es_Salaam Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Djibouti Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Douala Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun new file mode 100644 index 000000000000..772e23c4cd8b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Freetown Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Gaborone Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Harare Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg new file mode 100644 index 000000000000..bada0638f8a2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Johannesburg Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba new file mode 100644 index 000000000000..36b05220ac00 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Juba Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kampala Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum new file mode 100644 index 000000000000..3f8e44b8a6e1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Khartoum Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kigali Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Kinshasa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lagos Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Libreville Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lome Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Luanda Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lubumbashi Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Lusaka Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Malabo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo new file mode 100644 index 000000000000..651e5cf67a54 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maputo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru new file mode 100644 index 000000000000..bada0638f8a2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Maseru Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane new file mode 100644 index 000000000000..bada0638f8a2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mbabane Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Mogadishu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia new file mode 100644 index 000000000000..837780922f23 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Monrovia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nairobi Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena new file mode 100644 index 000000000000..ecbc0966dc2d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ndjamena Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Niamey Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Nouakchott Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Ouagadougou Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo new file mode 100644 index 000000000000..2f2ce2f7728e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Porto-Novo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome new file mode 100644 index 000000000000..425ad3fda7c5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Sao_Tome Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Timbuktu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli new file mode 100644 index 000000000000..e0c89971aabe --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tripoli Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis new file mode 100644 index 000000000000..ca324cb4cd26 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Tunis Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek new file mode 100644 index 000000000000..0edc52b9b783 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Africa/Windhoek Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Adak b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Adak new file mode 100644 index 000000000000..b1497bda631e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Adak Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage new file mode 100644 index 000000000000..cdf0572be31d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Anchorage Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Anguilla Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Antigua Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina new file mode 100644 index 000000000000..f66c9f79d6cd --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Araguaina Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires new file mode 100644 index 000000000000..d6f999b8605c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Buenos_Aires Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca new file mode 100644 index 000000000000..1dcc8d85434c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Catamarca Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia new file mode 100644 index 000000000000..1dcc8d85434c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/ComodRivadavia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba new file mode 100644 index 000000000000..35a52e53d123 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Cordoba Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy new file mode 100644 index 000000000000..b275f27c0287 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Jujuy Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja new file mode 100644 index 000000000000..23fca1220522 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/La_Rioja Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza new file mode 100644 index 000000000000..691c56978a03 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Mendoza Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos new file mode 100644 index 000000000000..991d1fae69ee --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Rio_Gallegos Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta new file mode 100644 index 000000000000..58863e0436d1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Salta Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan new file mode 100644 index 000000000000..7eba33c1c5b1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Juan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis new file mode 100644 index 000000000000..0a81cbddfa28 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/San_Luis Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman new file mode 100644 index 000000000000..10556d5d856a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Tucuman Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia new file mode 100644 index 000000000000..e03175027692 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Argentina/Ushuaia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba new file mode 100644 index 000000000000..d6ddf7d8f6bf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Aruba Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion new file mode 100644 index 000000000000..622503674225 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Asuncion Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan new file mode 100644 index 000000000000..c82871528308 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Atikokan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Atka b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Atka new file mode 100644 index 000000000000..b1497bda631e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Atka Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia new file mode 100644 index 000000000000..7969e3076687 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas new file mode 100644 index 000000000000..cbe22a7622d8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bahia_Banderas Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados new file mode 100644 index 000000000000..9d3afa6a53bd --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Barbados Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Belem b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Belem new file mode 100644 index 000000000000..e0d7653c64c1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Belem Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Belize b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Belize new file mode 100644 index 000000000000..de99b845019f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Belize Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon new file mode 100644 index 000000000000..7096b69a564b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Blanc-Sablon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista new file mode 100644 index 000000000000..fca97207b283 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Boa_Vista Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota new file mode 100644 index 000000000000..6cb53d4e6125 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Bogota Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Boise b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Boise new file mode 100644 index 000000000000..72fec9e8c52a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Boise Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires new file mode 100644 index 000000000000..d6f999b8605c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Buenos_Aires Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay new file mode 100644 index 000000000000..0a2225244a67 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cambridge_Bay Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande new file mode 100644 index 000000000000..6855e4e9fe02 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Campo_Grande Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun new file mode 100644 index 000000000000..640b259fd0f8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cancun Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas new file mode 100644 index 000000000000..8dbe6ff74127 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Caracas Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca new file mode 100644 index 000000000000..1dcc8d85434c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Catamarca Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne new file mode 100644 index 000000000000..cd49f0534438 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cayenne Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman new file mode 100644 index 000000000000..9154643f4c91 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cayman Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago new file mode 100644 index 000000000000..b01688065392 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Chicago Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua new file mode 100644 index 000000000000..e1780a5750e3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Chihuahua Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour new file mode 100644 index 000000000000..c82871528308 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Coral_Harbour Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba new file mode 100644 index 000000000000..35a52e53d123 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cordoba Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica new file mode 100644 index 000000000000..08f0128ee681 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Costa_Rica Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Creston b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Creston new file mode 100644 index 000000000000..9d69a0ab819e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Creston Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba new file mode 100644 index 000000000000..c09a87558d53 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Cuiaba Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao new file mode 100644 index 000000000000..d6ddf7d8f6bf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Curacao Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn new file mode 100644 index 000000000000..8718efcce25c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Danmarkshavn Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson new file mode 100644 index 000000000000..07e4c5f4ac38 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek new file mode 100644 index 000000000000..761d1d9af536 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dawson_Creek Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Denver b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Denver new file mode 100644 index 000000000000..09e54e5c7c5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Denver Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit new file mode 100644 index 000000000000..6eb3ac46ec56 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Detroit Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Dominica Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton new file mode 100644 index 000000000000..645ee9453073 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe new file mode 100644 index 000000000000..7da4b98fe3c7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Eirunepe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador new file mode 100644 index 000000000000..43484117e285 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/El_Salvador Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada new file mode 100644 index 000000000000..19ccd3576d46 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Ensenada Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson new file mode 100644 index 000000000000..2a49c6c50f4c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Nelson Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne new file mode 100644 index 000000000000..6b08d15bdaba --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fort_Wayne Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza new file mode 100644 index 000000000000..092e40d70122 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Fortaleza Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay new file mode 100644 index 000000000000..f85eb3415758 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Glace_Bay Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab new file mode 100644 index 000000000000..4ddc99d8b74c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Godthab Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay new file mode 100644 index 000000000000..820e0dd2cd7e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Goose_Bay Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk new file mode 100644 index 000000000000..062fcaed8e07 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Grand_Turk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Grenada Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guadeloupe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala new file mode 100644 index 000000000000..8aa8e588e3cb --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guatemala Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil new file mode 100644 index 000000000000..381ae6c46326 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guayaquil Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana new file mode 100644 index 000000000000..ebd85d0f3e02 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Guyana Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax new file mode 100644 index 000000000000..9fa850a7d4c3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Halifax Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Havana b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Havana new file mode 100644 index 000000000000..e06629d36841 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Havana Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo new file mode 100644 index 000000000000..8283239ecab2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Hermosillo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis new file mode 100644 index 000000000000..6b08d15bdaba --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Indianapolis Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox new file mode 100644 index 000000000000..b187d5f8c756 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Knox Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo new file mode 100644 index 000000000000..a730fe666b65 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Marengo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg new file mode 100644 index 000000000000..341a0235ef48 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Petersburg Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City new file mode 100644 index 000000000000..76e1f6285b55 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Tell_City Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay new file mode 100644 index 000000000000..f2acf6cbbd65 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vevay Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes new file mode 100644 index 000000000000..c255f89b6da9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Vincennes Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac new file mode 100644 index 000000000000..8700ed9f065e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indiana/Winamac Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis new file mode 100644 index 000000000000..6b08d15bdaba --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Indianapolis Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik new file mode 100644 index 000000000000..af3107db51e3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Inuvik Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit new file mode 100644 index 000000000000..eb2c99cca53a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Iqaluit Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica new file mode 100644 index 000000000000..be6b1b6f1e77 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Jamaica Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy new file mode 100644 index 000000000000..b275f27c0287 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Jujuy Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau new file mode 100644 index 000000000000..e347b369f780 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Juneau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville new file mode 100644 index 000000000000..f2136d6ed41b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Louisville Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello new file mode 100644 index 000000000000..d9f54a18bbe6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kentucky/Monticello Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN new file mode 100644 index 000000000000..b187d5f8c756 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Knox_IN Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk new file mode 100644 index 000000000000..d6ddf7d8f6bf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Kralendijk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz new file mode 100644 index 000000000000..68ddaae768e6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/La_Paz Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Lima b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Lima new file mode 100644 index 000000000000..b643c5517f92 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Lima Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles new file mode 100644 index 000000000000..aaf07787ad92 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Los_Angeles Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville new file mode 100644 index 000000000000..f2136d6ed41b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Louisville Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes new file mode 100644 index 000000000000..d6ddf7d8f6bf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Lower_Princes Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio new file mode 100644 index 000000000000..dbb8d57d91d6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Maceio Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Managua b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Managua new file mode 100644 index 000000000000..86ef76bf2241 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Managua Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus new file mode 100644 index 000000000000..59c952ebc651 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Manaus Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Marigot Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique new file mode 100644 index 000000000000..25c0232d9549 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Martinique Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros new file mode 100644 index 000000000000..722751b20e52 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Matamoros Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan new file mode 100644 index 000000000000..4c819fab0247 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mazatlan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza new file mode 100644 index 000000000000..691c56978a03 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mendoza Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee new file mode 100644 index 000000000000..28d2c56e1a99 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Menominee Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Merida b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Merida new file mode 100644 index 000000000000..d3b0ca12c95f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Merida Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla new file mode 100644 index 000000000000..9fefee388e6f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Metlakatla Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City new file mode 100644 index 000000000000..ffcf8bee10e5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Mexico_City Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon new file mode 100644 index 000000000000..3b62585d0a13 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Miquelon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton new file mode 100644 index 000000000000..ecb69ef2c96a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Moncton Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey new file mode 100644 index 000000000000..dea9e3f5864f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Monterrey Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo new file mode 100644 index 000000000000..4b2fb3e560f6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montevideo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal new file mode 100644 index 000000000000..fe6be8ea8c97 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montreal Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Montserrat Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau new file mode 100644 index 000000000000..cf1e92dc0f53 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nassau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/New_York b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/New_York new file mode 100644 index 000000000000..2b6c2eea14df --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/New_York Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon new file mode 100644 index 000000000000..b9f67a9f9495 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nipigon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nome b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nome new file mode 100644 index 000000000000..23ead1c004ff --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nome Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha new file mode 100644 index 000000000000..9e74745ca791 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Noronha Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah new file mode 100644 index 000000000000..becf4383301e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Beulah Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center new file mode 100644 index 000000000000..d03bda045d31 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/Center Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem new file mode 100644 index 000000000000..ecefc15d8cdf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/North_Dakota/New_Salem Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk new file mode 100644 index 000000000000..4ddc99d8b74c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Nuuk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga new file mode 100644 index 000000000000..da0909cb212f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Ojinaga Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Panama b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Panama new file mode 100644 index 000000000000..9154643f4c91 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Panama Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung new file mode 100644 index 000000000000..5be6f9b0160d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Pangnirtung Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo new file mode 100644 index 000000000000..24f925a2dd33 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Paramaribo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix new file mode 100644 index 000000000000..c2bd2f949b24 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Phoenix Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince new file mode 100644 index 000000000000..3e75731baa7c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Port-au-Prince Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Port_of_Spain Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre new file mode 100644 index 000000000000..fb5185ca6028 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Acre Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho new file mode 100644 index 000000000000..7f8047d9396f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Porto_Velho Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico new file mode 100644 index 000000000000..47b4dc34160d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Puerto_Rico Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas new file mode 100644 index 000000000000..5c9a20b947f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Punta_Arenas Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River new file mode 100644 index 000000000000..d6ddda4822d3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rainy_River Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet new file mode 100644 index 000000000000..92e2ed2dbe0f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rankin_Inlet Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Recife b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Recife new file mode 100644 index 000000000000..305abcb8a221 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Recife Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Regina b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Regina new file mode 100644 index 000000000000..a3f8217a544e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Regina Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute new file mode 100644 index 000000000000..a84d1dfdb3a8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Resolute Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco new file mode 100644 index 000000000000..fb5185ca6028 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rio_Branco Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario new file mode 100644 index 000000000000..35a52e53d123 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Rosario Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel new file mode 100644 index 000000000000..19ccd3576d46 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santa_Isabel Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem new file mode 100644 index 000000000000..f81d144206ac --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santarem Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago new file mode 100644 index 000000000000..8d6032264b65 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santiago Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo new file mode 100644 index 000000000000..3e0785086639 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Santo_Domingo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo new file mode 100644 index 000000000000..a16da2c4d5a9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Sao_Paulo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund new file mode 100644 index 000000000000..6db49124e2bb --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Scoresbysund Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock new file mode 100644 index 000000000000..09e54e5c7c5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Shiprock Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka new file mode 100644 index 000000000000..36681ed78eaf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Sitka Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Barthelemy Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns new file mode 100644 index 000000000000..e5f2aec2bb2b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Johns Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Kitts Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Lucia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Thomas Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/St_Vincent Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current new file mode 100644 index 000000000000..bdbb494487de --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Swift_Current Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa new file mode 100644 index 000000000000..38036a32831d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tegucigalpa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Thule b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Thule new file mode 100644 index 000000000000..f38dc56bf20d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Thule Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay new file mode 100644 index 000000000000..fcb032804311 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Thunder_Bay Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana new file mode 100644 index 000000000000..19ccd3576d46 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tijuana Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto new file mode 100644 index 000000000000..fe6be8ea8c97 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Toronto Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Tortola Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver new file mode 100644 index 000000000000..c998491112ea --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Vancouver Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin new file mode 100644 index 000000000000..f4fe59034242 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Virgin Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse new file mode 100644 index 000000000000..878b6a92f740 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Whitehorse Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg new file mode 100644 index 000000000000..7e646d18e188 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Winnipeg Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat new file mode 100644 index 000000000000..773feba89d36 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Yakutat Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife new file mode 100644 index 000000000000..c779cef92c8a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey new file mode 100644 index 000000000000..30315cc07893 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Casey Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis new file mode 100644 index 000000000000..3ec32224f298 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Davis Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville new file mode 100644 index 000000000000..c0cfc85a29e8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/DumontDUrville Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie new file mode 100644 index 000000000000..232717b613f1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Macquarie Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson new file mode 100644 index 000000000000..05e4c6c58673 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Mawson Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo new file mode 100644 index 000000000000..afb392931847 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/McMurdo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer new file mode 100644 index 000000000000..32c1941634ae --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Palmer Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera new file mode 100644 index 000000000000..ea49c00b2240 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Rothera Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole new file mode 100644 index 000000000000..afb392931847 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/South_Pole Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa new file mode 100644 index 000000000000..97d80d752c8e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Syowa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll new file mode 100644 index 000000000000..4e31affb50e3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Troll Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok new file mode 100644 index 000000000000..6e3290717e5a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Antarctica/Vostok Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen new file mode 100644 index 000000000000..dfc509570a5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Arctic/Longyearbyen Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden new file mode 100644 index 000000000000..01c47ccb86cc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aden Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty new file mode 100644 index 000000000000..3ec4fc89fe99 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Almaty Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman new file mode 100644 index 000000000000..1bd09fef27c9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Amman Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr new file mode 100644 index 000000000000..551884d322bc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Anadyr Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau new file mode 100644 index 000000000000..3a40d1175a7d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe new file mode 100644 index 000000000000..62c5840a83e2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Aqtobe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat new file mode 100644 index 000000000000..848216726908 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashgabat Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad new file mode 100644 index 000000000000..848216726908 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ashkhabad Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau new file mode 100644 index 000000000000..cb2c82f657c7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Atyrau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad new file mode 100644 index 000000000000..a3ce97599100 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baghdad Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain new file mode 100644 index 000000000000..7409d74983c8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bahrain Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku new file mode 100644 index 000000000000..96203d7a4266 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Baku Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok new file mode 100644 index 000000000000..ed687d2985c2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bangkok Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul new file mode 100644 index 000000000000..ff976dd3b27a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Barnaul Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut new file mode 100644 index 000000000000..55dce5722cc9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Beirut Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek new file mode 100644 index 000000000000..fe7832cdf99e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Bishkek Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei new file mode 100644 index 000000000000..e67b411b9f5a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Brunei Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta new file mode 100644 index 000000000000..00bc80a65e9a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Calcutta Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita new file mode 100644 index 000000000000..9d49cd35cd5e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chita Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan new file mode 100644 index 000000000000..0a948c2eaca3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Choibalsan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing new file mode 100644 index 000000000000..d6b66984a2f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chongqing Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking new file mode 100644 index 000000000000..d6b66984a2f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Chungking Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo new file mode 100644 index 000000000000..3eeb1b72b689 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Colombo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca new file mode 100644 index 000000000000..28136808b6d1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dacca Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus new file mode 100644 index 000000000000..168ef9baa47e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Damascus Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka new file mode 100644 index 000000000000..28136808b6d1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dhaka Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili new file mode 100644 index 000000000000..bb7be9f3a471 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dili Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai new file mode 100644 index 000000000000..58d75bc26eec --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dubai Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe new file mode 100644 index 000000000000..d83fb076a256 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Dushanbe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta new file mode 100644 index 000000000000..cc44179564af --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Famagusta Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza new file mode 100644 index 000000000000..4278ffa512b3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Gaza Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin new file mode 100644 index 000000000000..d6b66984a2f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Harbin Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron new file mode 100644 index 000000000000..e55318aaca8c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hebron Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh new file mode 100644 index 000000000000..7ca997250288 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ho_Chi_Minh Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong new file mode 100644 index 000000000000..c80e364801be --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hong_Kong Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd new file mode 100644 index 000000000000..6e08a261274e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Hovd Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk new file mode 100644 index 000000000000..550e2a08773b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Irkutsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul new file mode 100644 index 000000000000..c89186687300 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Istanbul Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta new file mode 100644 index 000000000000..c9752d2f23eb --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jakarta Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura new file mode 100644 index 000000000000..7c22f539d948 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jayapura Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem new file mode 100644 index 000000000000..e6e6cc6ca584 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Jerusalem Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul new file mode 100644 index 000000000000..660ce4cf6957 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kabul Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka new file mode 100644 index 000000000000..c65155402db6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kamchatka Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi new file mode 100644 index 000000000000..e56d5afdafb2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Karachi Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar new file mode 100644 index 000000000000..69ff7f6fb497 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kashgar Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu new file mode 100644 index 000000000000..3a0d330ffd2f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kathmandu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu new file mode 100644 index 000000000000..3a0d330ffd2f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Katmandu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga new file mode 100644 index 000000000000..aeb733202acd --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Khandyga Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata new file mode 100644 index 000000000000..00bc80a65e9a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kolkata Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk new file mode 100644 index 000000000000..e0d4fcb5c3d7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Krasnoyarsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur new file mode 100644 index 000000000000..e93dd5141bca --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuala_Lumpur Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching new file mode 100644 index 000000000000..59bc6e40b7bb --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuching Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait new file mode 100644 index 000000000000..01c47ccb86cc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Kuwait Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao new file mode 100644 index 000000000000..c22f75e42db6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macao Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau new file mode 100644 index 000000000000..c22f75e42db6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Macau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan new file mode 100644 index 000000000000..16bac8444656 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Magadan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar new file mode 100644 index 000000000000..5990010b6497 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Makassar Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila new file mode 100644 index 000000000000..3c3584e09ae4 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Manila Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat new file mode 100644 index 000000000000..58d75bc26eec --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Muscat Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia new file mode 100644 index 000000000000..c210d0a5989c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Nicosia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk new file mode 100644 index 000000000000..9378d50539df --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novokuznetsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk new file mode 100644 index 000000000000..65a9fa2cd2e8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Novosibirsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk new file mode 100644 index 000000000000..dc0ed422f619 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Omsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral new file mode 100644 index 000000000000..25a63ec8b995 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Oral Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh new file mode 100644 index 000000000000..ed687d2985c2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Phnom_Penh Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak new file mode 100644 index 000000000000..285bed2c63a5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pontianak Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang new file mode 100644 index 000000000000..57240cf89fb3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Pyongyang Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar new file mode 100644 index 000000000000..7409d74983c8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qatar Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay new file mode 100644 index 000000000000..ff6fe61d5075 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qostanay Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda new file mode 100644 index 000000000000..fe4d6c6d6d44 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Qyzylorda Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon new file mode 100644 index 000000000000..14b2ad09ead5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Rangoon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh new file mode 100644 index 000000000000..01c47ccb86cc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Riyadh Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon new file mode 100644 index 000000000000..7ca997250288 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Saigon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin new file mode 100644 index 000000000000..69f0faad1e72 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Sakhalin Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand new file mode 100644 index 000000000000..c43e27c5d4bd --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Samarkand Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul new file mode 100644 index 000000000000..1755147fab44 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Seoul Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai new file mode 100644 index 000000000000..d6b66984a2f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Shanghai Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore new file mode 100644 index 000000000000..350d77e28ee7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Singapore Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk new file mode 100644 index 000000000000..7fdee5cbee2b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Srednekolymsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei new file mode 100644 index 000000000000..35d89d036d07 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Taipei Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent new file mode 100644 index 000000000000..65ee428ce1c5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tashkent Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi new file mode 100644 index 000000000000..166e4341d6ce --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tbilisi Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran new file mode 100644 index 000000000000..f1555f0032f5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tehran Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv new file mode 100644 index 000000000000..e6e6cc6ca584 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tel_Aviv Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu new file mode 100644 index 000000000000..0edc72cfe46b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimbu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu new file mode 100644 index 000000000000..0edc72cfe46b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Thimphu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo new file mode 100644 index 000000000000..1aa066ce38fc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tokyo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk new file mode 100644 index 000000000000..c3c307d7b99f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Tomsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang new file mode 100644 index 000000000000..5990010b6497 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ujung_Pandang Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar new file mode 100644 index 000000000000..6f5d3a15abbe --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulaanbaatar Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator new file mode 100644 index 000000000000..6f5d3a15abbe --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ulan_Bator Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi new file mode 100644 index 000000000000..69ff7f6fb497 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Urumqi Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera new file mode 100644 index 000000000000..c39331e3aa7d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Ust-Nera Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane new file mode 100644 index 000000000000..ed687d2985c2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vientiane Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok new file mode 100644 index 000000000000..72a3d4e87a0d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Vladivostok Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk new file mode 100644 index 000000000000..336f932e8d45 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yakutsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon new file mode 100644 index 000000000000..14b2ad09ead5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yangon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg new file mode 100644 index 000000000000..a3bf7f29b6f1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yekaterinburg Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan new file mode 100644 index 000000000000..6dd927cb9410 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Asia/Yerevan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores new file mode 100644 index 000000000000..b7f75a9cf650 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Azores Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda new file mode 100644 index 000000000000..aa3301478f72 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Bermuda Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary new file mode 100644 index 000000000000..5ab3243a5f01 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Canary Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde new file mode 100644 index 000000000000..8f7de1c0a19a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Cape_Verde Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe new file mode 100644 index 000000000000..9558bf7180ac --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faeroe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe new file mode 100644 index 000000000000..9558bf7180ac --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Faroe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen new file mode 100644 index 000000000000..dfc509570a5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Jan_Mayen Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira new file mode 100644 index 000000000000..7c3a49c0e8cd --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Madeira Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik new file mode 100644 index 000000000000..2451aca76d7c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Reykjavik Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia new file mode 100644 index 000000000000..7fa5f4683538 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/South_Georgia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena new file mode 100644 index 000000000000..8906e88c819d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/St_Helena Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley new file mode 100644 index 000000000000..1a4c8ea86361 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Atlantic/Stanley Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT new file mode 100644 index 000000000000..f235d0dc742a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/ACT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide new file mode 100644 index 000000000000..f397b3b9eda6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Adelaide Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane new file mode 100644 index 000000000000..c7915db30bae --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Brisbane Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill new file mode 100644 index 000000000000..ed0d17a610e0 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Broken_Hill Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra new file mode 100644 index 000000000000..f235d0dc742a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Canberra Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie new file mode 100644 index 000000000000..55ceaefc6075 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Currie Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin new file mode 100644 index 000000000000..7114153b65c3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Darwin Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla new file mode 100644 index 000000000000..9fbc01fe6779 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Eucla Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart new file mode 100644 index 000000000000..21ef2d396f6b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Hobart Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI new file mode 100644 index 000000000000..4d4ec8ceea9a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/LHI Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman new file mode 100644 index 000000000000..e271d5b3e50e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lindeman Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe new file mode 100644 index 000000000000..4d4ec8ceea9a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Lord_Howe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne new file mode 100644 index 000000000000..c7160da33f3e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Melbourne Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW new file mode 100644 index 000000000000..f235d0dc742a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/NSW Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/North b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/North new file mode 100644 index 000000000000..7114153b65c3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/North Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth new file mode 100644 index 000000000000..e449b03fcf25 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Perth Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland new file mode 100644 index 000000000000..c7915db30bae --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Queensland Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/South b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/South new file mode 100644 index 000000000000..f397b3b9eda6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/South Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney new file mode 100644 index 000000000000..f235d0dc742a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Sydney Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania new file mode 100644 index 000000000000..21ef2d396f6b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Tasmania Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria new file mode 100644 index 000000000000..c7160da33f3e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Victoria Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/West b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/West new file mode 100644 index 000000000000..e449b03fcf25 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/West Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna new file mode 100644 index 000000000000..ed0d17a610e0 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Australia/Yancowinna Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre new file mode 100644 index 000000000000..fb5185ca6028 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/Acre Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha new file mode 100644 index 000000000000..9e74745ca791 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/DeNoronha Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East new file mode 100644 index 000000000000..a16da2c4d5a9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/East Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West new file mode 100644 index 000000000000..59c952ebc651 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Brazil/West Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/CET b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/CET new file mode 100644 index 000000000000..546748d6eace --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/CET Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT new file mode 100644 index 000000000000..d9315580584f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/CST6CDT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic new file mode 100644 index 000000000000..9fa850a7d4c3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Atlantic Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central new file mode 100644 index 000000000000..7e646d18e188 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Central Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern new file mode 100644 index 000000000000..fe6be8ea8c97 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Eastern Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain new file mode 100644 index 000000000000..645ee9453073 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland new file mode 100644 index 000000000000..e5f2aec2bb2b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Newfoundland Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific new file mode 100644 index 000000000000..c998491112ea --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Pacific Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan new file mode 100644 index 000000000000..a3f8217a544e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Saskatchewan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon new file mode 100644 index 000000000000..878b6a92f740 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Canada/Yukon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental new file mode 100644 index 000000000000..8d6032264b65 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Chile/Continental Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland new file mode 100644 index 000000000000..d29bcd68b020 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Chile/EasterIsland Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Cuba b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Cuba new file mode 100644 index 000000000000..e06629d36841 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Cuba Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EET b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EET new file mode 100644 index 000000000000..378919ea1131 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EET Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EST b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EST new file mode 100644 index 000000000000..3ae969114563 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EST Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT new file mode 100644 index 000000000000..50c95e0cb076 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/EST5EDT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Egypt b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Egypt new file mode 100644 index 000000000000..ea38c970086c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Egypt Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Eire b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Eire new file mode 100644 index 000000000000..4a45ea8f73f8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Eire Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+0 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 new file mode 100644 index 000000000000..98d5dcf917c6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+1 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 new file mode 100644 index 000000000000..ecb287e66786 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+10 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 new file mode 100644 index 000000000000..e941412971a4 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+11 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 new file mode 100644 index 000000000000..9c95bd0736da --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+12 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 new file mode 100644 index 000000000000..6d5ce3db7323 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+2 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 new file mode 100644 index 000000000000..5ef7be71fd96 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+3 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 new file mode 100644 index 000000000000..75f16216f0d3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+4 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 new file mode 100644 index 000000000000..589990ae8966 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+5 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 new file mode 100644 index 000000000000..fcb60ca2465a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+6 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 new file mode 100644 index 000000000000..c0427a40eef9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+7 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 new file mode 100644 index 000000000000..9bdc2283c07d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+8 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 new file mode 100644 index 000000000000..ca7a81f656f2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT+9 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-0 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 new file mode 100644 index 000000000000..cb45601c958d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-1 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 new file mode 100644 index 000000000000..11d988e10a3e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-10 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 new file mode 100644 index 000000000000..f4c5d5cc29b5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-11 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 new file mode 100644 index 000000000000..cd397b02cdde --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-12 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 new file mode 100644 index 000000000000..8fad7c6b0bef --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-13 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 new file mode 100644 index 000000000000..a595e60eeae1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-14 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 new file mode 100644 index 000000000000..97b44a9baecf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-2 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 new file mode 100644 index 000000000000..4eb17ff0057b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-3 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 new file mode 100644 index 000000000000..13aef80cbbcf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-4 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 new file mode 100644 index 000000000000..83a28169552f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-5 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 new file mode 100644 index 000000000000..79a983e5454a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-6 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 new file mode 100644 index 000000000000..e136690e165a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-7 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 new file mode 100644 index 000000000000..bc70fe416fdb --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-8 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 new file mode 100644 index 000000000000..d18cedd524f4 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT-9 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/GMT0 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Greenwich Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/UCT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/UTC Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Universal Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Etc/Zulu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam new file mode 100644 index 000000000000..4a6fa1d4945d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Amsterdam Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra new file mode 100644 index 000000000000..38685d4219d2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Andorra Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan new file mode 100644 index 000000000000..aff8d82d2a2d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Astrakhan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens new file mode 100644 index 000000000000..231bf9c3b713 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Athens Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belfast Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade new file mode 100644 index 000000000000..a1bf9281ed1b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Belgrade Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin new file mode 100644 index 000000000000..465546bd396a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Berlin Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava new file mode 100644 index 000000000000..fb7c145ac4c8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bratislava Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels new file mode 100644 index 000000000000..31973271d2f8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Brussels Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest new file mode 100644 index 000000000000..efa689ba9e0a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Bucharest Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest new file mode 100644 index 000000000000..940be4670a64 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Budapest Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen new file mode 100644 index 000000000000..388df2969f2d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Busingen Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau new file mode 100644 index 000000000000..6970b14c506c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Chisinau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen new file mode 100644 index 000000000000..45984a7599d2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Copenhagen Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin new file mode 100644 index 000000000000..4a45ea8f73f8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Dublin Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar new file mode 100644 index 000000000000..017bb2e34746 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Gibraltar Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Guernsey Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki new file mode 100644 index 000000000000..ff5e56530570 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Helsinki Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Isle_of_Man Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul new file mode 100644 index 000000000000..c89186687300 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Istanbul Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Jersey Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad new file mode 100644 index 000000000000..0ec475647055 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kaliningrad Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev new file mode 100644 index 000000000000..8f83cefbcc11 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kiev Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov new file mode 100644 index 000000000000..d1c93c540c26 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Kirov Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon new file mode 100644 index 000000000000..64841661a01a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Lisbon Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana new file mode 100644 index 000000000000..a1bf9281ed1b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ljubljana Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/London b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/London new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/London Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg new file mode 100644 index 000000000000..682bcbf61ac7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Luxembourg Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid new file mode 100644 index 000000000000..60bdf4d07e6e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Madrid Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta new file mode 100644 index 000000000000..27539c2243ff --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Malta Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn new file mode 100644 index 000000000000..ff5e56530570 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Mariehamn Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk new file mode 100644 index 000000000000..30d3a672bf64 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Minsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco new file mode 100644 index 000000000000..f30dfc7014f4 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Monaco Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow new file mode 100644 index 000000000000..5e6b6de6451b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Moscow Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia new file mode 100644 index 000000000000..c210d0a5989c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Nicosia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo new file mode 100644 index 000000000000..dfc509570a5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Oslo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris new file mode 100644 index 000000000000..00a27264c2cb --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Paris Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica new file mode 100644 index 000000000000..a1bf9281ed1b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Podgorica Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague new file mode 100644 index 000000000000..fb7c145ac4c8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Prague Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga new file mode 100644 index 000000000000..26af4c90b3b7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Riga Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome new file mode 100644 index 000000000000..639ca3be4062 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Rome Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara new file mode 100644 index 000000000000..8d0c26e5c852 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Samara Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino new file mode 100644 index 000000000000..639ca3be4062 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/San_Marino Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo new file mode 100644 index 000000000000..a1bf9281ed1b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sarajevo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov new file mode 100644 index 000000000000..2684d8f8b89f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Saratov Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol new file mode 100644 index 000000000000..88a6f3bdb469 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Simferopol Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje new file mode 100644 index 000000000000..a1bf9281ed1b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Skopje Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia new file mode 100644 index 000000000000..eabc972a22df --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Sofia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm new file mode 100644 index 000000000000..dd3eb3227852 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Stockholm Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn new file mode 100644 index 000000000000..5321bbd46e7a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tallinn Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane new file mode 100644 index 000000000000..743a7337ffd8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tirane Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol new file mode 100644 index 000000000000..6970b14c506c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Tiraspol Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk new file mode 100644 index 000000000000..bb842cb1f508 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Ulyanovsk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod new file mode 100644 index 000000000000..a5755685e390 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Uzhgorod Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz new file mode 100644 index 000000000000..388df2969f2d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vaduz Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican new file mode 100644 index 000000000000..639ca3be4062 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vatican Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna new file mode 100644 index 000000000000..75339e98d0a7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vienna Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius new file mode 100644 index 000000000000..75b2eebb57c5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Vilnius Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd new file mode 100644 index 000000000000..a486ad42eac2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Volgograd Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw new file mode 100644 index 000000000000..efe1a40f2a8f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Warsaw Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb new file mode 100644 index 000000000000..a1bf9281ed1b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zagreb Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye new file mode 100644 index 000000000000..4ea8dae45a6f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zaporozhye Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich new file mode 100644 index 000000000000..388df2969f2d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Europe/Zurich Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Factory b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Factory new file mode 100644 index 000000000000..b4dd7735ed5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Factory Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GB b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GB new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GB Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire new file mode 100644 index 000000000000..323cd3818ac6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GB-Eire Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT+0 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT-0 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT0 b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT0 new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/GMT0 Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Greenwich b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Greenwich new file mode 100644 index 000000000000..157573b1d340 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Greenwich Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/HST b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/HST new file mode 100644 index 000000000000..160a53e045c8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/HST Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Hongkong b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Hongkong new file mode 100644 index 000000000000..c80e364801be --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Hongkong Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Iceland b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Iceland new file mode 100644 index 000000000000..2451aca76d7c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Iceland Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Antananarivo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos new file mode 100644 index 000000000000..8b8ce226b6b7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Chagos Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas new file mode 100644 index 000000000000..766024b36c50 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Christmas Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos new file mode 100644 index 000000000000..117503410ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Cocos Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Comoro Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen new file mode 100644 index 000000000000..8ce93e01247e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Kerguelen Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe new file mode 100644 index 000000000000..75362bbf033d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mahe Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives new file mode 100644 index 000000000000..58a82e4eb701 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Maldives Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius new file mode 100644 index 000000000000..7c1113488200 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mauritius Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte new file mode 100644 index 000000000000..d3c0bb328ce9 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Mayotte Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion new file mode 100644 index 000000000000..248a7c93a52b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Indian/Reunion Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Iran b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Iran new file mode 100644 index 000000000000..f1555f0032f5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Iran Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Israel b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Israel new file mode 100644 index 000000000000..e6e6cc6ca584 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Israel Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Jamaica b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Jamaica new file mode 100644 index 000000000000..be6b1b6f1e77 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Jamaica Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Japan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Japan new file mode 100644 index 000000000000..1aa066ce38fc --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Japan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein new file mode 100644 index 000000000000..9416d522d0a3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Kwajalein Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Libya b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Libya new file mode 100644 index 000000000000..e0c89971aabe --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Libya Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MET b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MET new file mode 100644 index 000000000000..6f0558c3b6f4 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MET Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MST b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MST new file mode 100644 index 000000000000..a0953d1e791e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MST Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT new file mode 100644 index 000000000000..137867c8bf5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/MST7MDT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte new file mode 100644 index 000000000000..19ccd3576d46 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaNorte Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur new file mode 100644 index 000000000000..4c819fab0247 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/BajaSur Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General new file mode 100644 index 000000000000..ffcf8bee10e5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Mexico/General Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/NZ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/NZ new file mode 100644 index 000000000000..afb392931847 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/NZ Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT new file mode 100644 index 000000000000..f06065ebd183 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/NZ-CHAT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Navajo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Navajo new file mode 100644 index 000000000000..09e54e5c7c5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Navajo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/PRC b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/PRC new file mode 100644 index 000000000000..d6b66984a2f3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/PRC Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT new file mode 100644 index 000000000000..fde4833f6be3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/PST8PDT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia new file mode 100644 index 000000000000..244af26f8a2f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Apia Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland new file mode 100644 index 000000000000..afb392931847 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Auckland Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville new file mode 100644 index 000000000000..7c667093c50d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Bougainville Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham new file mode 100644 index 000000000000..f06065ebd183 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chatham Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk new file mode 100644 index 000000000000..ea3fb5cd3c9e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Chuuk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter new file mode 100644 index 000000000000..d29bcd68b020 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Easter Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate new file mode 100644 index 000000000000..906971e2cecf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Efate Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury new file mode 100644 index 000000000000..b22ab147c3b6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Enderbury Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo new file mode 100644 index 000000000000..b7b30213e154 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fakaofo Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji new file mode 100644 index 000000000000..e3934e423c9c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Fiji Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti new file mode 100644 index 000000000000..78ab35b6b02f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Funafuti Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos new file mode 100644 index 000000000000..a9403eca467d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Galapagos Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier new file mode 100644 index 000000000000..ddfc34ffc097 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Gambier Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal new file mode 100644 index 000000000000..720c67901740 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guadalcanal Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam new file mode 100644 index 000000000000..bf9a2d955fc2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Guam Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu new file mode 100644 index 000000000000..40e3d492e6c2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Honolulu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston new file mode 100644 index 000000000000..40e3d492e6c2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Johnston Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati new file mode 100644 index 000000000000..2f676d3bf5c8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kiritimati Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae new file mode 100644 index 000000000000..f5d58242c819 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kosrae Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein new file mode 100644 index 000000000000..9416d522d0a3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Kwajalein Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro new file mode 100644 index 000000000000..9228ee02ede2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Majuro Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas new file mode 100644 index 000000000000..6ea24b72cd95 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Marquesas Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway new file mode 100644 index 000000000000..001289ceecff --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Midway Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru new file mode 100644 index 000000000000..ae13aac7792a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Nauru Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue new file mode 100644 index 000000000000..7b3579351395 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Niue Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk new file mode 100644 index 000000000000..79e2a9419adf --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Norfolk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea new file mode 100644 index 000000000000..824f814160ee --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Noumea Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago new file mode 100644 index 000000000000..001289ceecff --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pago_Pago Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau new file mode 100644 index 000000000000..bc8eb7a55b8a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Palau Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn new file mode 100644 index 000000000000..8a4ba4d30a6b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pitcairn Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei new file mode 100644 index 000000000000..b92b254a9af1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Pohnpei Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape new file mode 100644 index 000000000000..b92b254a9af1 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Ponape Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby new file mode 100644 index 000000000000..5d8fc3a1b253 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Port_Moresby Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga new file mode 100644 index 000000000000..143a1883b0f8 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Rarotonga Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan new file mode 100644 index 000000000000..bf9a2d955fc2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Saipan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa new file mode 100644 index 000000000000..001289ceecff --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Samoa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti new file mode 100644 index 000000000000..50a064fa0166 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tahiti Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa new file mode 100644 index 000000000000..6bc216823e00 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tarawa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu new file mode 100644 index 000000000000..54aeb0ffa227 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Tongatapu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk new file mode 100644 index 000000000000..ea3fb5cd3c9e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Truk Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake new file mode 100644 index 000000000000..71cca8877d33 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wake Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis new file mode 100644 index 000000000000..4bce89300306 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Wallis Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap new file mode 100644 index 000000000000..ea3fb5cd3c9e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Pacific/Yap Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Poland b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Poland new file mode 100644 index 000000000000..efe1a40f2a8f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Poland Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Portugal b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Portugal new file mode 100644 index 000000000000..64841661a01a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Portugal Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/ROC b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/ROC new file mode 100644 index 000000000000..35d89d036d07 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/ROC Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/ROK b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/ROK new file mode 100644 index 000000000000..1755147fab44 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/ROK Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Singapore b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Singapore new file mode 100644 index 000000000000..350d77e28ee7 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Singapore Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Turkey b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Turkey new file mode 100644 index 000000000000..c89186687300 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Turkey Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/UCT b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/UCT new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/UCT Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska new file mode 100644 index 000000000000..cdf0572be31d --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Alaska Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian new file mode 100644 index 000000000000..b1497bda631e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Aleutian Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona new file mode 100644 index 000000000000..c2bd2f949b24 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Arizona Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Central b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Central new file mode 100644 index 000000000000..b01688065392 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Central Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana new file mode 100644 index 000000000000..6b08d15bdaba --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/East-Indiana Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern new file mode 100644 index 000000000000..2b6c2eea14df --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Eastern Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii new file mode 100644 index 000000000000..40e3d492e6c2 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Hawaii Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke new file mode 100644 index 000000000000..b187d5f8c756 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Indiana-Starke Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan new file mode 100644 index 000000000000..6eb3ac46ec56 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Michigan Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain new file mode 100644 index 000000000000..09e54e5c7c5b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Mountain Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific new file mode 100644 index 000000000000..aaf07787ad92 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Pacific Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa new file mode 100644 index 000000000000..001289ceecff --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/US/Samoa Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/UTC b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/UTC new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/UTC Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Universal b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Universal new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Universal Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/W-SU b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/W-SU new file mode 100644 index 000000000000..5e6b6de6451b --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/W-SU Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/WET b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/WET new file mode 100644 index 000000000000..423c6c203a50 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/WET Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Zulu b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Zulu new file mode 100644 index 000000000000..00841a62213e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/Zulu Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab new file mode 100644 index 000000000000..a4ff61a4d321 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/iso3166.tab @@ -0,0 +1,274 @@ +# ISO 3166 alpha-2 country codes +# +# This file is in the public domain, so clarified as of +# 2009-05-17 by Arthur David Olson. +# +# From Paul Eggert (2015-05-02): +# This file contains a table of two-letter country codes. Columns are +# separated by a single tab. Lines beginning with '#' are comments. +# All text uses UTF-8 encoding. The columns of the table are as follows: +# +# 1. ISO 3166-1 alpha-2 country code, current as of +# ISO 3166-1 N976 (2018-11-06). See: Updates on ISO 3166-1 +# https://isotc.iso.org/livelink/livelink/Open/16944257 +# 2. The usual English name for the coded region, +# chosen so that alphabetic sorting of subsets produces helpful lists. +# This is not the same as the English name in the ISO 3166 tables. +# +# The table is sorted by country code. +# +# This table is intended as an aid for users, to help them select time +# zone data appropriate for their practical needs. It is not intended +# to take or endorse any position on legal or territorial claims. +# +#country- +#code name of country, territory, area, or subdivision +AD Andorra +AE United Arab Emirates +AF Afghanistan +AG Antigua & Barbuda +AI Anguilla +AL Albania +AM Armenia +AO Angola +AQ Antarctica +AR Argentina +AS Samoa (American) +AT Austria +AU Australia +AW Aruba +AX ร land Islands +AZ Azerbaijan +BA Bosnia & Herzegovina +BB Barbados +BD Bangladesh +BE Belgium +BF Burkina Faso +BG Bulgaria +BH Bahrain +BI Burundi +BJ Benin +BL St Barthelemy +BM Bermuda +BN Brunei +BO Bolivia +BQ Caribbean NL +BR Brazil +BS Bahamas +BT Bhutan +BV Bouvet Island +BW Botswana +BY Belarus +BZ Belize +CA Canada +CC Cocos (Keeling) Islands +CD Congo (Dem. Rep.) +CF Central African Rep. +CG Congo (Rep.) +CH Switzerland +CI Cรดte d'Ivoire +CK Cook Islands +CL Chile +CM Cameroon +CN China +CO Colombia +CR Costa Rica +CU Cuba +CV Cape Verde +CW Curaรงao +CX Christmas Island +CY Cyprus +CZ Czech Republic +DE Germany +DJ Djibouti +DK Denmark +DM Dominica +DO Dominican Republic +DZ Algeria +EC Ecuador +EE Estonia +EG Egypt +EH Western Sahara +ER Eritrea +ES Spain +ET Ethiopia +FI Finland +FJ Fiji +FK Falkland Islands +FM Micronesia +FO Faroe Islands +FR France +GA Gabon +GB Britain (UK) +GD Grenada +GE Georgia +GF French Guiana +GG Guernsey +GH Ghana +GI Gibraltar +GL Greenland +GM Gambia +GN Guinea +GP Guadeloupe +GQ Equatorial Guinea +GR Greece +GS South Georgia & the South Sandwich Islands +GT Guatemala +GU Guam +GW Guinea-Bissau +GY Guyana +HK Hong Kong +HM Heard Island & McDonald Islands +HN Honduras +HR Croatia +HT Haiti +HU Hungary +ID Indonesia +IE Ireland +IL Israel +IM Isle of Man +IN India +IO British Indian Ocean Territory +IQ Iraq +IR Iran +IS Iceland +IT Italy +JE Jersey +JM Jamaica +JO Jordan +JP Japan +KE Kenya +KG Kyrgyzstan +KH Cambodia +KI Kiribati +KM Comoros +KN St Kitts & Nevis +KP Korea (North) +KR Korea (South) +KW Kuwait +KY Cayman Islands +KZ Kazakhstan +LA Laos +LB Lebanon +LC St Lucia +LI Liechtenstein +LK Sri Lanka +LR Liberia +LS Lesotho +LT Lithuania +LU Luxembourg +LV Latvia +LY Libya +MA Morocco +MC Monaco +MD Moldova +ME Montenegro +MF St Martin (French) +MG Madagascar +MH Marshall Islands +MK North Macedonia +ML Mali +MM Myanmar (Burma) +MN Mongolia +MO Macau +MP Northern Mariana Islands +MQ Martinique +MR Mauritania +MS Montserrat +MT Malta +MU Mauritius +MV Maldives +MW Malawi +MX Mexico +MY Malaysia +MZ Mozambique +NA Namibia +NC New Caledonia +NE Niger +NF Norfolk Island +NG Nigeria +NI Nicaragua +NL Netherlands +NO Norway +NP Nepal +NR Nauru +NU Niue +NZ New Zealand +OM Oman +PA Panama +PE Peru +PF French Polynesia +PG Papua New Guinea +PH Philippines +PK Pakistan +PL Poland +PM St Pierre & Miquelon +PN Pitcairn +PR Puerto Rico +PS Palestine +PT Portugal +PW Palau +PY Paraguay +QA Qatar +RE Rรฉunion +RO Romania +RS Serbia +RU Russia +RW Rwanda +SA Saudi Arabia +SB Solomon Islands +SC Seychelles +SD Sudan +SE Sweden +SG Singapore +SH St Helena +SI Slovenia +SJ Svalbard & Jan Mayen +SK Slovakia +SL Sierra Leone +SM San Marino +SN Senegal +SO Somalia +SR Suriname +SS South Sudan +ST Sao Tome & Principe +SV El Salvador +SX St Maarten (Dutch) +SY Syria +SZ Eswatini (Swaziland) +TC Turks & Caicos Is +TD Chad +TF French Southern & Antarctic Lands +TG Togo +TH Thailand +TJ Tajikistan +TK Tokelau +TL East Timor +TM Turkmenistan +TN Tunisia +TO Tonga +TR Turkey +TT Trinidad & Tobago +TV Tuvalu +TW Taiwan +TZ Tanzania +UA Ukraine +UG Uganda +UM US minor outlying islands +US United States +UY Uruguay +UZ Uzbekistan +VA Vatican City +VC St Vincent +VE Venezuela +VG Virgin Islands (UK) +VI Virgin Islands (US) +VN Vietnam +VU Vanuatu +WF Wallis & Futuna +WS Samoa (western) +YE Yemen +YT Mayotte +ZA South Africa +ZM Zambia +ZW Zimbabwe diff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/localtime b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/localtime new file mode 100644 index 000000000000..afeeb88d0628 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/localtime Binary files differdiff --git a/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab new file mode 100644 index 000000000000..53ee77e88e5e --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab @@ -0,0 +1,384 @@ +# tzdb timezone descriptions +# +# This file is in the public domain. +# +# From Paul Eggert (2018-06-27): +# This file contains a table where each row stands for a timezone where +# civil timestamps have agreed since 1970. Columns are separated by +# a single tab. Lines beginning with '#' are comments. All text uses +# UTF-8 encoding. The columns of the table are as follows: +# +# 1. The countries that overlap the timezone, as a comma-separated list +# of ISO 3166 2-character country codes. See the file 'iso3166.tab'. +# 2. Latitude and longitude of the timezone's principal location +# in ISO 6709 sign-degrees-minutes-seconds format, +# either ยฑDDMMยฑDDDMM or ยฑDDMMSSยฑDDDMMSS, +# first latitude (+ is north), then longitude (+ is east). +# 3. Timezone name used in value of TZ environment variable. +# Please see the theory.html file for how these names are chosen. +# If multiple timezones overlap a country, each has a row in the +# table, with each column 1 containing the country code. +# 4. Comments; present if and only if a country has multiple timezones. +# +# If a timezone covers multiple countries, the most-populous city is used, +# and that country is listed first in column 1; any other countries +# are listed alphabetically by country code. The table is sorted +# first by country code, then (if possible) by an order within the +# country that (1) makes some geographical sense, and (2) puts the +# most populous timezones first, where that does not contradict (1). +# +# This table is intended as an aid for users, to help them select timezones +# appropriate for their practical needs. It is not intended to take or +# endorse any position on legal or territorial claims. +# +#country- +#codes coordinates TZ comments +AD +4230+00131 Europe/Andorra +AE,OM +2518+05518 Asia/Dubai +AF +3431+06912 Asia/Kabul +AL +4120+01950 Europe/Tirane +AM +4011+04430 Asia/Yerevan +AQ -6617+11031 Antarctica/Casey Casey +AQ -6835+07758 Antarctica/Davis Davis +AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville +AQ -6736+06253 Antarctica/Mawson Mawson +AQ -6448-06406 Antarctica/Palmer Palmer +AQ -6734-06808 Antarctica/Rothera Rothera +AQ -690022+0393524 Antarctica/Syowa Syowa +AQ -720041+0023206 Antarctica/Troll Troll +AQ -7824+10654 Antarctica/Vostok Vostok +AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) +AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, FM, MN, SE, SF) +AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) +AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) +AR -2649-06513 America/Argentina/Tucuman Tucumรกn (TM) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) +AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) +AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) +AR -3319-06621 America/Argentina/San_Luis San Luis (SL) +AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) +AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) +AS,UM -1416-17042 Pacific/Pago_Pago Samoa, Midway +AT +4813+01620 Europe/Vienna +AU -3133+15905 Australia/Lord_Howe Lord Howe Island +AU -5430+15857 Antarctica/Macquarie Macquarie Island +AU -4253+14719 Australia/Hobart Tasmania (most areas) +AU -3956+14352 Australia/Currie Tasmania (King Island) +AU -3749+14458 Australia/Melbourne Victoria +AU -3352+15113 Australia/Sydney New South Wales (most areas) +AU -3157+14127 Australia/Broken_Hill New South Wales (Yancowinna) +AU -2728+15302 Australia/Brisbane Queensland (most areas) +AU -2016+14900 Australia/Lindeman Queensland (Whitsunday Islands) +AU -3455+13835 Australia/Adelaide South Australia +AU -1228+13050 Australia/Darwin Northern Territory +AU -3157+11551 Australia/Perth Western Australia (most areas) +AU -3143+12852 Australia/Eucla Western Australia (Eucla) +AZ +4023+04951 Asia/Baku +BB +1306-05937 America/Barbados +BD +2343+09025 Asia/Dhaka +BE +5050+00420 Europe/Brussels +BG +4241+02319 Europe/Sofia +BM +3217-06446 Atlantic/Bermuda +BN +0456+11455 Asia/Brunei +BO -1630-06809 America/La_Paz +BR -0351-03225 America/Noronha Atlantic islands +BR -0127-04829 America/Belem Parรก (east); Amapรก +BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) +BR -0803-03454 America/Recife Pernambuco +BR -0712-04812 America/Araguaina Tocantins +BR -0940-03543 America/Maceio Alagoas, Sergipe +BR -1259-03831 America/Bahia Bahia +BR -2332-04637 America/Sao_Paulo Brazil (southeast: GO, DF, MG, ES, RJ, SP, PR, SC, RS) +BR -2027-05437 America/Campo_Grande Mato Grosso do Sul +BR -1535-05605 America/Cuiaba Mato Grosso +BR -0226-05452 America/Santarem Parรก (west) +BR -0846-06354 America/Porto_Velho Rondรดnia +BR +0249-06040 America/Boa_Vista Roraima +BR -0308-06001 America/Manaus Amazonas (east) +BR -0640-06952 America/Eirunepe Amazonas (west) +BR -0958-06748 America/Rio_Branco Acre +BS +2505-07721 America/Nassau +BT +2728+08939 Asia/Thimphu +BY +5354+02734 Europe/Minsk +BZ +1730-08812 America/Belize +CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) +CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) +CA +4606-06447 America/Moncton Atlantic - New Brunswick +CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) +CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) +CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) +CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) +CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) +CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) +CA +744144-0944945 America/Resolute Central - NU (Resolute) +CA +624900-0920459 America/Rankin_Inlet Central - NU (central) +CA +5024-10439 America/Regina CST - SK (most areas) +CA +5017-10750 America/Swift_Current CST - SK (midwest) +CA +5333-11328 America/Edmonton Mountain - AB; BC (E); SK (W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +6227-11421 America/Yellowknife Mountain - NT (central) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +4906-11631 America/Creston MST - BC (Creston) +CA +5946-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) +CA +5848-12242 America/Fort_Nelson MST - BC (Ft Nelson) +CA +4916-12307 America/Vancouver Pacific - BC (most areas) +CA +6043-13503 America/Whitehorse Pacific - Yukon (east) +CA +6404-13925 America/Dawson Pacific - Yukon (west) +CC -1210+09655 Indian/Cocos +CH,DE,LI +4723+00832 Europe/Zurich Swiss time +CI,BF,GM,GN,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan +CK -2114-15946 Pacific/Rarotonga +CL -3327-07040 America/Santiago Chile (most areas) +CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -2709-10926 Pacific/Easter Easter Island +CN +3114+12128 Asia/Shanghai Beijing Time +CN +4348+08735 Asia/Urumqi Xinjiang Time +CO +0436-07405 America/Bogota +CR +0956-08405 America/Costa_Rica +CU +2308-08222 America/Havana +CV +1455-02331 Atlantic/Cape_Verde +CW,AW,BQ,SX +1211-06900 America/Curacao +CX -1025+10543 Indian/Christmas +CY +3510+03322 Asia/Nicosia Cyprus (most areas) +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ,SK +5005+01426 Europe/Prague +DE +5230+01322 Europe/Berlin Germany (most areas) +DK +5540+01235 Europe/Copenhagen +DO +1828-06954 America/Santo_Domingo +DZ +3647+00303 Africa/Algiers +EC -0210-07950 America/Guayaquil Ecuador (mainland) +EC -0054-08936 Pacific/Galapagos Galรกpagos Islands +EE +5925+02445 Europe/Tallinn +EG +3003+03115 Africa/Cairo +EH +2709-01312 Africa/El_Aaiun +ES +4024-00341 Europe/Madrid Spain (mainland) +ES +3553-00519 Africa/Ceuta Ceuta, Melilla +ES +2806-01524 Atlantic/Canary Canary Islands +FI,AX +6010+02458 Europe/Helsinki +FJ -1808+17825 Pacific/Fiji +FK -5142-05751 Atlantic/Stanley +FM +0725+15147 Pacific/Chuuk Chuuk/Truk, Yap +FM +0658+15813 Pacific/Pohnpei Pohnpei/Ponape +FM +0519+16259 Pacific/Kosrae Kosrae +FO +6201-00646 Atlantic/Faroe +FR +4852+00220 Europe/Paris +GB,GG,IM,JE +513030-0000731 Europe/London +GE +4143+04449 Asia/Tbilisi +GF +0456-05220 America/Cayenne +GH +0533-00013 Africa/Accra +GI +3608-00521 Europe/Gibraltar +GL +6411-05144 America/Nuuk Greenland (most areas) +GL +7646-01840 America/Danmarkshavn National Park (east coast) +GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit +GL +7634-06847 America/Thule Thule/Pituffik +GR +3758+02343 Europe/Athens +GS -5416-03632 Atlantic/South_Georgia +GT +1438-09031 America/Guatemala +GU,MP +1328+14445 Pacific/Guam +GW +1151-01535 Africa/Bissau +GY +0648-05810 America/Guyana +HK +2217+11409 Asia/Hong_Kong +HN +1406-08713 America/Tegucigalpa +HT +1832-07220 America/Port-au-Prince +HU +4730+01905 Europe/Budapest +ID -0610+10648 Asia/Jakarta Java, Sumatra +ID -0002+10920 Asia/Pontianak Borneo (west, central) +ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +IE +5320-00615 Europe/Dublin +IL +314650+0351326 Asia/Jerusalem +IN +2232+08822 Asia/Kolkata +IO -0720+07225 Indian/Chagos +IQ +3321+04425 Asia/Baghdad +IR +3540+05126 Asia/Tehran +IS +6409-02151 Atlantic/Reykjavik +IT,SM,VA +4154+01229 Europe/Rome +JM +175805-0764736 America/Jamaica +JO +3157+03556 Asia/Amman +JP +353916+1394441 Asia/Tokyo +KE,DJ,ER,ET,KM,MG,SO,TZ,UG,YT -0117+03649 Africa/Nairobi +KG +4254+07436 Asia/Bishkek +KI +0125+17300 Pacific/Tarawa Gilbert Islands +KI -0308-17105 Pacific/Enderbury Phoenix Islands +KI +0152-15720 Pacific/Kiritimati Line Islands +KP +3901+12545 Asia/Pyongyang +KR +3733+12658 Asia/Seoul +KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) +KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda +KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay +KZ +5017+05710 Asia/Aqtobe Aqtรถbe/Aktobe +KZ +4431+05016 Asia/Aqtau Mangghystaลซ/Mankistau +KZ +4707+05156 Asia/Atyrau Atyraลซ/Atirau/Gur'yev +KZ +5113+05121 Asia/Oral West Kazakhstan +LB +3353+03530 Asia/Beirut +LK +0656+07951 Asia/Colombo +LR +0618-01047 Africa/Monrovia +LT +5441+02519 Europe/Vilnius +LU +4936+00609 Europe/Luxembourg +LV +5657+02406 Europe/Riga +LY +3254+01311 Africa/Tripoli +MA +3339-00735 Africa/Casablanca +MC +4342+00723 Europe/Monaco +MD +4700+02850 Europe/Chisinau +MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) +MH +0905+16720 Pacific/Kwajalein Kwajalein +MM +1647+09610 Asia/Yangon +MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) +MN +4801+09139 Asia/Hovd Bayan-รlgii, Govi-Altai, Hovd, Uvs, Zavkhan +MN +4804+11430 Asia/Choibalsan Dornod, Sรผkhbaatar +MO +221150+1133230 Asia/Macau +MQ +1436-06105 America/Martinique +MT +3554+01431 Europe/Malta +MU -2010+05730 Indian/Mauritius +MV +0410+07330 Indian/Maldives +MX +1924-09909 America/Mexico_City Central Time +MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo +MX +2058-08937 America/Merida Central Time - Campeche, Yucatรกn +MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leรณn, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leรณn, Tamaulipas (US border) +MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa +MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) +MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) +MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora +MX +3232-11701 America/Tijuana Pacific Time US - Baja California +MX +2048-10515 America/Bahia_Banderas Central Time - Bahรญa de Banderas +MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) +MY +0133+11020 Asia/Kuching Sabah, Sarawak +MZ,BI,BW,CD,MW,RW,ZM,ZW -2558+03235 Africa/Maputo Central Africa Time +NA -2234+01706 Africa/Windhoek +NC -2216+16627 Pacific/Noumea +NF -2903+16758 Pacific/Norfolk +NG,AO,BJ,CD,CF,CG,CM,GA,GQ,NE +0627+00324 Africa/Lagos West Africa Time +NI +1209-08617 America/Managua +NL +5222+00454 Europe/Amsterdam +NO,SJ +5955+01045 Europe/Oslo +NP +2743+08519 Asia/Kathmandu +NR -0031+16655 Pacific/Nauru +NU -1901-16955 Pacific/Niue +NZ,AQ -3652+17446 Pacific/Auckland New Zealand time +NZ -4357-17633 Pacific/Chatham Chatham Islands +PA,KY +0858-07932 America/Panama +PE -1203-07703 America/Lima +PF -1732-14934 Pacific/Tahiti Society Islands +PF -0900-13930 Pacific/Marquesas Marquesas Islands +PF -2308-13457 Pacific/Gambier Gambier Islands +PG -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas) +PG -0613+15534 Pacific/Bougainville Bougainville +PH +1435+12100 Asia/Manila +PK +2452+06703 Asia/Karachi +PL +5215+02100 Europe/Warsaw +PM +4703-05620 America/Miquelon +PN -2504-13005 Pacific/Pitcairn +PR +182806-0660622 America/Puerto_Rico +PS +3130+03428 Asia/Gaza Gaza Strip +PS +313200+0350542 Asia/Hebron West Bank +PT +3843-00908 Europe/Lisbon Portugal (mainland) +PT +3238-01654 Atlantic/Madeira Madeira Islands +PT +3744-02540 Atlantic/Azores Azores +PW +0720+13429 Pacific/Palau +PY -2516-05740 America/Asuncion +QA,BH +2517+05132 Asia/Qatar +RE,TF -2052+05528 Indian/Reunion Rรฉunion, Crozet, Scattered Islands +RO +4426+02606 Europe/Bucharest +RS,BA,HR,ME,MK,SI +4450+02030 Europe/Belgrade +RU +5443+02030 Europe/Kaliningrad MSK-01 - Kaliningrad +RU +554521+0373704 Europe/Moscow MSK+00 - Moscow area +# Mention RU and UA alphabetically. See "territorial claims" above. +RU,UA +4457+03406 Europe/Simferopol Crimea +RU +5836+04939 Europe/Kirov MSK+00 - Kirov +RU +4621+04803 Europe/Astrakhan MSK+01 - Astrakhan +RU +4844+04425 Europe/Volgograd MSK+01 - Volgograd +RU +5134+04602 Europe/Saratov MSK+01 - Saratov +RU +5420+04824 Europe/Ulyanovsk MSK+01 - Ulyanovsk +RU +5312+05009 Europe/Samara MSK+01 - Samara, Udmurtia +RU +5651+06036 Asia/Yekaterinburg MSK+02 - Urals +RU +5500+07324 Asia/Omsk MSK+03 - Omsk +RU +5502+08255 Asia/Novosibirsk MSK+04 - Novosibirsk +RU +5322+08345 Asia/Barnaul MSK+04 - Altai +RU +5630+08458 Asia/Tomsk MSK+04 - Tomsk +RU +5345+08707 Asia/Novokuznetsk MSK+04 - Kemerovo +RU +5601+09250 Asia/Krasnoyarsk MSK+04 - Krasnoyarsk area +RU +5216+10420 Asia/Irkutsk MSK+05 - Irkutsk, Buryatia +RU +5203+11328 Asia/Chita MSK+06 - Zabaykalsky +RU +6200+12940 Asia/Yakutsk MSK+06 - Lena River +RU +623923+1353314 Asia/Khandyga MSK+06 - Tomponsky, Ust-Maysky +RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River +RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky +RU +5934+15048 Asia/Magadan MSK+08 - Magadan +RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); North Kuril Is +RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka +RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea +SA,KW,YE +2438+04643 Asia/Riyadh +SB -0932+16012 Pacific/Guadalcanal +SC -0440+05528 Indian/Mahe +SD +1536+03232 Africa/Khartoum +SE +5920+01803 Europe/Stockholm +SG +0117+10351 Asia/Singapore +SR +0550-05510 America/Paramaribo +SS +0451+03137 Africa/Juba +ST +0020+00644 Africa/Sao_Tome +SV +1342-08912 America/El_Salvador +SY +3330+03618 Asia/Damascus +TC +2128-07108 America/Grand_Turk +TD +1207+01503 Africa/Ndjamena +TF -492110+0701303 Indian/Kerguelen Kerguelen, St Paul Island, Amsterdam Island +TH,KH,LA,VN +1345+10031 Asia/Bangkok Indochina (most areas) +TJ +3835+06848 Asia/Dushanbe +TK -0922-17114 Pacific/Fakaofo +TL -0833+12535 Asia/Dili +TM +3757+05823 Asia/Ashgabat +TN +3648+01011 Africa/Tunis +TO -2110-17510 Pacific/Tongatapu +TR +4101+02858 Europe/Istanbul +TT,AG,AI,BL,DM,GD,GP,KN,LC,MF,MS,VC,VG,VI +1039-06131 America/Port_of_Spain +TV -0831+17913 Pacific/Funafuti +TW +2503+12130 Asia/Taipei +UA +5026+03031 Europe/Kiev Ukraine (most areas) +UA +4837+02218 Europe/Uzhgorod Transcarpathia +UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk +UM +1917+16637 Pacific/Wake Wake Island +US +404251-0740023 America/New_York Eastern (most areas) +US +421953-0830245 America/Detroit Eastern - MI (most areas) +US +381515-0854534 America/Kentucky/Louisville Eastern - KY (Louisville area) +US +364947-0845057 America/Kentucky/Monticello Eastern - KY (Wayne) +US +394606-0860929 America/Indiana/Indianapolis Eastern - IN (most areas) +US +384038-0873143 America/Indiana/Vincennes Eastern - IN (Da, Du, K, Mn) +US +410305-0863611 America/Indiana/Winamac Eastern - IN (Pulaski) +US +382232-0862041 America/Indiana/Marengo Eastern - IN (Crawford) +US +382931-0871643 America/Indiana/Petersburg Eastern - IN (Pike) +US +384452-0850402 America/Indiana/Vevay Eastern - IN (Switzerland) +US +415100-0873900 America/Chicago Central (most areas) +US +375711-0864541 America/Indiana/Tell_City Central - IN (Perry) +US +411745-0863730 America/Indiana/Knox Central - IN (Starke) +US +450628-0873651 America/Menominee Central - MI (Wisconsin border) +US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) +US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) +US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) +US +394421-1045903 America/Denver Mountain (most areas) +US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +332654-1120424 America/Phoenix MST - Arizona (except Navajo) +US +340308-1181434 America/Los_Angeles Pacific +US +611305-1495401 America/Anchorage Alaska (most areas) +US +581807-1342511 America/Juneau Alaska - Juneau area +US +571035-1351807 America/Sitka Alaska - Sitka area +US +550737-1313435 America/Metlakatla Alaska - Annette Island +US +593249-1394338 America/Yakutat Alaska - Yakutat +US +643004-1652423 America/Nome Alaska (west) +US +515248-1763929 America/Adak Aleutian Islands +US,UM +211825-1575130 Pacific/Honolulu Hawaii +UY -345433-0561245 America/Montevideo +UZ +3940+06648 Asia/Samarkand Uzbekistan (west) +UZ +4120+06918 Asia/Tashkent Uzbekistan (east) +VE +1030-06656 America/Caracas +VN +1045+10640 Asia/Ho_Chi_Minh Vietnam (south) +VU -1740+16825 Pacific/Efate +WF -1318-17610 Pacific/Wallis +WS -1350-17144 Pacific/Apia +ZA,LS,SZ -2615+02800 Africa/Johannesburg diff --git a/third_party/abseil_cpp/absl/time/internal/get_current_time_chrono.inc b/third_party/abseil_cpp/absl/time/internal/get_current_time_chrono.inc new file mode 100644 index 000000000000..5eeb6406aaf3 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/get_current_time_chrono.inc @@ -0,0 +1,31 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <chrono> +#include <cstdint> + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { + +static int64_t GetCurrentTimeNanosFromSystem() { + return std::chrono::duration_cast<std::chrono::nanoseconds>( + std::chrono::system_clock::now() - + std::chrono::system_clock::from_time_t(0)) + .count(); +} + +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/get_current_time_posix.inc b/third_party/abseil_cpp/absl/time/internal/get_current_time_posix.inc new file mode 100644 index 000000000000..42072000ae3c --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/get_current_time_posix.inc @@ -0,0 +1,24 @@ +#include "absl/time/clock.h" + +#include <sys/time.h> +#include <ctime> +#include <cstdint> + +#include "absl/base/internal/raw_logging.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { + +static int64_t GetCurrentTimeNanosFromSystem() { + const int64_t kNanosPerSecond = 1000 * 1000 * 1000; + struct timespec ts; + ABSL_RAW_CHECK(clock_gettime(CLOCK_REALTIME, &ts) == 0, + "Failed to read real-time clock."); + return (int64_t{ts.tv_sec} * kNanosPerSecond + + int64_t{ts.tv_nsec}); +} + +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/test_util.cc b/third_party/abseil_cpp/absl/time/internal/test_util.cc new file mode 100644 index 000000000000..9a485a0750e4 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/test_util.cc @@ -0,0 +1,131 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/internal/test_util.h" + +#include <algorithm> +#include <cstddef> +#include <cstring> + +#include "absl/base/config.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/time/internal/cctz/include/cctz/zone_info_source.h" + +namespace cctz = absl::time_internal::cctz; + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { + +TimeZone LoadTimeZone(const std::string& name) { + TimeZone tz; + ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str()); + return tz; +} + +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { +namespace cctz_extension { +namespace { + +// Embed the zoneinfo data for time zones used during tests and benchmarks. +// The data was generated using "xxd -i zoneinfo-file". There is no need +// to update the data as long as the tests do not depend on recent changes +// (and the past rules remain the same). +#include "absl/time/internal/zoneinfo.inc" + +const struct ZoneInfo { + const char* name; + const char* data; + std::size_t length; +} kZoneInfo[] = { + // The three real time zones used by :time_test and :time_benchmark. + {"America/Los_Angeles", // + reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, + {"America/New_York", // + reinterpret_cast<char*>(America_New_York), America_New_York_len}, + {"Australia/Sydney", // + reinterpret_cast<char*>(Australia_Sydney), Australia_Sydney_len}, + + // Other zones named in tests but which should fail to load. + {"Invalid/TimeZone", nullptr, 0}, + {"", nullptr, 0}, + + // Also allow for loading the local time zone under TZ=US/Pacific. + {"US/Pacific", // + reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, + + // Allows use of the local time zone from a system-specific location. +#ifdef _MSC_VER + {"localtime", // + reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, +#else + {"/etc/localtime", // + reinterpret_cast<char*>(America_Los_Angeles), America_Los_Angeles_len}, +#endif +}; + +class TestZoneInfoSource : public cctz::ZoneInfoSource { + public: + TestZoneInfoSource(const char* data, std::size_t size) + : data_(data), end_(data + size) {} + + std::size_t Read(void* ptr, std::size_t size) override { + const std::size_t len = std::min<std::size_t>(size, end_ - data_); + memcpy(ptr, data_, len); + data_ += len; + return len; + } + + int Skip(std::size_t offset) override { + data_ += std::min<std::size_t>(offset, end_ - data_); + return 0; + } + + private: + const char* data_; + const char* const end_; +}; + +std::unique_ptr<cctz::ZoneInfoSource> TestFactory( + const std::string& name, + const std::function<std::unique_ptr<cctz::ZoneInfoSource>( + const std::string& name)>& /*fallback_factory*/) { + for (const ZoneInfo& zoneinfo : kZoneInfo) { + if (name == zoneinfo.name) { + if (zoneinfo.data == nullptr) return nullptr; + return std::unique_ptr<cctz::ZoneInfoSource>( + new TestZoneInfoSource(zoneinfo.data, zoneinfo.length)); + } + } + ABSL_RAW_LOG(FATAL, "Unexpected time zone \"%s\" in test", name.c_str()); + return nullptr; +} + +} // namespace + +#if !defined(__MINGW32__) +// MinGW does not support the weak symbol extension mechanism. +ZoneInfoSourceFactory zone_info_source_factory = TestFactory; +#endif + +} // namespace cctz_extension +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/internal/test_util.h b/third_party/abseil_cpp/absl/time/internal/test_util.h new file mode 100644 index 000000000000..5c4bf1f680ee --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/test_util.h @@ -0,0 +1,33 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_TIME_INTERNAL_TEST_UTIL_H_ +#define ABSL_TIME_INTERNAL_TEST_UTIL_H_ + +#include <string> + +#include "absl/time/time.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace time_internal { + +// Loads the named timezone, but dies on any failure. +absl::TimeZone LoadTimeZone(const std::string& name); + +} // namespace time_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_INTERNAL_TEST_UTIL_H_ diff --git a/third_party/abseil_cpp/absl/time/internal/zoneinfo.inc b/third_party/abseil_cpp/absl/time/internal/zoneinfo.inc new file mode 100644 index 000000000000..bfed82990dd5 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/internal/zoneinfo.inc @@ -0,0 +1,729 @@ +unsigned char America_Los_Angeles[] = { + 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, + 0x9e, 0xa6, 0x48, 0xa0, 0x9f, 0xbb, 0x15, 0x90, 0xa0, 0x86, 0x2a, 0xa0, + 0xa1, 0x9a, 0xf7, 0x90, 0xcb, 0x89, 0x1a, 0xa0, 0xd2, 0x23, 0xf4, 0x70, + 0xd2, 0x61, 0x26, 0x10, 0xd6, 0xfe, 0x74, 0x5c, 0xd8, 0x80, 0xad, 0x90, + 0xda, 0xfe, 0xc3, 0x90, 0xdb, 0xc0, 0x90, 0x10, 0xdc, 0xde, 0xa5, 0x90, + 0xdd, 0xa9, 0xac, 0x90, 0xde, 0xbe, 0x87, 0x90, 0xdf, 0x89, 0x8e, 0x90, + 0xe0, 0x9e, 0x69, 0x90, 0xe1, 0x69, 0x70, 0x90, 0xe2, 0x7e, 0x4b, 0x90, + 0xe3, 0x49, 0x52, 0x90, 0xe4, 0x5e, 0x2d, 0x90, 0xe5, 0x29, 0x34, 0x90, + 0xe6, 0x47, 0x4a, 0x10, 0xe7, 0x12, 0x51, 0x10, 0xe8, 0x27, 0x2c, 0x10, + 0xe8, 0xf2, 0x33, 0x10, 0xea, 0x07, 0x0e, 0x10, 0xea, 0xd2, 0x15, 0x10, + 0xeb, 0xe6, 0xf0, 0x10, 0xec, 0xb1, 0xf7, 0x10, 0xed, 0xc6, 0xd2, 0x10, + 0xee, 0x91, 0xd9, 0x10, 0xef, 0xaf, 0xee, 0x90, 0xf0, 0x71, 0xbb, 0x10, + 0xf1, 0x8f, 0xd0, 0x90, 0xf2, 0x7f, 0xc1, 0x90, 0xf3, 0x6f, 0xb2, 0x90, + 0xf4, 0x5f, 0xa3, 0x90, 0xf5, 0x4f, 0x94, 0x90, 0xf6, 0x3f, 0x85, 0x90, + 0xf7, 0x2f, 0x76, 0x90, 0xf8, 0x28, 0xa2, 0x10, 0xf9, 0x0f, 0x58, 0x90, + 0xfa, 0x08, 0x84, 0x10, 0xfa, 0xf8, 0x83, 0x20, 0xfb, 0xe8, 0x66, 0x10, + 0xfc, 0xd8, 0x65, 0x20, 0xfd, 0xc8, 0x48, 0x10, 0xfe, 0xb8, 0x47, 0x20, + 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x98, 0x29, 0x20, 0x01, 0x88, 0x0c, 0x10, + 0x02, 0x78, 0x0b, 0x20, 0x03, 0x71, 0x28, 0x90, 0x04, 0x61, 0x27, 0xa0, + 0x05, 0x51, 0x0a, 0x90, 0x06, 0x41, 0x09, 0xa0, 0x07, 0x30, 0xec, 0x90, + 0x07, 0x8d, 0x43, 0xa0, 0x09, 0x10, 0xce, 0x90, 0x09, 0xad, 0xbf, 0x20, + 0x0a, 0xf0, 0xb0, 0x90, 0x0b, 0xe0, 0xaf, 0xa0, 0x0c, 0xd9, 0xcd, 0x10, + 0x0d, 0xc0, 0x91, 0xa0, 0x0e, 0xb9, 0xaf, 0x10, 0x0f, 0xa9, 0xae, 0x20, + 0x10, 0x99, 0x91, 0x10, 0x11, 0x89, 0x90, 0x20, 0x12, 0x79, 0x73, 0x10, + 0x13, 0x69, 0x72, 0x20, 0x14, 0x59, 0x55, 0x10, 0x15, 0x49, 0x54, 0x20, + 0x16, 0x39, 0x37, 0x10, 0x17, 0x29, 0x36, 0x20, 0x18, 0x22, 0x53, 0x90, + 0x19, 0x09, 0x18, 0x20, 0x1a, 0x02, 0x35, 0x90, 0x1a, 0xf2, 0x34, 0xa0, + 0x1b, 0xe2, 0x17, 0x90, 0x1c, 0xd2, 0x16, 0xa0, 0x1d, 0xc1, 0xf9, 0x90, + 0x1e, 0xb1, 0xf8, 0xa0, 0x1f, 0xa1, 0xdb, 0x90, 0x20, 0x76, 0x2b, 0x20, + 0x21, 0x81, 0xbd, 0x90, 0x22, 0x56, 0x0d, 0x20, 0x23, 0x6a, 0xda, 0x10, + 0x24, 0x35, 0xef, 0x20, 0x25, 0x4a, 0xbc, 0x10, 0x26, 0x15, 0xd1, 0x20, + 0x27, 0x2a, 0x9e, 0x10, 0x27, 0xfe, 0xed, 0xa0, 0x29, 0x0a, 0x80, 0x10, + 0x29, 0xde, 0xcf, 0xa0, 0x2a, 0xea, 0x62, 0x10, 0x2b, 0xbe, 0xb1, 0xa0, + 0x2c, 0xd3, 0x7e, 0x90, 0x2d, 0x9e, 0x93, 0xa0, 0x2e, 0xb3, 0x60, 0x90, + 0x2f, 0x7e, 0x75, 0xa0, 0x30, 0x93, 0x42, 0x90, 0x31, 0x67, 0x92, 0x20, + 0x32, 0x73, 0x24, 0x90, 0x33, 0x47, 0x74, 0x20, 0x34, 0x53, 0x06, 0x90, + 0x35, 0x27, 0x56, 0x20, 0x36, 0x32, 0xe8, 0x90, 0x37, 0x07, 0x38, 0x20, + 0x38, 0x1c, 0x05, 0x10, 0x38, 0xe7, 0x1a, 0x20, 0x39, 0xfb, 0xe7, 0x10, + 0x3a, 0xc6, 0xfc, 0x20, 0x3b, 0xdb, 0xc9, 0x10, 0x3c, 0xb0, 0x18, 0xa0, + 0x3d, 0xbb, 0xab, 0x10, 0x3e, 0x8f, 0xfa, 0xa0, 0x3f, 0x9b, 0x8d, 0x10, + 0x40, 0x6f, 0xdc, 0xa0, 0x41, 0x84, 0xa9, 0x90, 0x42, 0x4f, 0xbe, 0xa0, + 0x43, 0x64, 0x8b, 0x90, 0x44, 0x2f, 0xa0, 0xa0, 0x45, 0x44, 0x6d, 0x90, + 0x45, 0xf3, 0xd3, 0x20, 0x47, 0x2d, 0x8a, 0x10, 0x47, 0xd3, 0xb5, 0x20, + 0x49, 0x0d, 0x6c, 0x10, 0x49, 0xb3, 0x97, 0x20, 0x4a, 0xed, 0x4e, 0x10, + 0x4b, 0x9c, 0xb3, 0xa0, 0x4c, 0xd6, 0x6a, 0x90, 0x4d, 0x7c, 0x95, 0xa0, + 0x4e, 0xb6, 0x4c, 0x90, 0x4f, 0x5c, 0x77, 0xa0, 0x50, 0x96, 0x2e, 0x90, + 0x51, 0x3c, 0x59, 0xa0, 0x52, 0x76, 0x10, 0x90, 0x53, 0x1c, 0x3b, 0xa0, + 0x54, 0x55, 0xf2, 0x90, 0x54, 0xfc, 0x1d, 0xa0, 0x56, 0x35, 0xd4, 0x90, + 0x56, 0xe5, 0x3a, 0x20, 0x58, 0x1e, 0xf1, 0x10, 0x58, 0xc5, 0x1c, 0x20, + 0x59, 0xfe, 0xd3, 0x10, 0x5a, 0xa4, 0xfe, 0x20, 0x5b, 0xde, 0xb5, 0x10, + 0x5c, 0x84, 0xe0, 0x20, 0x5d, 0xbe, 0x97, 0x10, 0x5e, 0x64, 0xc2, 0x20, + 0x5f, 0x9e, 0x79, 0x10, 0x60, 0x4d, 0xde, 0xa0, 0x61, 0x87, 0x95, 0x90, + 0x62, 0x2d, 0xc0, 0xa0, 0x63, 0x67, 0x77, 0x90, 0x64, 0x0d, 0xa2, 0xa0, + 0x65, 0x47, 0x59, 0x90, 0x65, 0xed, 0x84, 0xa0, 0x67, 0x27, 0x3b, 0x90, + 0x67, 0xcd, 0x66, 0xa0, 0x69, 0x07, 0x1d, 0x90, 0x69, 0xad, 0x48, 0xa0, + 0x6a, 0xe6, 0xff, 0x90, 0x6b, 0x96, 0x65, 0x20, 0x6c, 0xd0, 0x1c, 0x10, + 0x6d, 0x76, 0x47, 0x20, 0x6e, 0xaf, 0xfe, 0x10, 0x6f, 0x56, 0x29, 0x20, + 0x70, 0x8f, 0xe0, 0x10, 0x71, 0x36, 0x0b, 0x20, 0x72, 0x6f, 0xc2, 0x10, + 0x73, 0x15, 0xed, 0x20, 0x74, 0x4f, 0xa4, 0x10, 0x74, 0xff, 0x09, 0xa0, + 0x76, 0x38, 0xc0, 0x90, 0x76, 0xde, 0xeb, 0xa0, 0x78, 0x18, 0xa2, 0x90, + 0x78, 0xbe, 0xcd, 0xa0, 0x79, 0xf8, 0x84, 0x90, 0x7a, 0x9e, 0xaf, 0xa0, + 0x7b, 0xd8, 0x66, 0x90, 0x7c, 0x7e, 0x91, 0xa0, 0x7d, 0xb8, 0x48, 0x90, + 0x7e, 0x5e, 0x73, 0xa0, 0x7f, 0x98, 0x2a, 0x90, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, + 0x01, 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, + 0x01, 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, + 0x50, 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, + 0x50, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbb, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x04, + 0x1a, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x48, 0xa0, 0xff, 0xff, + 0xff, 0xff, 0x9f, 0xbb, 0x15, 0x90, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, + 0x2a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xf7, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xcb, 0x89, 0x1a, 0xa0, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x23, + 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x61, 0x26, 0x10, 0xff, 0xff, + 0xff, 0xff, 0xd6, 0xfe, 0x74, 0x5c, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x80, + 0xad, 0x90, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xc3, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xdb, 0xc0, 0x90, 0x10, 0xff, 0xff, 0xff, 0xff, 0xdc, 0xde, + 0xa5, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0xac, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xde, 0xbe, 0x87, 0x90, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x89, + 0x8e, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x69, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xe1, 0x69, 0x70, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe2, 0x7e, + 0x4b, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x52, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xe4, 0x5e, 0x2d, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe5, 0x29, + 0x34, 0x90, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x4a, 0x10, 0xff, 0xff, + 0xff, 0xff, 0xe7, 0x12, 0x51, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0x27, + 0x2c, 0x10, 0xff, 0xff, 0xff, 0xff, 0xe8, 0xf2, 0x33, 0x10, 0xff, 0xff, + 0xff, 0xff, 0xea, 0x07, 0x0e, 0x10, 0xff, 0xff, 0xff, 0xff, 0xea, 0xd2, + 0x15, 0x10, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xf0, 0x10, 0xff, 0xff, + 0xff, 0xff, 0xec, 0xb1, 0xf7, 0x10, 0xff, 0xff, 0xff, 0xff, 0xed, 0xc6, + 0xd2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xee, 0x91, 0xd9, 0x10, 0xff, 0xff, + 0xff, 0xff, 0xef, 0xaf, 0xee, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x71, + 0xbb, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xd0, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xf2, 0x7f, 0xc1, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x6f, + 0xb2, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0xa3, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xf5, 0x4f, 0x94, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf6, 0x3f, + 0x85, 0x90, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x76, 0x90, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0x28, 0xa2, 0x10, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x0f, + 0x58, 0x90, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x84, 0x10, 0xff, 0xff, + 0xff, 0xff, 0xfa, 0xf8, 0x83, 0x20, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xe8, + 0x66, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x65, 0x20, 0xff, 0xff, + 0xff, 0xff, 0xfd, 0xc8, 0x48, 0x10, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb8, + 0x47, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa8, 0x2a, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x98, 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x88, + 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x78, 0x0b, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x71, 0x28, 0x90, 0x00, 0x00, 0x00, 0x00, 0x04, 0x61, + 0x27, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x05, 0x51, 0x0a, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x41, 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x30, + 0xec, 0x90, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x43, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x09, 0x10, 0xce, 0x90, 0x00, 0x00, 0x00, 0x00, 0x09, 0xad, + 0xbf, 0x20, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0xb0, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x0b, 0xe0, 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd9, + 0xcd, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x91, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb9, 0xaf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xa9, + 0xae, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x91, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x89, 0x90, 0x20, 0x00, 0x00, 0x00, 0x00, 0x12, 0x79, + 0x73, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x72, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x14, 0x59, 0x55, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15, 0x49, + 0x54, 0x20, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x37, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x17, 0x29, 0x36, 0x20, 0x00, 0x00, 0x00, 0x00, 0x18, 0x22, + 0x53, 0x90, 0x00, 0x00, 0x00, 0x00, 0x19, 0x09, 0x18, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x1a, 0x02, 0x35, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xf2, + 0x34, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe2, 0x17, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x1c, 0xd2, 0x16, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, + 0xf9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xf8, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0xa1, 0xdb, 0x90, 0x00, 0x00, 0x00, 0x00, 0x20, 0x76, + 0x2b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0xbd, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x22, 0x56, 0x0d, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x6a, + 0xda, 0x10, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xef, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x25, 0x4a, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x26, 0x15, + 0xd1, 0x20, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x9e, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x27, 0xfe, 0xed, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x29, 0x0a, + 0x80, 0x10, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xcf, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x2a, 0xea, 0x62, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2b, 0xbe, + 0xb1, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x7e, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x2d, 0x9e, 0x93, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb3, + 0x60, 0x90, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x75, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x93, 0x42, 0x90, 0x00, 0x00, 0x00, 0x00, 0x31, 0x67, + 0x92, 0x20, 0x00, 0x00, 0x00, 0x00, 0x32, 0x73, 0x24, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x33, 0x47, 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x34, 0x53, + 0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x56, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x36, 0x32, 0xe8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x37, 0x07, + 0x38, 0x20, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1c, 0x05, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x38, 0xe7, 0x1a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x39, 0xfb, + 0xe7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xfc, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x3b, 0xdb, 0xc9, 0x10, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xb0, + 0x18, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0xab, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x3e, 0x8f, 0xfa, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9b, + 0x8d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xdc, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x41, 0x84, 0xa9, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x4f, + 0xbe, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x8b, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x44, 0x2f, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x45, 0x44, + 0x6d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xd3, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x47, 0x2d, 0x8a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x47, 0xd3, + 0xb5, 0x20, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x6c, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x49, 0xb3, 0x97, 0x20, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xed, + 0x4e, 0x10, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0xb3, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x4c, 0xd6, 0x6a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x7c, + 0x95, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x4c, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x4f, 0x5c, 0x77, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x50, 0x96, + 0x2e, 0x90, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x59, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x52, 0x76, 0x10, 0x90, 0x00, 0x00, 0x00, 0x00, 0x53, 0x1c, + 0x3b, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xf2, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x54, 0xfc, 0x1d, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x56, 0x35, + 0xd4, 0x90, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x3a, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x58, 0x1e, 0xf1, 0x10, 0x00, 0x00, 0x00, 0x00, 0x58, 0xc5, + 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xd3, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x5a, 0xa4, 0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xde, + 0xb5, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xe0, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x5d, 0xbe, 0x97, 0x10, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x64, + 0xc2, 0x20, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x79, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x4d, 0xde, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x61, 0x87, + 0x95, 0x90, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0xc0, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x63, 0x67, 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0d, + 0xa2, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x59, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x65, 0xed, 0x84, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x67, 0x27, + 0x3b, 0x90, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x66, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x69, 0x07, 0x1d, 0x90, 0x00, 0x00, 0x00, 0x00, 0x69, 0xad, + 0x48, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xff, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x6b, 0x96, 0x65, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xd0, + 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x47, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x6e, 0xaf, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x56, + 0x29, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xe0, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x71, 0x36, 0x0b, 0x20, 0x00, 0x00, 0x00, 0x00, 0x72, 0x6f, + 0xc2, 0x10, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xed, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x74, 0x4f, 0xa4, 0x10, 0x00, 0x00, 0x00, 0x00, 0x74, 0xff, + 0x09, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0xc0, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x76, 0xde, 0xeb, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18, + 0xa2, 0x90, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xcd, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x79, 0xf8, 0x84, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x9e, + 0xaf, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x66, 0x90, 0x00, 0x00, + 0x00, 0x00, 0x7c, 0x7e, 0x91, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x7d, 0xb8, + 0x48, 0x90, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x73, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0x98, 0x2a, 0x90, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0xff, 0xff, 0x91, 0x26, 0x00, 0x00, 0xff, 0xff, 0x9d, 0x90, 0x01, + 0x04, 0xff, 0xff, 0x8f, 0x80, 0x00, 0x08, 0xff, 0xff, 0x9d, 0x90, 0x01, + 0x0c, 0xff, 0xff, 0x9d, 0x90, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x50, + 0x44, 0x54, 0x00, 0x50, 0x53, 0x54, 0x00, 0x50, 0x57, 0x54, 0x00, 0x50, + 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0a, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x2c, 0x4d, 0x33, + 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, 0x2e, 0x31, 0x2e, 0x30, + 0x0a +}; +unsigned int America_Los_Angeles_len = 2845; +unsigned char America_New_York[] = { + 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00, + 0x9e, 0xa6, 0x1e, 0x70, 0x9f, 0xba, 0xeb, 0x60, 0xa0, 0x86, 0x00, 0x70, + 0xa1, 0x9a, 0xcd, 0x60, 0xa2, 0x65, 0xe2, 0x70, 0xa3, 0x83, 0xe9, 0xe0, + 0xa4, 0x6a, 0xae, 0x70, 0xa5, 0x35, 0xa7, 0x60, 0xa6, 0x53, 0xca, 0xf0, + 0xa7, 0x15, 0x89, 0x60, 0xa8, 0x33, 0xac, 0xf0, 0xa8, 0xfe, 0xa5, 0xe0, + 0xaa, 0x13, 0x8e, 0xf0, 0xaa, 0xde, 0x87, 0xe0, 0xab, 0xf3, 0x70, 0xf0, + 0xac, 0xbe, 0x69, 0xe0, 0xad, 0xd3, 0x52, 0xf0, 0xae, 0x9e, 0x4b, 0xe0, + 0xaf, 0xb3, 0x34, 0xf0, 0xb0, 0x7e, 0x2d, 0xe0, 0xb1, 0x9c, 0x51, 0x70, + 0xb2, 0x67, 0x4a, 0x60, 0xb3, 0x7c, 0x33, 0x70, 0xb4, 0x47, 0x2c, 0x60, + 0xb5, 0x5c, 0x15, 0x70, 0xb6, 0x27, 0x0e, 0x60, 0xb7, 0x3b, 0xf7, 0x70, + 0xb8, 0x06, 0xf0, 0x60, 0xb9, 0x1b, 0xd9, 0x70, 0xb9, 0xe6, 0xd2, 0x60, + 0xbb, 0x04, 0xf5, 0xf0, 0xbb, 0xc6, 0xb4, 0x60, 0xbc, 0xe4, 0xd7, 0xf0, + 0xbd, 0xaf, 0xd0, 0xe0, 0xbe, 0xc4, 0xb9, 0xf0, 0xbf, 0x8f, 0xb2, 0xe0, + 0xc0, 0xa4, 0x9b, 0xf0, 0xc1, 0x6f, 0x94, 0xe0, 0xc2, 0x84, 0x7d, 0xf0, + 0xc3, 0x4f, 0x76, 0xe0, 0xc4, 0x64, 0x5f, 0xf0, 0xc5, 0x2f, 0x58, 0xe0, + 0xc6, 0x4d, 0x7c, 0x70, 0xc7, 0x0f, 0x3a, 0xe0, 0xc8, 0x2d, 0x5e, 0x70, + 0xc8, 0xf8, 0x57, 0x60, 0xca, 0x0d, 0x40, 0x70, 0xca, 0xd8, 0x39, 0x60, + 0xcb, 0x88, 0xf0, 0x70, 0xd2, 0x23, 0xf4, 0x70, 0xd2, 0x60, 0xfb, 0xe0, + 0xd3, 0x75, 0xe4, 0xf0, 0xd4, 0x40, 0xdd, 0xe0, 0xd5, 0x55, 0xc6, 0xf0, + 0xd6, 0x20, 0xbf, 0xe0, 0xd7, 0x35, 0xa8, 0xf0, 0xd8, 0x00, 0xa1, 0xe0, + 0xd9, 0x15, 0x8a, 0xf0, 0xd9, 0xe0, 0x83, 0xe0, 0xda, 0xfe, 0xa7, 0x70, + 0xdb, 0xc0, 0x65, 0xe0, 0xdc, 0xde, 0x89, 0x70, 0xdd, 0xa9, 0x82, 0x60, + 0xde, 0xbe, 0x6b, 0x70, 0xdf, 0x89, 0x64, 0x60, 0xe0, 0x9e, 0x4d, 0x70, + 0xe1, 0x69, 0x46, 0x60, 0xe2, 0x7e, 0x2f, 0x70, 0xe3, 0x49, 0x28, 0x60, + 0xe4, 0x5e, 0x11, 0x70, 0xe5, 0x57, 0x2e, 0xe0, 0xe6, 0x47, 0x2d, 0xf0, + 0xe7, 0x37, 0x10, 0xe0, 0xe8, 0x27, 0x0f, 0xf0, 0xe9, 0x16, 0xf2, 0xe0, + 0xea, 0x06, 0xf1, 0xf0, 0xea, 0xf6, 0xd4, 0xe0, 0xeb, 0xe6, 0xd3, 0xf0, + 0xec, 0xd6, 0xb6, 0xe0, 0xed, 0xc6, 0xb5, 0xf0, 0xee, 0xbf, 0xd3, 0x60, + 0xef, 0xaf, 0xd2, 0x70, 0xf0, 0x9f, 0xb5, 0x60, 0xf1, 0x8f, 0xb4, 0x70, + 0xf2, 0x7f, 0x97, 0x60, 0xf3, 0x6f, 0x96, 0x70, 0xf4, 0x5f, 0x79, 0x60, + 0xf5, 0x4f, 0x78, 0x70, 0xf6, 0x3f, 0x5b, 0x60, 0xf7, 0x2f, 0x5a, 0x70, + 0xf8, 0x28, 0x77, 0xe0, 0xf9, 0x0f, 0x3c, 0x70, 0xfa, 0x08, 0x59, 0xe0, + 0xfa, 0xf8, 0x58, 0xf0, 0xfb, 0xe8, 0x3b, 0xe0, 0xfc, 0xd8, 0x3a, 0xf0, + 0xfd, 0xc8, 0x1d, 0xe0, 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xa7, 0xff, 0xe0, + 0x00, 0x97, 0xfe, 0xf0, 0x01, 0x87, 0xe1, 0xe0, 0x02, 0x77, 0xe0, 0xf0, + 0x03, 0x70, 0xfe, 0x60, 0x04, 0x60, 0xfd, 0x70, 0x05, 0x50, 0xe0, 0x60, + 0x06, 0x40, 0xdf, 0x70, 0x07, 0x30, 0xc2, 0x60, 0x07, 0x8d, 0x19, 0x70, + 0x09, 0x10, 0xa4, 0x60, 0x09, 0xad, 0x94, 0xf0, 0x0a, 0xf0, 0x86, 0x60, + 0x0b, 0xe0, 0x85, 0x70, 0x0c, 0xd9, 0xa2, 0xe0, 0x0d, 0xc0, 0x67, 0x70, + 0x0e, 0xb9, 0x84, 0xe0, 0x0f, 0xa9, 0x83, 0xf0, 0x10, 0x99, 0x66, 0xe0, + 0x11, 0x89, 0x65, 0xf0, 0x12, 0x79, 0x48, 0xe0, 0x13, 0x69, 0x47, 0xf0, + 0x14, 0x59, 0x2a, 0xe0, 0x15, 0x49, 0x29, 0xf0, 0x16, 0x39, 0x0c, 0xe0, + 0x17, 0x29, 0x0b, 0xf0, 0x18, 0x22, 0x29, 0x60, 0x19, 0x08, 0xed, 0xf0, + 0x1a, 0x02, 0x0b, 0x60, 0x1a, 0xf2, 0x0a, 0x70, 0x1b, 0xe1, 0xed, 0x60, + 0x1c, 0xd1, 0xec, 0x70, 0x1d, 0xc1, 0xcf, 0x60, 0x1e, 0xb1, 0xce, 0x70, + 0x1f, 0xa1, 0xb1, 0x60, 0x20, 0x76, 0x00, 0xf0, 0x21, 0x81, 0x93, 0x60, + 0x22, 0x55, 0xe2, 0xf0, 0x23, 0x6a, 0xaf, 0xe0, 0x24, 0x35, 0xc4, 0xf0, + 0x25, 0x4a, 0x91, 0xe0, 0x26, 0x15, 0xa6, 0xf0, 0x27, 0x2a, 0x73, 0xe0, + 0x27, 0xfe, 0xc3, 0x70, 0x29, 0x0a, 0x55, 0xe0, 0x29, 0xde, 0xa5, 0x70, + 0x2a, 0xea, 0x37, 0xe0, 0x2b, 0xbe, 0x87, 0x70, 0x2c, 0xd3, 0x54, 0x60, + 0x2d, 0x9e, 0x69, 0x70, 0x2e, 0xb3, 0x36, 0x60, 0x2f, 0x7e, 0x4b, 0x70, + 0x30, 0x93, 0x18, 0x60, 0x31, 0x67, 0x67, 0xf0, 0x32, 0x72, 0xfa, 0x60, + 0x33, 0x47, 0x49, 0xf0, 0x34, 0x52, 0xdc, 0x60, 0x35, 0x27, 0x2b, 0xf0, + 0x36, 0x32, 0xbe, 0x60, 0x37, 0x07, 0x0d, 0xf0, 0x38, 0x1b, 0xda, 0xe0, + 0x38, 0xe6, 0xef, 0xf0, 0x39, 0xfb, 0xbc, 0xe0, 0x3a, 0xc6, 0xd1, 0xf0, + 0x3b, 0xdb, 0x9e, 0xe0, 0x3c, 0xaf, 0xee, 0x70, 0x3d, 0xbb, 0x80, 0xe0, + 0x3e, 0x8f, 0xd0, 0x70, 0x3f, 0x9b, 0x62, 0xe0, 0x40, 0x6f, 0xb2, 0x70, + 0x41, 0x84, 0x7f, 0x60, 0x42, 0x4f, 0x94, 0x70, 0x43, 0x64, 0x61, 0x60, + 0x44, 0x2f, 0x76, 0x70, 0x45, 0x44, 0x43, 0x60, 0x45, 0xf3, 0xa8, 0xf0, + 0x47, 0x2d, 0x5f, 0xe0, 0x47, 0xd3, 0x8a, 0xf0, 0x49, 0x0d, 0x41, 0xe0, + 0x49, 0xb3, 0x6c, 0xf0, 0x4a, 0xed, 0x23, 0xe0, 0x4b, 0x9c, 0x89, 0x70, + 0x4c, 0xd6, 0x40, 0x60, 0x4d, 0x7c, 0x6b, 0x70, 0x4e, 0xb6, 0x22, 0x60, + 0x4f, 0x5c, 0x4d, 0x70, 0x50, 0x96, 0x04, 0x60, 0x51, 0x3c, 0x2f, 0x70, + 0x52, 0x75, 0xe6, 0x60, 0x53, 0x1c, 0x11, 0x70, 0x54, 0x55, 0xc8, 0x60, + 0x54, 0xfb, 0xf3, 0x70, 0x56, 0x35, 0xaa, 0x60, 0x56, 0xe5, 0x0f, 0xf0, + 0x58, 0x1e, 0xc6, 0xe0, 0x58, 0xc4, 0xf1, 0xf0, 0x59, 0xfe, 0xa8, 0xe0, + 0x5a, 0xa4, 0xd3, 0xf0, 0x5b, 0xde, 0x8a, 0xe0, 0x5c, 0x84, 0xb5, 0xf0, + 0x5d, 0xbe, 0x6c, 0xe0, 0x5e, 0x64, 0x97, 0xf0, 0x5f, 0x9e, 0x4e, 0xe0, + 0x60, 0x4d, 0xb4, 0x70, 0x61, 0x87, 0x6b, 0x60, 0x62, 0x2d, 0x96, 0x70, + 0x63, 0x67, 0x4d, 0x60, 0x64, 0x0d, 0x78, 0x70, 0x65, 0x47, 0x2f, 0x60, + 0x65, 0xed, 0x5a, 0x70, 0x67, 0x27, 0x11, 0x60, 0x67, 0xcd, 0x3c, 0x70, + 0x69, 0x06, 0xf3, 0x60, 0x69, 0xad, 0x1e, 0x70, 0x6a, 0xe6, 0xd5, 0x60, + 0x6b, 0x96, 0x3a, 0xf0, 0x6c, 0xcf, 0xf1, 0xe0, 0x6d, 0x76, 0x1c, 0xf0, + 0x6e, 0xaf, 0xd3, 0xe0, 0x6f, 0x55, 0xfe, 0xf0, 0x70, 0x8f, 0xb5, 0xe0, + 0x71, 0x35, 0xe0, 0xf0, 0x72, 0x6f, 0x97, 0xe0, 0x73, 0x15, 0xc2, 0xf0, + 0x74, 0x4f, 0x79, 0xe0, 0x74, 0xfe, 0xdf, 0x70, 0x76, 0x38, 0x96, 0x60, + 0x76, 0xde, 0xc1, 0x70, 0x78, 0x18, 0x78, 0x60, 0x78, 0xbe, 0xa3, 0x70, + 0x79, 0xf8, 0x5a, 0x60, 0x7a, 0x9e, 0x85, 0x70, 0x7b, 0xd8, 0x3c, 0x60, + 0x7c, 0x7e, 0x67, 0x70, 0x7d, 0xb8, 0x1e, 0x60, 0x7e, 0x5e, 0x49, 0x70, + 0x7f, 0x98, 0x00, 0x60, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x04, + 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x0c, + 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, 0x4d, 0x54, 0x00, 0x45, 0x44, + 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, 0x57, 0x54, 0x00, 0x45, 0x50, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x03, 0xf0, 0x90, + 0xff, 0xff, 0xff, 0xff, 0x9e, 0xa6, 0x1e, 0x70, 0xff, 0xff, 0xff, 0xff, + 0x9f, 0xba, 0xeb, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa0, 0x86, 0x00, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xa1, 0x9a, 0xcd, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xa2, 0x65, 0xe2, 0x70, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x83, 0xe9, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xa4, 0x6a, 0xae, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xa5, 0x35, 0xa7, 0x60, 0xff, 0xff, 0xff, 0xff, 0xa6, 0x53, 0xca, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xa7, 0x15, 0x89, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xa8, 0x33, 0xac, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xa8, 0xfe, 0xa5, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xaa, 0x13, 0x8e, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xaa, 0xde, 0x87, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xab, 0xf3, 0x70, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xac, 0xbe, 0x69, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xad, 0xd3, 0x52, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xae, 0x9e, 0x4b, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xaf, 0xb3, 0x34, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xb0, 0x7e, 0x2d, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x9c, 0x51, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xb2, 0x67, 0x4a, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xb3, 0x7c, 0x33, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb4, 0x47, 0x2c, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xb5, 0x5c, 0x15, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xb6, 0x27, 0x0e, 0x60, 0xff, 0xff, 0xff, 0xff, 0xb7, 0x3b, 0xf7, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xb8, 0x06, 0xf0, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xb9, 0x1b, 0xd9, 0x70, 0xff, 0xff, 0xff, 0xff, 0xb9, 0xe6, 0xd2, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xbb, 0x04, 0xf5, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xbb, 0xc6, 0xb4, 0x60, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe4, 0xd7, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xbd, 0xaf, 0xd0, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xbe, 0xc4, 0xb9, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xbf, 0x8f, 0xb2, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0xa4, 0x9b, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xc1, 0x6f, 0x94, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x84, 0x7d, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xc3, 0x4f, 0x76, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xc4, 0x64, 0x5f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xc5, 0x2f, 0x58, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xc6, 0x4d, 0x7c, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0x0f, 0x3a, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x2d, 0x5e, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xc8, 0xf8, 0x57, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xca, 0x0d, 0x40, 0x70, 0xff, 0xff, 0xff, 0xff, 0xca, 0xd8, 0x39, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xcb, 0x88, 0xf0, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xd2, 0x23, 0xf4, 0x70, 0xff, 0xff, 0xff, 0xff, 0xd2, 0x60, 0xfb, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xd3, 0x75, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xd4, 0x40, 0xdd, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xd5, 0x55, 0xc6, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xd6, 0x20, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xd7, 0x35, 0xa8, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xd8, 0x00, 0xa1, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xd9, 0x15, 0x8a, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xd9, 0xe0, 0x83, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xda, 0xfe, 0xa7, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xdb, 0xc0, 0x65, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xdc, 0xde, 0x89, 0x70, 0xff, 0xff, 0xff, 0xff, 0xdd, 0xa9, 0x82, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xde, 0xbe, 0x6b, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xdf, 0x89, 0x64, 0x60, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x9e, 0x4d, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xe1, 0x69, 0x46, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xe2, 0x7e, 0x2f, 0x70, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x49, 0x28, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xe4, 0x5e, 0x11, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xe5, 0x57, 0x2e, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xe6, 0x47, 0x2d, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xe7, 0x37, 0x10, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xe8, 0x27, 0x0f, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x16, 0xf2, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xea, 0x06, 0xf1, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xea, 0xf6, 0xd4, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xeb, 0xe6, 0xd3, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xec, 0xd6, 0xb6, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xed, 0xc6, 0xb5, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xee, 0xbf, 0xd3, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xef, 0xaf, 0xd2, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x9f, 0xb5, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf1, 0x8f, 0xb4, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xf2, 0x7f, 0x97, 0x60, 0xff, 0xff, 0xff, 0xff, + 0xf3, 0x6f, 0x96, 0x70, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x5f, 0x79, 0x60, + 0xff, 0xff, 0xff, 0xff, 0xf5, 0x4f, 0x78, 0x70, 0xff, 0xff, 0xff, 0xff, + 0xf6, 0x3f, 0x5b, 0x60, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x2f, 0x5a, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x28, 0x77, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xf9, 0x0f, 0x3c, 0x70, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x08, 0x59, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfa, 0xf8, 0x58, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xfb, 0xe8, 0x3b, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xd8, 0x3a, 0xf0, + 0xff, 0xff, 0xff, 0xff, 0xfd, 0xc8, 0x1d, 0xe0, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xb8, 0x1c, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x87, 0xe1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x77, 0xe0, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x70, 0xfe, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x60, 0xfd, 0x70, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0xe0, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x40, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x30, 0xc2, 0x60, 0x00, 0x00, 0x00, 0x00, 0x07, 0x8d, 0x19, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x10, 0xa4, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x09, 0xad, 0x94, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xf0, 0x86, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0xe0, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0xd9, 0xa2, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0d, 0xc0, 0x67, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb9, 0x84, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0xa9, 0x83, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x99, 0x66, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x89, 0x65, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x79, 0x48, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x13, 0x69, 0x47, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x59, 0x2a, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x49, 0x29, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x16, 0x39, 0x0c, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x17, 0x29, 0x0b, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x22, 0x29, 0x60, 0x00, 0x00, 0x00, 0x00, 0x19, 0x08, 0xed, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x0b, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0xf2, 0x0a, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0xed, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0xd1, 0xec, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x1d, 0xc1, 0xcf, 0x60, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb1, 0xce, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0xa1, 0xb1, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x76, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x21, 0x81, 0x93, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x22, 0x55, 0xe2, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x6a, 0xaf, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x24, 0x35, 0xc4, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x25, 0x4a, 0x91, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x15, 0xa6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x27, 0x2a, 0x73, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x27, 0xfe, 0xc3, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x0a, 0x55, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x29, 0xde, 0xa5, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0xea, 0x37, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0xbe, 0x87, 0x70, 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd3, 0x54, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x2d, 0x9e, 0x69, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0xb3, 0x36, 0x60, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x7e, 0x4b, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x93, 0x18, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x67, 0x67, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0xfa, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x33, 0x47, 0x49, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x52, 0xdc, 0x60, 0x00, 0x00, 0x00, 0x00, 0x35, 0x27, 0x2b, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x32, 0xbe, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x37, 0x07, 0x0d, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0xda, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x38, 0xe6, 0xef, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x39, 0xfb, 0xbc, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3a, 0xc6, 0xd1, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x3b, 0xdb, 0x9e, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0xaf, 0xee, 0x70, 0x00, 0x00, 0x00, 0x00, 0x3d, 0xbb, 0x80, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x3e, 0x8f, 0xd0, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x3f, 0x9b, 0x62, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6f, 0xb2, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x41, 0x84, 0x7f, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x42, 0x4f, 0x94, 0x70, 0x00, 0x00, 0x00, 0x00, 0x43, 0x64, 0x61, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x2f, 0x76, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x44, 0x43, 0x60, 0x00, 0x00, 0x00, 0x00, 0x45, 0xf3, 0xa8, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x47, 0x2d, 0x5f, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x47, 0xd3, 0x8a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x49, 0x0d, 0x41, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x49, 0xb3, 0x6c, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x4a, 0xed, 0x23, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x9c, 0x89, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x4c, 0xd6, 0x40, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x4d, 0x7c, 0x6b, 0x70, 0x00, 0x00, 0x00, 0x00, 0x4e, 0xb6, 0x22, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x4f, 0x5c, 0x4d, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x96, 0x04, 0x60, 0x00, 0x00, 0x00, 0x00, 0x51, 0x3c, 0x2f, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x52, 0x75, 0xe6, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x1c, 0x11, 0x70, 0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0xc8, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x54, 0xfb, 0xf3, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x35, 0xaa, 0x60, 0x00, 0x00, 0x00, 0x00, 0x56, 0xe5, 0x0f, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x1e, 0xc6, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x58, 0xc4, 0xf1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x59, 0xfe, 0xa8, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x5a, 0xa4, 0xd3, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x5b, 0xde, 0x8a, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x84, 0xb5, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0xbe, 0x6c, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x5e, 0x64, 0x97, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x9e, 0x4e, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x4d, 0xb4, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x87, 0x6b, 0x60, 0x00, 0x00, 0x00, 0x00, 0x62, 0x2d, 0x96, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x67, 0x4d, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x0d, 0x78, 0x70, 0x00, 0x00, 0x00, 0x00, 0x65, 0x47, 0x2f, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x65, 0xed, 0x5a, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x67, 0x27, 0x11, 0x60, 0x00, 0x00, 0x00, 0x00, 0x67, 0xcd, 0x3c, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x69, 0x06, 0xf3, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x69, 0xad, 0x1e, 0x70, 0x00, 0x00, 0x00, 0x00, 0x6a, 0xe6, 0xd5, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x6b, 0x96, 0x3a, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0xcf, 0xf1, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x76, 0x1c, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x6e, 0xaf, 0xd3, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x55, 0xfe, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x8f, 0xb5, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x71, 0x35, 0xe0, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x6f, 0x97, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x73, 0x15, 0xc2, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x4f, 0x79, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x74, 0xfe, 0xdf, 0x70, 0x00, 0x00, 0x00, 0x00, 0x76, 0x38, 0x96, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x76, 0xde, 0xc1, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x18, 0x78, 0x60, 0x00, 0x00, 0x00, 0x00, 0x78, 0xbe, 0xa3, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x79, 0xf8, 0x5a, 0x60, 0x00, 0x00, 0x00, 0x00, + 0x7a, 0x9e, 0x85, 0x70, 0x00, 0x00, 0x00, 0x00, 0x7b, 0xd8, 0x3c, 0x60, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7e, 0x67, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x7d, 0xb8, 0x1e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x5e, 0x49, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x98, 0x00, 0x60, 0x00, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, + 0x02, 0x01, 0x02, 0x01, 0x02, 0xff, 0xff, 0xba, 0x9e, 0x00, 0x00, 0xff, + 0xff, 0xc7, 0xc0, 0x01, 0x04, 0xff, 0xff, 0xb9, 0xb0, 0x00, 0x08, 0xff, + 0xff, 0xc7, 0xc0, 0x01, 0x0c, 0xff, 0xff, 0xc7, 0xc0, 0x01, 0x10, 0x4c, + 0x4d, 0x54, 0x00, 0x45, 0x44, 0x54, 0x00, 0x45, 0x53, 0x54, 0x00, 0x45, + 0x57, 0x54, 0x00, 0x45, 0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44, + 0x54, 0x2c, 0x4d, 0x33, 0x2e, 0x32, 0x2e, 0x30, 0x2c, 0x4d, 0x31, 0x31, + 0x2e, 0x31, 0x2e, 0x30, 0x0a +}; +unsigned int America_New_York_len = 3545; +unsigned char Australia_Sydney[] = { + 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, 0x80, 0x00, 0x00, 0x00, + 0x9c, 0x4e, 0xa6, 0x9c, 0x9c, 0xbc, 0x20, 0xf0, 0xcb, 0x54, 0xb3, 0x00, + 0xcb, 0xc7, 0x57, 0x70, 0xcc, 0xb7, 0x56, 0x80, 0xcd, 0xa7, 0x39, 0x70, + 0xce, 0xa0, 0x73, 0x00, 0xcf, 0x87, 0x1b, 0x70, 0x03, 0x70, 0x39, 0x80, + 0x04, 0x0d, 0x1c, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x05, 0xf6, 0x38, 0x80, + 0x07, 0x2f, 0xfd, 0x80, 0x07, 0xd6, 0x1a, 0x80, 0x09, 0x0f, 0xdf, 0x80, + 0x09, 0xb5, 0xfc, 0x80, 0x0a, 0xef, 0xc1, 0x80, 0x0b, 0x9f, 0x19, 0x00, + 0x0c, 0xd8, 0xde, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x0e, 0xb8, 0xc0, 0x00, + 0x0f, 0x5e, 0xdd, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x11, 0x3e, 0xbf, 0x00, + 0x12, 0x78, 0x84, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x14, 0x58, 0x66, 0x00, + 0x14, 0xfe, 0x83, 0x00, 0x16, 0x38, 0x48, 0x00, 0x17, 0x0c, 0x89, 0x80, + 0x18, 0x21, 0x64, 0x80, 0x18, 0xc7, 0x81, 0x80, 0x1a, 0x01, 0x46, 0x80, + 0x1a, 0xa7, 0x63, 0x80, 0x1b, 0xe1, 0x28, 0x80, 0x1c, 0x87, 0x45, 0x80, + 0x1d, 0xc1, 0x0a, 0x80, 0x1e, 0x79, 0x9c, 0x80, 0x1f, 0x97, 0xb2, 0x00, + 0x20, 0x59, 0x7e, 0x80, 0x21, 0x80, 0xce, 0x80, 0x22, 0x42, 0x9b, 0x00, + 0x23, 0x69, 0xeb, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x25, 0x49, 0xcd, 0x00, + 0x25, 0xef, 0xea, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x27, 0xcf, 0xcc, 0x00, + 0x29, 0x09, 0x91, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x2a, 0xe9, 0x73, 0x00, + 0x2b, 0x98, 0xca, 0x80, 0x2c, 0xd2, 0x8f, 0x80, 0x2d, 0x78, 0xac, 0x80, + 0x2e, 0xb2, 0x71, 0x80, 0x2f, 0x58, 0x8e, 0x80, 0x30, 0x92, 0x53, 0x80, + 0x31, 0x5d, 0x5a, 0x80, 0x32, 0x72, 0x35, 0x80, 0x33, 0x3d, 0x3c, 0x80, + 0x34, 0x52, 0x17, 0x80, 0x35, 0x1d, 0x1e, 0x80, 0x36, 0x31, 0xf9, 0x80, + 0x36, 0xfd, 0x00, 0x80, 0x38, 0x1b, 0x16, 0x00, 0x38, 0xdc, 0xe2, 0x80, + 0x39, 0xa7, 0xe9, 0x80, 0x3a, 0xbc, 0xc4, 0x80, 0x3b, 0xda, 0xda, 0x00, + 0x3c, 0xa5, 0xe1, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x3e, 0x85, 0xc3, 0x00, + 0x3f, 0x9a, 0x9e, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x41, 0x83, 0xba, 0x80, + 0x42, 0x45, 0x87, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x44, 0x2e, 0xa3, 0x80, + 0x45, 0x43, 0x7e, 0x80, 0x46, 0x05, 0x4b, 0x00, 0x47, 0x23, 0x60, 0x80, + 0x47, 0xf7, 0xa2, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x49, 0xd7, 0x84, 0x00, + 0x4a, 0xc7, 0x75, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x4c, 0xa7, 0x57, 0x00, + 0x4d, 0x97, 0x48, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x4f, 0x77, 0x2a, 0x00, + 0x50, 0x70, 0x55, 0x80, 0x51, 0x60, 0x46, 0x80, 0x52, 0x50, 0x37, 0x80, + 0x53, 0x40, 0x28, 0x80, 0x54, 0x30, 0x19, 0x80, 0x55, 0x20, 0x0a, 0x80, + 0x56, 0x0f, 0xfb, 0x80, 0x56, 0xff, 0xec, 0x80, 0x57, 0xef, 0xdd, 0x80, + 0x58, 0xdf, 0xce, 0x80, 0x59, 0xcf, 0xbf, 0x80, 0x5a, 0xbf, 0xb0, 0x80, + 0x5b, 0xb8, 0xdc, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x5d, 0x98, 0xbe, 0x00, + 0x5e, 0x88, 0xaf, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x60, 0x68, 0x91, 0x00, + 0x61, 0x58, 0x82, 0x00, 0x62, 0x48, 0x73, 0x00, 0x63, 0x38, 0x64, 0x00, + 0x64, 0x28, 0x55, 0x00, 0x65, 0x18, 0x46, 0x00, 0x66, 0x11, 0x71, 0x80, + 0x67, 0x01, 0x62, 0x80, 0x67, 0xf1, 0x53, 0x80, 0x68, 0xe1, 0x44, 0x80, + 0x69, 0xd1, 0x35, 0x80, 0x6a, 0xc1, 0x26, 0x80, 0x6b, 0xb1, 0x17, 0x80, + 0x6c, 0xa1, 0x08, 0x80, 0x6d, 0x90, 0xf9, 0x80, 0x6e, 0x80, 0xea, 0x80, + 0x6f, 0x70, 0xdb, 0x80, 0x70, 0x6a, 0x07, 0x00, 0x71, 0x59, 0xf8, 0x00, + 0x72, 0x49, 0xe9, 0x00, 0x73, 0x39, 0xda, 0x00, 0x74, 0x29, 0xcb, 0x00, + 0x75, 0x19, 0xbc, 0x00, 0x76, 0x09, 0xad, 0x00, 0x76, 0xf9, 0x9e, 0x00, + 0x77, 0xe9, 0x8f, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x79, 0xc9, 0x71, 0x00, + 0x7a, 0xb9, 0x62, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x7c, 0xa2, 0x7e, 0x80, + 0x7d, 0x92, 0x6f, 0x80, 0x7e, 0x82, 0x60, 0x80, 0x7f, 0x72, 0x51, 0x80, + 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, + 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x00, 0x00, + 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00, + 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, 0xb0, 0x01, 0x04, 0x00, 0x00, + 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, 0x00, 0x41, 0x45, 0x44, 0x54, + 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0e, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x73, 0x16, 0x7f, 0x3c, 0xff, 0xff, 0xff, 0xff, 0x9c, 0x4e, 0xa6, 0x9c, + 0xff, 0xff, 0xff, 0xff, 0x9c, 0xbc, 0x20, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xcb, 0x54, 0xb3, 0x00, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xc7, 0x57, 0x70, + 0xff, 0xff, 0xff, 0xff, 0xcc, 0xb7, 0x56, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xcd, 0xa7, 0x39, 0x70, 0xff, 0xff, 0xff, 0xff, 0xce, 0xa0, 0x73, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xcf, 0x87, 0x1b, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x70, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0d, 0x1c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, 0x1b, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x05, 0xf6, 0x38, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x2f, 0xfd, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xd6, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x0f, 0xdf, 0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xb5, 0xfc, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0xef, 0xc1, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x9f, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xd8, 0xde, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x7e, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0xb8, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x5e, 0xdd, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x98, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x3e, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x78, 0x84, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x1e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x58, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0xfe, 0x83, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x38, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x0c, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, 0x18, 0x21, 0x64, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x18, 0xc7, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1a, 0xa7, 0x63, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0xe1, 0x28, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x87, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1d, 0xc1, 0x0a, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x79, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x97, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x59, 0x7e, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x21, 0x80, 0xce, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x42, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x69, 0xeb, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x22, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x49, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0xef, 0xea, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x27, 0x29, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0xcf, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x09, 0x91, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x29, 0xaf, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0xe9, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x98, 0xca, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x2c, 0xd2, 0x8f, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x2d, 0x78, 0xac, 0x80, 0x00, 0x00, 0x00, 0x00, 0x2e, 0xb2, 0x71, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x2f, 0x58, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x92, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, 0x31, 0x5d, 0x5a, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x32, 0x72, 0x35, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x3d, 0x3c, 0x80, 0x00, 0x00, 0x00, 0x00, 0x34, 0x52, 0x17, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x35, 0x1d, 0x1e, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x31, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x36, 0xfd, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0xdc, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, 0x39, 0xa7, 0xe9, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0xbc, 0xc4, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x3b, 0xda, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0xa5, 0xe1, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3d, 0xba, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x85, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x9a, 0x9e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x65, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x41, 0x83, 0xba, 0x80, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0x87, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x9c, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x2e, 0xa3, 0x80, 0x00, 0x00, 0x00, 0x00, 0x45, 0x43, 0x7e, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x05, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x23, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0xf7, 0xa2, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0xe7, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x49, 0xd7, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0xc7, 0x75, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4b, 0xb7, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0xa7, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x97, 0x48, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4e, 0x87, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0x77, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x70, 0x55, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x60, 0x46, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x52, 0x50, 0x37, 0x80, 0x00, 0x00, 0x00, 0x00, 0x53, 0x40, 0x28, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x30, 0x19, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x20, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x56, 0x0f, 0xfb, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x56, 0xff, 0xec, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x57, 0xef, 0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x58, 0xdf, 0xce, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x59, 0xcf, 0xbf, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0xbf, 0xb0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x5b, 0xb8, 0xdc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5c, 0xa8, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5d, 0x98, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x88, 0xaf, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x68, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x58, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x62, 0x48, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x38, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x28, 0x55, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x65, 0x18, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x11, 0x71, 0x80, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x62, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x67, 0xf1, 0x53, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xe1, 0x44, 0x80, 0x00, 0x00, 0x00, 0x00, 0x69, 0xd1, 0x35, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x6a, 0xc1, 0x26, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x6b, 0xb1, 0x17, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xa1, 0x08, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x6d, 0x90, 0xf9, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x6e, 0x80, 0xea, 0x80, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x70, 0xdb, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x70, 0x6a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x71, 0x59, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x49, 0xe9, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x39, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x74, 0x29, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x19, 0xbc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0x09, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x76, 0xf9, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0xe9, 0x8f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0xd9, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x79, 0xc9, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0xb9, 0x62, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7b, 0xb2, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0xa2, 0x7e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x92, 0x6f, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x82, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x7f, 0x72, 0x51, 0x80, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, + 0x01, 0x02, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, 0x03, 0x04, + 0x03, 0x04, 0x03, 0x00, 0x00, 0x8d, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x9a, + 0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x00, 0x00, 0x9a, + 0xb0, 0x01, 0x04, 0x00, 0x00, 0x8c, 0xa0, 0x00, 0x09, 0x4c, 0x4d, 0x54, + 0x00, 0x41, 0x45, 0x44, 0x54, 0x00, 0x41, 0x45, 0x53, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x41, 0x45, + 0x53, 0x54, 0x2d, 0x31, 0x30, 0x41, 0x45, 0x44, 0x54, 0x2c, 0x4d, 0x31, + 0x30, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x4d, 0x34, 0x2e, 0x31, 0x2e, 0x30, + 0x2f, 0x33, 0x0a +}; +unsigned int Australia_Sydney_len = 2223; diff --git a/third_party/abseil_cpp/absl/time/time.cc b/third_party/abseil_cpp/absl/time/time.cc new file mode 100644 index 000000000000..1ec2026e254f --- /dev/null +++ b/third_party/abseil_cpp/absl/time/time.cc @@ -0,0 +1,500 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The implementation of the absl::Time class, which is declared in +// //absl/time.h. +// +// The representation for an absl::Time is an absl::Duration offset from the +// epoch. We use the traditional Unix epoch (1970-01-01 00:00:00 +0000) +// for convenience, but this is not exposed in the API and could be changed. +// +// NOTE: To keep type verbosity to a minimum, the following variable naming +// conventions are used throughout this file. +// +// tz: An absl::TimeZone +// ci: An absl::TimeZone::CivilInfo +// ti: An absl::TimeZone::TimeInfo +// cd: An absl::CivilDay or a cctz::civil_day +// cs: An absl::CivilSecond or a cctz::civil_second +// bd: An absl::Time::Breakdown +// cl: A cctz::time_zone::civil_lookup +// al: A cctz::time_zone::absolute_lookup + +#include "absl/time/time.h" + +#if defined(_MSC_VER) +#include <winsock2.h> // for timeval +#endif + +#include <cstring> +#include <ctime> +#include <limits> + +#include "absl/time/internal/cctz/include/cctz/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +namespace cctz = absl::time_internal::cctz; + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace { + +inline cctz::time_point<cctz::seconds> unix_epoch() { + return std::chrono::time_point_cast<cctz::seconds>( + std::chrono::system_clock::from_time_t(0)); +} + +// Floors d to the next unit boundary closer to negative infinity. +inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { + absl::Duration rem; + int64_t q = absl::IDivDuration(d, unit, &rem); + return (q > 0 || rem >= ZeroDuration() || + q == std::numeric_limits<int64_t>::min()) + ? q + : q - 1; +} + +inline absl::Time::Breakdown InfiniteFutureBreakdown() { + absl::Time::Breakdown bd; + bd.year = std::numeric_limits<int64_t>::max(); + bd.month = 12; + bd.day = 31; + bd.hour = 23; + bd.minute = 59; + bd.second = 59; + bd.subsecond = absl::InfiniteDuration(); + bd.weekday = 4; + bd.yearday = 365; + bd.offset = 0; + bd.is_dst = false; + bd.zone_abbr = "-00"; + return bd; +} + +inline absl::Time::Breakdown InfinitePastBreakdown() { + Time::Breakdown bd; + bd.year = std::numeric_limits<int64_t>::min(); + bd.month = 1; + bd.day = 1; + bd.hour = 0; + bd.minute = 0; + bd.second = 0; + bd.subsecond = -absl::InfiniteDuration(); + bd.weekday = 7; + bd.yearday = 1; + bd.offset = 0; + bd.is_dst = false; + bd.zone_abbr = "-00"; + return bd; +} + +inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() { + TimeZone::CivilInfo ci; + ci.cs = CivilSecond::max(); + ci.subsecond = InfiniteDuration(); + ci.offset = 0; + ci.is_dst = false; + ci.zone_abbr = "-00"; + return ci; +} + +inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() { + TimeZone::CivilInfo ci; + ci.cs = CivilSecond::min(); + ci.subsecond = -InfiniteDuration(); + ci.offset = 0; + ci.is_dst = false; + ci.zone_abbr = "-00"; + return ci; +} + +inline absl::TimeConversion InfiniteFutureTimeConversion() { + absl::TimeConversion tc; + tc.pre = tc.trans = tc.post = absl::InfiniteFuture(); + tc.kind = absl::TimeConversion::UNIQUE; + tc.normalized = true; + return tc; +} + +inline TimeConversion InfinitePastTimeConversion() { + absl::TimeConversion tc; + tc.pre = tc.trans = tc.post = absl::InfinitePast(); + tc.kind = absl::TimeConversion::UNIQUE; + tc.normalized = true; + return tc; +} + +// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as +// necessary. If sec is min/max, then consult cs+tz to check for overlow. +Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec, + const cctz::civil_second& cs, + const cctz::time_zone& tz, + bool* normalized = nullptr) { + const auto max = cctz::time_point<cctz::seconds>::max(); + const auto min = cctz::time_point<cctz::seconds>::min(); + if (sec == max) { + const auto al = tz.lookup(max); + if (cs > al.cs) { + if (normalized) *normalized = true; + return absl::InfiniteFuture(); + } + } + if (sec == min) { + const auto al = tz.lookup(min); + if (cs < al.cs) { + if (normalized) *normalized = true; + return absl::InfinitePast(); + } + } + const auto hi = (sec - unix_epoch()).count(); + return time_internal::FromUnixDuration(time_internal::MakeDuration(hi)); +} + +// Returns Mon=1..Sun=7. +inline int MapWeekday(const cctz::weekday& wd) { + switch (wd) { + case cctz::weekday::monday: + return 1; + case cctz::weekday::tuesday: + return 2; + case cctz::weekday::wednesday: + return 3; + case cctz::weekday::thursday: + return 4; + case cctz::weekday::friday: + return 5; + case cctz::weekday::saturday: + return 6; + case cctz::weekday::sunday: + return 7; + } + 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 + +// +// Time +// + +absl::Time::Breakdown Time::In(absl::TimeZone tz) const { + if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown(); + if (*this == absl::InfinitePast()) return InfinitePastBreakdown(); + + const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_)); + const auto al = cctz::time_zone(tz).lookup(tp); + const auto cs = al.cs; + const auto cd = cctz::civil_day(cs); + + absl::Time::Breakdown bd; + bd.year = cs.year(); + bd.month = cs.month(); + bd.day = cs.day(); + bd.hour = cs.hour(); + bd.minute = cs.minute(); + bd.second = cs.second(); + bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_)); + bd.weekday = MapWeekday(cctz::get_weekday(cd)); + bd.yearday = cctz::get_yearday(cd); + bd.offset = al.offset; + bd.is_dst = al.is_dst; + bd.zone_abbr = al.abbr; + return bd; +} + +// +// Conversions from/to other time types. +// + +absl::Time FromUDate(double udate) { + return time_internal::FromUnixDuration(absl::Milliseconds(udate)); +} + +absl::Time FromUniversal(int64_t universal) { + return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal); +} + +int64_t ToUnixNanos(Time t) { + if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && + time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) { + return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * + 1000 * 1000 * 1000) + + (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4); + } + return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1)); +} + +int64_t ToUnixMicros(Time t) { + if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && + time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) { + return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * + 1000 * 1000) + + (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000); + } + return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1)); +} + +int64_t ToUnixMillis(Time t) { + if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && + time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) { + return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) + + (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / + (4000 * 1000)); + } + return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1)); +} + +int64_t ToUnixSeconds(Time t) { + return time_internal::GetRepHi(time_internal::ToUnixDuration(t)); +} + +time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; } + +double ToUDate(Time t) { + return absl::FDivDuration(time_internal::ToUnixDuration(t), + absl::Milliseconds(1)); +} + +int64_t ToUniversal(absl::Time t) { + return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100)); +} + +absl::Time TimeFromTimespec(timespec ts) { + return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts)); +} + +absl::Time TimeFromTimeval(timeval tv) { + return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv)); +} + +timespec ToTimespec(Time t) { + timespec ts; + absl::Duration d = time_internal::ToUnixDuration(t); + if (!time_internal::IsInfiniteDuration(d)) { + ts.tv_sec = time_internal::GetRepHi(d); + if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing + ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor + return ts; + } + } + if (d >= absl::ZeroDuration()) { + ts.tv_sec = std::numeric_limits<time_t>::max(); + ts.tv_nsec = 1000 * 1000 * 1000 - 1; + } else { + ts.tv_sec = std::numeric_limits<time_t>::min(); + ts.tv_nsec = 0; + } + return ts; +} + +timeval ToTimeval(Time t) { + timeval tv; + timespec ts = absl::ToTimespec(t); + tv.tv_sec = ts.tv_sec; + if (tv.tv_sec != ts.tv_sec) { // narrowing + if (ts.tv_sec < 0) { + tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min(); + tv.tv_usec = 0; + } else { + tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max(); + tv.tv_usec = 1000 * 1000 - 1; + } + return tv; + } + tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t + return tv; +} + +Time FromChrono(const std::chrono::system_clock::time_point& tp) { + return time_internal::FromUnixDuration(time_internal::FromChrono( + tp - std::chrono::system_clock::from_time_t(0))); +} + +std::chrono::system_clock::time_point ToChronoTime(absl::Time t) { + using D = std::chrono::system_clock::duration; + auto d = time_internal::ToUnixDuration(t); + if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1})); + return std::chrono::system_clock::from_time_t(0) + + time_internal::ToChronoDuration<D>(d); +} + +// +// TimeZone +// + +absl::TimeZone::CivilInfo TimeZone::At(Time t) const { + if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo(); + if (t == absl::InfinitePast()) return InfinitePastCivilInfo(); + + const auto ud = time_internal::ToUnixDuration(t); + const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud)); + const auto al = cz_.lookup(tp); + + TimeZone::CivilInfo ci; + ci.cs = CivilSecond(al.cs); + ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud)); + ci.offset = al.offset; + ci.is_dst = al.is_dst; + ci.zone_abbr = al.abbr; + return ci; +} + +absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const { + const cctz::civil_second cs(ct); + const auto cl = cz_.lookup(cs); + + TimeZone::TimeInfo ti; + switch (cl.kind) { + case cctz::time_zone::civil_lookup::UNIQUE: + ti.kind = TimeZone::TimeInfo::UNIQUE; + break; + case cctz::time_zone::civil_lookup::SKIPPED: + ti.kind = TimeZone::TimeInfo::SKIPPED; + break; + case cctz::time_zone::civil_lookup::REPEATED: + ti.kind = TimeZone::TimeInfo::REPEATED; + break; + } + ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_); + ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_); + ti.post = MakeTimeWithOverflow(cl.post, cs, cz_); + 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. +// + +absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, + int min, int sec, TimeZone tz) { + // Avoids years that are too extreme for CivilSecond to normalize. + if (year > 300000000000) return InfiniteFutureTimeConversion(); + if (year < -300000000000) return InfinitePastTimeConversion(); + + const CivilSecond cs(year, mon, day, hour, min, sec); + const auto ti = tz.At(cs); + + TimeConversion tc; + tc.pre = ti.pre; + tc.trans = ti.trans; + tc.post = ti.post; + switch (ti.kind) { + case TimeZone::TimeInfo::UNIQUE: + tc.kind = TimeConversion::UNIQUE; + break; + case TimeZone::TimeInfo::SKIPPED: + tc.kind = TimeConversion::SKIPPED; + break; + case TimeZone::TimeInfo::REPEATED: + tc.kind = TimeConversion::REPEATED; + break; + } + tc.normalized = false; + if (year != cs.year() || mon != cs.month() || day != cs.day() || + hour != cs.hour() || min != cs.minute() || sec != cs.second()) { + tc.normalized = true; + } + return tc; +} + +absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) { + civil_year_t tm_year = tm.tm_year; + // Avoids years that are too extreme for CivilSecond to normalize. + if (tm_year > 300000000000ll) return InfiniteFuture(); + if (tm_year < -300000000000ll) return InfinitePast(); + int tm_mon = tm.tm_mon; + if (tm_mon == std::numeric_limits<int>::max()) { + tm_mon -= 12; + tm_year += 1; + } + const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec)); + return tm.tm_isdst == 0 ? ti.post : ti.pre; +} + +struct tm ToTM(absl::Time t, absl::TimeZone tz) { + struct tm tm = {}; + + const auto ci = tz.At(t); + const auto& cs = ci.cs; + tm.tm_sec = cs.second(); + tm.tm_min = cs.minute(); + tm.tm_hour = cs.hour(); + tm.tm_mday = cs.day(); + tm.tm_mon = cs.month() - 1; + + // Saturates tm.tm_year in cases of over/underflow, accounting for the fact + // that tm.tm_year is years since 1900. + if (cs.year() < std::numeric_limits<int>::min() + 1900) { + tm.tm_year = std::numeric_limits<int>::min(); + } else if (cs.year() > std::numeric_limits<int>::max()) { + tm.tm_year = std::numeric_limits<int>::max() - 1900; + } else { + tm.tm_year = static_cast<int>(cs.year() - 1900); + } + + switch (GetWeekday(cs)) { + case Weekday::sunday: + tm.tm_wday = 0; + break; + case Weekday::monday: + tm.tm_wday = 1; + break; + case Weekday::tuesday: + tm.tm_wday = 2; + break; + case Weekday::wednesday: + tm.tm_wday = 3; + break; + case Weekday::thursday: + tm.tm_wday = 4; + break; + case Weekday::friday: + tm.tm_wday = 5; + break; + case Weekday::saturday: + tm.tm_wday = 6; + break; + } + tm.tm_yday = GetYearDay(cs) - 1; + tm.tm_isdst = ci.is_dst ? 1 : 0; + + return tm; +} + +ABSL_NAMESPACE_END +} // namespace absl diff --git a/third_party/abseil_cpp/absl/time/time.h b/third_party/abseil_cpp/absl/time/time.h new file mode 100644 index 000000000000..72508031acd6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/time.h @@ -0,0 +1,1581 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: time.h +// ----------------------------------------------------------------------------- +// +// This header file defines abstractions for computing with absolute points +// in time, durations of time, and formatting and parsing time within a given +// time zone. The following abstractions are defined: +// +// * `absl::Time` defines an absolute, specific instance in time +// * `absl::Duration` defines a signed, fixed-length span of time +// * `absl::TimeZone` defines geopolitical time zone regions (as collected +// within the IANA Time Zone database (https://www.iana.org/time-zones)). +// +// Note: Absolute times are distinct from civil times, which refer to the +// human-scale time commonly represented by `YYYY-MM-DD hh:mm:ss`. The mapping +// between absolute and civil times can be specified by use of time zones +// (`absl::TimeZone` within this API). That is: +// +// Civil Time = F(Absolute Time, Time Zone) +// Absolute Time = G(Civil Time, Time Zone) +// +// See civil_time.h for abstractions related to constructing and manipulating +// civil time. +// +// Example: +// +// absl::TimeZone nyc; +// // LoadTimeZone() may fail so it's always better to check for success. +// if (!absl::LoadTimeZone("America/New_York", &nyc)) { +// // handle error case +// } +// +// // My flight leaves NYC on Jan 2, 2017 at 03:04:05 +// absl::CivilSecond cs(2017, 1, 2, 3, 4, 5); +// absl::Time takeoff = absl::FromCivil(cs, nyc); +// +// absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35); +// absl::Time landing = takeoff + flight_duration; +// +// absl::TimeZone syd; +// if (!absl::LoadTimeZone("Australia/Sydney", &syd)) { +// // handle error case +// } +// std::string s = absl::FormatTime( +// "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S", +// landing, syd); + +#ifndef ABSL_TIME_TIME_H_ +#define ABSL_TIME_TIME_H_ + +#if !defined(_MSC_VER) +#include <sys/time.h> +#else +// We don't include `winsock2.h` because it drags in `windows.h` and friends, +// and they define conflicting macros like OPAQUE, ERROR, and more. This has the +// potential to break Abseil users. +// +// Instead we only forward declare `timeval` and require Windows users include +// `winsock2.h` themselves. This is both inconsistent and troublesome, but so is +// including 'windows.h' so we are picking the lesser of two evils here. +struct timeval; +#endif +#include <chrono> // NOLINT(build/c++11) +#include <cmath> +#include <cstdint> +#include <ctime> +#include <ostream> +#include <string> +#include <type_traits> +#include <utility> + +#include "absl/base/macros.h" +#include "absl/strings/string_view.h" +#include "absl/time/civil_time.h" +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +class Duration; // Defined below +class Time; // Defined below +class TimeZone; // Defined below + +namespace time_internal { +int64_t IDivDuration(bool satq, Duration num, Duration den, Duration* rem); +constexpr Time FromUnixDuration(Duration d); +constexpr Duration ToUnixDuration(Time t); +constexpr int64_t GetRepHi(Duration d); +constexpr uint32_t GetRepLo(Duration d); +constexpr Duration MakeDuration(int64_t hi, uint32_t lo); +constexpr Duration MakeDuration(int64_t hi, int64_t lo); +inline Duration MakePosDoubleDuration(double n); +constexpr int64_t kTicksPerNanosecond = 4; +constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond; +template <std::intmax_t N> +constexpr Duration FromInt64(int64_t v, std::ratio<1, N>); +constexpr Duration FromInt64(int64_t v, std::ratio<60>); +constexpr Duration FromInt64(int64_t v, std::ratio<3600>); +template <typename T> +using EnableIfIntegral = typename std::enable_if< + std::is_integral<T>::value || std::is_enum<T>::value, int>::type; +template <typename T> +using EnableIfFloat = + typename std::enable_if<std::is_floating_point<T>::value, int>::type; +} // namespace time_internal + +// Duration +// +// The `absl::Duration` class represents a signed, fixed-length span of time. +// A `Duration` is generated using a unit-specific factory function, or is +// the result of subtracting one `absl::Time` from another. Durations behave +// like unit-safe integers and they support all the natural integer-like +// arithmetic operations. Arithmetic overflows and saturates at +/- infinity. +// `Duration` should be passed by value rather than const reference. +// +// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`, +// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for +// creation of constexpr `Duration` values +// +// Examples: +// +// constexpr absl::Duration ten_ns = absl::Nanoseconds(10); +// constexpr absl::Duration min = absl::Minutes(1); +// constexpr absl::Duration hour = absl::Hours(1); +// absl::Duration dur = 60 * min; // dur == hour +// absl::Duration half_sec = absl::Milliseconds(500); +// absl::Duration quarter_sec = 0.25 * absl::Seconds(1); +// +// `Duration` values can be easily converted to an integral number of units +// using the division operator. +// +// Example: +// +// constexpr absl::Duration dur = absl::Milliseconds(1500); +// int64_t ns = dur / absl::Nanoseconds(1); // ns == 1500000000 +// int64_t ms = dur / absl::Milliseconds(1); // ms == 1500 +// int64_t sec = dur / absl::Seconds(1); // sec == 1 (subseconds truncated) +// int64_t min = dur / absl::Minutes(1); // min == 0 +// +// See the `IDivDuration()` and `FDivDuration()` functions below for details on +// how to access the fractional parts of the quotient. +// +// Alternatively, conversions can be performed using helpers such as +// `ToInt64Microseconds()` and `ToDoubleSeconds()`. +class Duration { + public: + // Value semantics. + constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration + + // Copyable. +#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1910 + // Explicitly defining the constexpr copy constructor avoids an MSVC bug. + constexpr Duration(const Duration& d) + : rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {} +#else + constexpr Duration(const Duration& d) = default; +#endif + Duration& operator=(const Duration& d) = default; + + // Compound assignment operators. + Duration& operator+=(Duration d); + Duration& operator-=(Duration d); + Duration& operator*=(int64_t r); + Duration& operator*=(double r); + Duration& operator/=(int64_t r); + Duration& operator/=(double r); + Duration& operator%=(Duration rhs); + + // Overloads that forward to either the int64_t or double overloads above. + // Integer operands must be representable as int64_t. + template <typename T> + Duration& operator*=(T r) { + int64_t x = r; + return *this *= x; + } + template <typename T> + Duration& operator/=(T r) { + int64_t x = r; + return *this /= x; + } + Duration& operator*=(float r) { return *this *= static_cast<double>(r); } + Duration& operator/=(float r) { return *this /= static_cast<double>(r); } + + template <typename H> + friend H AbslHashValue(H h, Duration d) { + return H::combine(std::move(h), d.rep_hi_, d.rep_lo_); + } + + private: + friend constexpr int64_t time_internal::GetRepHi(Duration d); + friend constexpr uint32_t time_internal::GetRepLo(Duration d); + friend constexpr Duration time_internal::MakeDuration(int64_t hi, + uint32_t lo); + constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {} + int64_t rep_hi_; + uint32_t rep_lo_; +}; + +// Relational Operators +constexpr bool operator<(Duration lhs, Duration rhs); +constexpr bool operator>(Duration lhs, Duration rhs) { return rhs < lhs; } +constexpr bool operator>=(Duration lhs, Duration rhs) { return !(lhs < rhs); } +constexpr bool operator<=(Duration lhs, Duration rhs) { return !(rhs < lhs); } +constexpr bool operator==(Duration lhs, Duration rhs); +constexpr bool operator!=(Duration lhs, Duration rhs) { return !(lhs == rhs); } + +// Additive Operators +constexpr Duration operator-(Duration d); +inline Duration operator+(Duration lhs, Duration rhs) { return lhs += rhs; } +inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; } + +// Multiplicative Operators +// Integer operands must be representable as int64_t. +template <typename T> +Duration operator*(Duration lhs, T rhs) { + return lhs *= rhs; +} +template <typename T> +Duration operator*(T lhs, Duration rhs) { + return rhs *= lhs; +} +template <typename T> +Duration operator/(Duration lhs, T rhs) { + return lhs /= rhs; +} +inline int64_t operator/(Duration lhs, Duration rhs) { + return time_internal::IDivDuration(true, lhs, rhs, + &lhs); // trunc towards zero +} +inline Duration operator%(Duration lhs, Duration rhs) { return lhs %= rhs; } + +// IDivDuration() +// +// Divides a numerator `Duration` by a denominator `Duration`, returning the +// quotient and remainder. The remainder always has the same sign as the +// numerator. The returned quotient and remainder respect the identity: +// +// numerator = denominator * quotient + remainder +// +// Returned quotients are capped to the range of `int64_t`, with the difference +// spilling into the remainder to uphold the above identity. This means that the +// remainder returned could differ from the remainder returned by +// `Duration::operator%` for huge quotients. +// +// See also the notes on `InfiniteDuration()` below regarding the behavior of +// division involving zero and infinite durations. +// +// Example: +// +// constexpr absl::Duration a = +// absl::Seconds(std::numeric_limits<int64_t>::max()); // big +// constexpr absl::Duration b = absl::Nanoseconds(1); // small +// +// absl::Duration rem = a % b; +// // rem == absl::ZeroDuration() +// +// // Here, q would overflow int64_t, so rem accounts for the difference. +// int64_t q = absl::IDivDuration(a, b, &rem); +// // q == std::numeric_limits<int64_t>::max(), rem == a - b * q +inline int64_t IDivDuration(Duration num, Duration den, Duration* rem) { + return time_internal::IDivDuration(true, num, den, + rem); // trunc towards zero +} + +// FDivDuration() +// +// Divides a `Duration` numerator into a fractional number of units of a +// `Duration` denominator. +// +// See also the notes on `InfiniteDuration()` below regarding the behavior of +// division involving zero and infinite durations. +// +// Example: +// +// double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1)); +// // d == 1.5 +double FDivDuration(Duration num, Duration den); + +// ZeroDuration() +// +// Returns a zero-length duration. This function behaves just like the default +// constructor, but the name helps make the semantics clear at call sites. +constexpr Duration ZeroDuration() { return Duration(); } + +// AbsDuration() +// +// Returns the absolute value of a duration. +inline Duration AbsDuration(Duration d) { + return (d < ZeroDuration()) ? -d : d; +} + +// Trunc() +// +// Truncates a duration (toward zero) to a multiple of a non-zero unit. +// +// Example: +// +// absl::Duration d = absl::Nanoseconds(123456789); +// absl::Duration a = absl::Trunc(d, absl::Microseconds(1)); // 123456us +Duration Trunc(Duration d, Duration unit); + +// Floor() +// +// Floors a duration using the passed duration unit to its largest value not +// greater than the duration. +// +// Example: +// +// absl::Duration d = absl::Nanoseconds(123456789); +// absl::Duration b = absl::Floor(d, absl::Microseconds(1)); // 123456us +Duration Floor(Duration d, Duration unit); + +// Ceil() +// +// Returns the ceiling of a duration using the passed duration unit to its +// smallest value not less than the duration. +// +// Example: +// +// absl::Duration d = absl::Nanoseconds(123456789); +// absl::Duration c = absl::Ceil(d, absl::Microseconds(1)); // 123457us +Duration Ceil(Duration d, Duration unit); + +// InfiniteDuration() +// +// Returns an infinite `Duration`. To get a `Duration` representing negative +// infinity, use `-InfiniteDuration()`. +// +// Duration arithmetic overflows to +/- infinity and saturates. In general, +// arithmetic with `Duration` infinities is similar to IEEE 754 infinities +// except where IEEE 754 NaN would be involved, in which case +/- +// `InfiniteDuration()` is used in place of a "nan" Duration. +// +// Examples: +// +// constexpr absl::Duration inf = absl::InfiniteDuration(); +// const absl::Duration d = ... any finite duration ... +// +// inf == inf + inf +// inf == inf + d +// inf == inf - inf +// -inf == d - inf +// +// inf == d * 1e100 +// inf == inf / 2 +// 0 == d / inf +// INT64_MAX == inf / d +// +// d < inf +// -inf < d +// +// // Division by zero returns infinity, or INT64_MIN/MAX where appropriate. +// inf == d / 0 +// INT64_MAX == d / absl::ZeroDuration() +// +// The examples involving the `/` operator above also apply to `IDivDuration()` +// and `FDivDuration()`. +constexpr Duration InfiniteDuration(); + +// Nanoseconds() +// Microseconds() +// Milliseconds() +// Seconds() +// Minutes() +// Hours() +// +// Factory functions for constructing `Duration` values from an integral number +// of the unit indicated by the factory function's name. The number must be +// representable as int64_t. +// +// NOTE: no "Days()" factory function exists because "a day" is ambiguous. +// Civil days are not always 24 hours long, and a 24-hour duration often does +// not correspond with a civil day. If a 24-hour duration is needed, use +// `absl::Hours(24)`. If you actually want a civil day, use absl::CivilDay +// from civil_time.h. +// +// Example: +// +// absl::Duration a = absl::Seconds(60); +// absl::Duration b = absl::Minutes(1); // b == a +constexpr Duration Nanoseconds(int64_t n); +constexpr Duration Microseconds(int64_t n); +constexpr Duration Milliseconds(int64_t n); +constexpr Duration Seconds(int64_t n); +constexpr Duration Minutes(int64_t n); +constexpr Duration Hours(int64_t n); + +// Factory overloads for constructing `Duration` values from a floating-point +// number of the unit indicated by the factory function's name. These functions +// exist for convenience, but they are not as efficient as the integral +// factories, which should be preferred. +// +// Example: +// +// auto a = absl::Seconds(1.5); // OK +// auto b = absl::Milliseconds(1500); // BETTER +template <typename T, time_internal::EnableIfFloat<T> = 0> +Duration Nanoseconds(T n) { + return n * Nanoseconds(1); +} +template <typename T, time_internal::EnableIfFloat<T> = 0> +Duration Microseconds(T n) { + return n * Microseconds(1); +} +template <typename T, time_internal::EnableIfFloat<T> = 0> +Duration Milliseconds(T n) { + return n * Milliseconds(1); +} +template <typename T, time_internal::EnableIfFloat<T> = 0> +Duration Seconds(T n) { + if (n >= 0) { // Note: `NaN >= 0` is false. + if (n >= static_cast<T>((std::numeric_limits<int64_t>::max)())) { + return InfiniteDuration(); + } + return time_internal::MakePosDoubleDuration(n); + } else { + if (std::isnan(n)) + return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration(); + if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration(); + return -time_internal::MakePosDoubleDuration(-n); + } +} +template <typename T, time_internal::EnableIfFloat<T> = 0> +Duration Minutes(T n) { + return n * Minutes(1); +} +template <typename T, time_internal::EnableIfFloat<T> = 0> +Duration Hours(T n) { + return n * Hours(1); +} + +// ToInt64Nanoseconds() +// ToInt64Microseconds() +// ToInt64Milliseconds() +// ToInt64Seconds() +// ToInt64Minutes() +// ToInt64Hours() +// +// Helper functions that convert a Duration to an integral count of the +// indicated unit. These functions are shorthand for the `IDivDuration()` +// function above; see its documentation for details about overflow, etc. +// +// Example: +// +// absl::Duration d = absl::Milliseconds(1500); +// int64_t isec = absl::ToInt64Seconds(d); // isec == 1 +int64_t ToInt64Nanoseconds(Duration d); +int64_t ToInt64Microseconds(Duration d); +int64_t ToInt64Milliseconds(Duration d); +int64_t ToInt64Seconds(Duration d); +int64_t ToInt64Minutes(Duration d); +int64_t ToInt64Hours(Duration d); + +// ToDoubleNanoSeconds() +// ToDoubleMicroseconds() +// ToDoubleMilliseconds() +// ToDoubleSeconds() +// ToDoubleMinutes() +// ToDoubleHours() +// +// Helper functions that convert a Duration to a floating point count of the +// indicated unit. These functions are shorthand for the `FDivDuration()` +// function above; see its documentation for details about overflow, etc. +// +// Example: +// +// absl::Duration d = absl::Milliseconds(1500); +// double dsec = absl::ToDoubleSeconds(d); // dsec == 1.5 +double ToDoubleNanoseconds(Duration d); +double ToDoubleMicroseconds(Duration d); +double ToDoubleMilliseconds(Duration d); +double ToDoubleSeconds(Duration d); +double ToDoubleMinutes(Duration d); +double ToDoubleHours(Duration d); + +// FromChrono() +// +// Converts any of the pre-defined std::chrono durations to an absl::Duration. +// +// Example: +// +// std::chrono::milliseconds ms(123); +// absl::Duration d = absl::FromChrono(ms); +constexpr Duration FromChrono(const std::chrono::nanoseconds& d); +constexpr Duration FromChrono(const std::chrono::microseconds& d); +constexpr Duration FromChrono(const std::chrono::milliseconds& d); +constexpr Duration FromChrono(const std::chrono::seconds& d); +constexpr Duration FromChrono(const std::chrono::minutes& d); +constexpr Duration FromChrono(const std::chrono::hours& d); + +// ToChronoNanoseconds() +// ToChronoMicroseconds() +// ToChronoMilliseconds() +// ToChronoSeconds() +// ToChronoMinutes() +// ToChronoHours() +// +// Converts an absl::Duration to any of the pre-defined std::chrono durations. +// If overflow would occur, the returned value will saturate at the min/max +// chrono duration value instead. +// +// Example: +// +// absl::Duration d = absl::Microseconds(123); +// auto x = absl::ToChronoMicroseconds(d); +// auto y = absl::ToChronoNanoseconds(d); // x == y +// auto z = absl::ToChronoSeconds(absl::InfiniteDuration()); +// // z == std::chrono::seconds::max() +std::chrono::nanoseconds ToChronoNanoseconds(Duration d); +std::chrono::microseconds ToChronoMicroseconds(Duration d); +std::chrono::milliseconds ToChronoMilliseconds(Duration d); +std::chrono::seconds ToChronoSeconds(Duration d); +std::chrono::minutes ToChronoMinutes(Duration d); +std::chrono::hours ToChronoHours(Duration d); + +// FormatDuration() +// +// Returns a string representing the duration in the form "72h3m0.5s". +// Returns "inf" or "-inf" for +/- `InfiniteDuration()`. +std::string FormatDuration(Duration d); + +// Output stream operator. +inline std::ostream& operator<<(std::ostream& os, Duration d) { + return os << FormatDuration(d); +} + +// ParseDuration() +// +// Parses a duration string consisting of a possibly signed sequence of +// decimal numbers, each with an optional fractional part and a unit +// suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h". +// Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as +// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`. +bool ParseDuration(absl::string_view dur_string, Duration* d); + +// Support for flag values of type Duration. Duration flags must be specified +// in a format that is valid input for absl::ParseDuration(). +bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error); +std::string AbslUnparseFlag(Duration d); +ABSL_DEPRECATED("Use AbslParseFlag() instead.") +bool ParseFlag(const std::string& text, Duration* dst, std::string* error); +ABSL_DEPRECATED("Use AbslUnparseFlag() instead.") +std::string UnparseFlag(Duration d); + +// Time +// +// An `absl::Time` represents a specific instant in time. Arithmetic operators +// are provided for naturally expressing time calculations. Instances are +// created using `absl::Now()` and the `absl::From*()` factory functions that +// accept the gamut of other time representations. Formatting and parsing +// functions are provided for conversion to and from strings. `absl::Time` +// should be passed by value rather than const reference. +// +// `absl::Time` assumes there are 60 seconds in a minute, which means the +// underlying time scales must be "smeared" to eliminate leap seconds. +// See https://developers.google.com/time/smear. +// +// Even though `absl::Time` supports a wide range of timestamps, exercise +// caution when using values in the distant past. `absl::Time` uses the +// Proleptic Gregorian calendar, which extends the Gregorian calendar backward +// to dates before its introduction in 1582. +// See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar +// for more information. Use the ICU calendar classes to convert a date in +// some other calendar (http://userguide.icu-project.org/datetime/calendar). +// +// Similarly, standardized time zones are a reasonably recent innovation, with +// the Greenwich prime meridian being established in 1884. The TZ database +// itself does not profess accurate offsets for timestamps prior to 1970. The +// breakdown of future timestamps is subject to the whim of regional +// governments. +// +// The `absl::Time` class represents an instant in time as a count of clock +// ticks of some granularity (resolution) from some starting point (epoch). +// +// `absl::Time` uses a resolution that is high enough to avoid loss in +// precision, and a range that is wide enough to avoid overflow, when +// converting between tick counts in most Google time scales (i.e., resolution +// of at least one nanosecond, and range +/-100 billion years). Conversions +// between the time scales are performed by truncating (towards negative +// infinity) to the nearest representable point. +// +// Examples: +// +// absl::Time t1 = ...; +// absl::Time t2 = t1 + absl::Minutes(2); +// absl::Duration d = t2 - t1; // == absl::Minutes(2) +// +class Time { + public: + // Value semantics. + + // Returns the Unix epoch. However, those reading your code may not know + // or expect the Unix epoch as the default value, so make your code more + // readable by explicitly initializing all instances before use. + // + // Example: + // absl::Time t = absl::UnixEpoch(); + // absl::Time t = absl::Now(); + // absl::Time t = absl::TimeFromTimeval(tv); + // absl::Time t = absl::InfinitePast(); + constexpr Time() = default; + + // Copyable. + constexpr Time(const Time& t) = default; + Time& operator=(const Time& t) = default; + + // Assignment operators. + Time& operator+=(Duration d) { + rep_ += d; + return *this; + } + Time& operator-=(Duration d) { + rep_ -= d; + return *this; + } + + // Time::Breakdown + // + // The calendar and wall-clock (aka "civil time") components of an + // `absl::Time` in a certain `absl::TimeZone`. This struct is not + // intended to represent an instant in time. So, rather than passing + // a `Time::Breakdown` to a function, pass an `absl::Time` and an + // `absl::TimeZone`. + // + // Deprecated. Use `absl::TimeZone::CivilInfo`. + struct + Breakdown { + int64_t year; // year (e.g., 2013) + int month; // month of year [1:12] + int day; // day of month [1:31] + int hour; // hour of day [0:23] + int minute; // minute of hour [0:59] + int second; // second of minute [0:59] + Duration subsecond; // [Seconds(0):Seconds(1)) if finite + int weekday; // 1==Mon, ..., 7=Sun + int yearday; // day of year [1:366] + + // Note: The following fields exist for backward compatibility + // with older APIs. Accessing these fields directly is a sign of + // imprudent logic in the calling code. Modern time-related code + // should only access this data indirectly by way of FormatTime(). + // These fields are undefined for InfiniteFuture() and InfinitePast(). + int offset; // seconds east of UTC + bool is_dst; // is offset non-standard? + const char* zone_abbr; // time-zone abbreviation (e.g., "PST") + }; + + // Time::In() + // + // Returns the breakdown of this instant in the given TimeZone. + // + // Deprecated. Use `absl::TimeZone::At(Time)`. + Breakdown In(TimeZone tz) const; + + template <typename H> + friend H AbslHashValue(H h, Time t) { + return H::combine(std::move(h), t.rep_); + } + + private: + friend constexpr Time time_internal::FromUnixDuration(Duration d); + friend constexpr Duration time_internal::ToUnixDuration(Time t); + friend constexpr bool operator<(Time lhs, Time rhs); + friend constexpr bool operator==(Time lhs, Time rhs); + friend Duration operator-(Time lhs, Time rhs); + friend constexpr Time UniversalEpoch(); + friend constexpr Time InfiniteFuture(); + friend constexpr Time InfinitePast(); + constexpr explicit Time(Duration rep) : rep_(rep) {} + Duration rep_; +}; + +// Relational Operators +constexpr bool operator<(Time lhs, Time rhs) { return lhs.rep_ < rhs.rep_; } +constexpr bool operator>(Time lhs, Time rhs) { return rhs < lhs; } +constexpr bool operator>=(Time lhs, Time rhs) { return !(lhs < rhs); } +constexpr bool operator<=(Time lhs, Time rhs) { return !(rhs < lhs); } +constexpr bool operator==(Time lhs, Time rhs) { return lhs.rep_ == rhs.rep_; } +constexpr bool operator!=(Time lhs, Time rhs) { return !(lhs == rhs); } + +// Additive Operators +inline Time operator+(Time lhs, Duration rhs) { return lhs += rhs; } +inline Time operator+(Duration lhs, Time rhs) { return rhs += lhs; } +inline Time operator-(Time lhs, Duration rhs) { return lhs -= rhs; } +inline Duration operator-(Time lhs, Time rhs) { return lhs.rep_ - rhs.rep_; } + +// UnixEpoch() +// +// Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000". +constexpr Time UnixEpoch() { return Time(); } + +// UniversalEpoch() +// +// Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the +// epoch of the ICU Universal Time Scale. +constexpr Time UniversalEpoch() { + // 719162 is the number of days from 0001-01-01 to 1970-01-01, + // assuming the Gregorian calendar. + return Time(time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, 0U)); +} + +// InfiniteFuture() +// +// Returns an `absl::Time` that is infinitely far in the future. +constexpr Time InfiniteFuture() { + return Time( + time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U)); +} + +// InfinitePast() +// +// Returns an `absl::Time` that is infinitely far in the past. +constexpr Time InfinitePast() { + return Time( + time_internal::MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U)); +} + +// FromUnixNanos() +// FromUnixMicros() +// FromUnixMillis() +// FromUnixSeconds() +// FromTimeT() +// FromUDate() +// FromUniversal() +// +// Creates an `absl::Time` from a variety of other representations. +constexpr Time FromUnixNanos(int64_t ns); +constexpr Time FromUnixMicros(int64_t us); +constexpr Time FromUnixMillis(int64_t ms); +constexpr Time FromUnixSeconds(int64_t s); +constexpr Time FromTimeT(time_t t); +Time FromUDate(double udate); +Time FromUniversal(int64_t universal); + +// ToUnixNanos() +// ToUnixMicros() +// ToUnixMillis() +// ToUnixSeconds() +// ToTimeT() +// ToUDate() +// ToUniversal() +// +// Converts an `absl::Time` to a variety of other representations. Note that +// these operations round down toward negative infinity where necessary to +// adjust to the resolution of the result type. Beware of possible time_t +// over/underflow in ToTime{T,val,spec}() on 32-bit platforms. +int64_t ToUnixNanos(Time t); +int64_t ToUnixMicros(Time t); +int64_t ToUnixMillis(Time t); +int64_t ToUnixSeconds(Time t); +time_t ToTimeT(Time t); +double ToUDate(Time t); +int64_t ToUniversal(Time t); + +// DurationFromTimespec() +// DurationFromTimeval() +// ToTimespec() +// ToTimeval() +// TimeFromTimespec() +// TimeFromTimeval() +// ToTimespec() +// ToTimeval() +// +// Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2) +// and select(2)), while others use them as a Time (e.g. clock_gettime(2) +// and gettimeofday(2)), so conversion functions are provided for both cases. +// The "to timespec/val" direction is easily handled via overloading, but +// for "from timespec/val" the desired type is part of the function name. +Duration DurationFromTimespec(timespec ts); +Duration DurationFromTimeval(timeval tv); +timespec ToTimespec(Duration d); +timeval ToTimeval(Duration d); +Time TimeFromTimespec(timespec ts); +Time TimeFromTimeval(timeval tv); +timespec ToTimespec(Time t); +timeval ToTimeval(Time t); + +// FromChrono() +// +// Converts a std::chrono::system_clock::time_point to an absl::Time. +// +// Example: +// +// auto tp = std::chrono::system_clock::from_time_t(123); +// absl::Time t = absl::FromChrono(tp); +// // t == absl::FromTimeT(123) +Time FromChrono(const std::chrono::system_clock::time_point& tp); + +// ToChronoTime() +// +// Converts an absl::Time to a std::chrono::system_clock::time_point. If +// overflow would occur, the returned value will saturate at the min/max time +// point value instead. +// +// Example: +// +// absl::Time t = absl::FromTimeT(123); +// auto tp = absl::ToChronoTime(t); +// // tp == std::chrono::system_clock::from_time_t(123); +std::chrono::system_clock::time_point ToChronoTime(Time); + +// Support for flag values of type Time. Time flags must be specified in a +// format that matches absl::RFC3339_full. For example: +// +// --start_time=2016-01-02T03:04:05.678+08:00 +// +// Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required. +// +// Additionally, if you'd like to specify a time as a count of +// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag +// and add that duration to absl::UnixEpoch() to get an absl::Time. +bool AbslParseFlag(absl::string_view text, Time* t, std::string* error); +std::string AbslUnparseFlag(Time t); +ABSL_DEPRECATED("Use AbslParseFlag() instead.") +bool ParseFlag(const std::string& text, Time* t, std::string* error); +ABSL_DEPRECATED("Use AbslUnparseFlag() instead.") +std::string UnparseFlag(Time t); + +// TimeZone +// +// The `absl::TimeZone` is an opaque, small, value-type class representing a +// geo-political region within which particular rules are used for converting +// between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone` +// values are named using the TZ identifiers from the IANA Time Zone Database, +// such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values +// are created from factory functions such as `absl::LoadTimeZone()`. Note: +// strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by +// value rather than const reference. +// +// For more on the fundamental concepts of time zones, absolute times, and civil +// times, see https://github.com/google/cctz#fundamental-concepts +// +// Examples: +// +// absl::TimeZone utc = absl::UTCTimeZone(); +// absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60); +// absl::TimeZone loc = absl::LocalTimeZone(); +// absl::TimeZone lax; +// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) { +// // handle error case +// } +// +// See also: +// - https://github.com/google/cctz +// - https://www.iana.org/time-zones +// - https://en.wikipedia.org/wiki/Zoneinfo +class TimeZone { + public: + explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {} + TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit. + + // Copyable. + TimeZone(const TimeZone&) = default; + TimeZone& operator=(const TimeZone&) = default; + + explicit operator time_internal::cctz::time_zone() const { return cz_; } + + std::string name() const { return cz_.name(); } + + // TimeZone::CivilInfo + // + // Information about the civil time corresponding to an absolute time. + // This struct is not intended to represent an instant in time. So, rather + // than passing a `TimeZone::CivilInfo` to a function, pass an `absl::Time` + // and an `absl::TimeZone`. + struct CivilInfo { + CivilSecond cs; + Duration subsecond; + + // Note: The following fields exist for backward compatibility + // with older APIs. Accessing these fields directly is a sign of + // imprudent logic in the calling code. Modern time-related code + // should only access this data indirectly by way of FormatTime(). + // These fields are undefined for InfiniteFuture() and InfinitePast(). + int offset; // seconds east of UTC + bool is_dst; // is offset non-standard? + const char* zone_abbr; // time-zone abbreviation (e.g., "PST") + }; + + // TimeZone::At(Time) + // + // Returns the civil time for this TimeZone at a certain `absl::Time`. + // If the input time is infinite, the output civil second will be set to + // CivilSecond::max() or min(), and the subsecond will be infinite. + // + // Example: + // + // const auto epoch = lax.At(absl::UnixEpoch()); + // // epoch.cs == 1969-12-31 16:00:00 + // // epoch.subsecond == absl::ZeroDuration() + // // epoch.offset == -28800 + // // epoch.is_dst == false + // // epoch.abbr == "PST" + CivilInfo At(Time t) const; + + // TimeZone::TimeInfo + // + // Information about the absolute times corresponding to a civil time. + // (Subseconds must be handled separately.) + // + // It is possible for a caller to pass a civil-time value that does + // not represent an actual or unique instant in time (due to a shift + // in UTC offset in the TimeZone, which results in a discontinuity in + // the civil-time components). For example, a daylight-saving-time + // transition skips or repeats civil times---in the United States, + // March 13, 2011 02:15 never occurred, while November 6, 2011 01:15 + // occurred twice---so requests for such times are not well-defined. + // To account for these possibilities, `absl::TimeZone::TimeInfo` is + // richer than just a single `absl::Time`. + struct TimeInfo { + enum CivilKind { + UNIQUE, // the civil time was singular (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 + Time trans; // when the civil-time discontinuity occurred + Time post; // time calculated using the post-transition offset + }; + + // TimeZone::At(CivilSecond) + // + // Returns an `absl::TimeInfo` containing the absolute time(s) for this + // TimeZone at an `absl::CivilSecond`. When the civil time is skipped or + // repeated, returns times calculated using the pre-transition and post- + // transition UTC offsets, plus the transition time itself. + // + // Examples: + // + // // A unique civil time + // const auto jan01 = lax.At(absl::CivilSecond(2011, 1, 1, 0, 0, 0)); + // // jan01.kind == TimeZone::TimeInfo::UNIQUE + // // jan01.pre is 2011-01-01 00:00:00 -0800 + // // jan01.trans is 2011-01-01 00:00:00 -0800 + // // jan01.post is 2011-01-01 00:00:00 -0800 + // + // // A Spring DST transition, when there is a gap in civil time + // const auto mar13 = lax.At(absl::CivilSecond(2011, 3, 13, 2, 15, 0)); + // // mar13.kind == TimeZone::TimeInfo::SKIPPED + // // mar13.pre is 2011-03-13 03:15:00 -0700 + // // mar13.trans is 2011-03-13 03:00:00 -0700 + // // mar13.post is 2011-03-13 01:15:00 -0800 + // + // // A Fall DST transition, when civil times are repeated + // const auto nov06 = lax.At(absl::CivilSecond(2011, 11, 6, 1, 15, 0)); + // // nov06.kind == TimeZone::TimeInfo::REPEATED + // // nov06.pre is 2011-11-06 01:15:00 -0700 + // // nov06.trans is 2011-11-06 01:00:00 -0800 + // // 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_); + } + + private: + friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; } + friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; } + friend std::ostream& operator<<(std::ostream& os, TimeZone tz) { + return os << tz.name(); + } + + time_internal::cctz::time_zone cz_; +}; + +// LoadTimeZone() +// +// Loads the named zone. May perform I/O on the initial load of the named +// zone. If the name is invalid, or some other kind of error occurs, returns +// `false` and `*tz` is set to the UTC time zone. +inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) { + if (name == "localtime") { + *tz = TimeZone(time_internal::cctz::local_time_zone()); + return true; + } + time_internal::cctz::time_zone cz; + const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz); + *tz = TimeZone(cz); + return b; +} + +// FixedTimeZone() +// +// Returns a TimeZone that is a fixed offset (seconds east) from UTC. +// Note: If the absolute value of the offset is greater than 24 hours +// you'll get UTC (i.e., no offset) instead. +inline TimeZone FixedTimeZone(int seconds) { + return TimeZone( + time_internal::cctz::fixed_time_zone(std::chrono::seconds(seconds))); +} + +// UTCTimeZone() +// +// Convenience method returning the UTC time zone. +inline TimeZone UTCTimeZone() { + return TimeZone(time_internal::cctz::utc_time_zone()); +} + +// LocalTimeZone() +// +// Convenience method returning the local time zone, or UTC if there is +// no configured local zone. Warning: Be wary of using LocalTimeZone(), +// and particularly so in a server process, as the zone configured for the +// local machine should be irrelevant. Prefer an explicit zone name. +inline TimeZone LocalTimeZone() { + return TimeZone(time_internal::cctz::local_time_zone()); +} + +// ToCivilSecond() +// ToCivilMinute() +// ToCivilHour() +// ToCivilDay() +// ToCivilMonth() +// ToCivilYear() +// +// Helpers for TimeZone::At(Time) to return particularly aligned civil times. +// +// Example: +// +// absl::Time t = ...; +// absl::TimeZone tz = ...; +// const auto cd = absl::ToCivilDay(t, tz); +inline CivilSecond ToCivilSecond(Time t, TimeZone tz) { + return tz.At(t).cs; // already a CivilSecond +} +inline CivilMinute ToCivilMinute(Time t, TimeZone tz) { + return CivilMinute(tz.At(t).cs); +} +inline CivilHour ToCivilHour(Time t, TimeZone tz) { + return CivilHour(tz.At(t).cs); +} +inline CivilDay ToCivilDay(Time t, TimeZone tz) { + return CivilDay(tz.At(t).cs); +} +inline CivilMonth ToCivilMonth(Time t, TimeZone tz) { + return CivilMonth(tz.At(t).cs); +} +inline CivilYear ToCivilYear(Time t, TimeZone tz) { + return CivilYear(tz.At(t).cs); +} + +// FromCivil() +// +// Helper for TimeZone::At(CivilSecond) that provides "order-preserving +// semantics." If the civil time maps to a unique time, that time is +// returned. If the civil time is repeated in the given time zone, the +// time using the pre-transition offset is returned. Otherwise, the +// civil time is skipped in the given time zone, and the transition time +// is returned. This means that for any two civil times, ct1 and ct2, +// (ct1 < ct2) => (FromCivil(ct1) <= FromCivil(ct2)), the equal case +// being when two non-existent civil times map to the same transition time. +// +// Note: Accepts civil times of any alignment. +inline Time FromCivil(CivilSecond ct, TimeZone tz) { + const auto ti = tz.At(ct); + if (ti.kind == TimeZone::TimeInfo::SKIPPED) return ti.trans; + return ti.pre; +} + +// TimeConversion +// +// An `absl::TimeConversion` represents the conversion of year, month, day, +// hour, minute, and second values (i.e., a civil time), in a particular +// `absl::TimeZone`, to a time instant (an absolute time), as returned by +// `absl::ConvertDateTime()`. Legacy version of `absl::TimeZone::TimeInfo`. +// +// Deprecated. Use `absl::TimeZone::TimeInfo`. +struct + TimeConversion { + Time pre; // time calculated using the pre-transition offset + Time trans; // when the civil-time discontinuity occurred + Time post; // time calculated using the post-transition offset + + enum Kind { + UNIQUE, // the civil time was singular (pre == trans == post) + SKIPPED, // the civil time did not exist + REPEATED, // the civil time was ambiguous + }; + Kind kind; + + bool normalized; // input values were outside their valid ranges +}; + +// ConvertDateTime() +// +// Legacy version of `absl::TimeZone::At(absl::CivilSecond)` that takes +// the civil time as six, separate values (YMDHMS). +// +// The input month, day, hour, minute, and second values can be outside +// of their valid ranges, in which case they will be "normalized" during +// the conversion. +// +// Example: +// +// // "October 32" normalizes to "November 1". +// absl::TimeConversion tc = +// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, lax); +// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true +// // absl::ToCivilDay(tc.pre, tz).month() == 11 +// // absl::ToCivilDay(tc.pre, tz).day() == 1 +// +// Deprecated. Use `absl::TimeZone::At(CivilSecond)`. +TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, + int min, int sec, TimeZone tz); + +// FromDateTime() +// +// A convenience wrapper for `absl::ConvertDateTime()` that simply returns +// the "pre" `absl::Time`. That is, the unique result, or the instant that +// is correct using the pre-transition offset (as if the transition never +// happened). +// +// Example: +// +// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax); +// // t = 2017-09-26 09:30:00 -0700 +// +// Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the +// behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil +// times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`. +inline Time FromDateTime(int64_t year, int mon, int day, int hour, + int min, int sec, TimeZone tz) { + return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre; +} + +// FromTM() +// +// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and +// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3) +// for a description of the expected values of the tm fields. If the indicated +// time instant is not unique (see `absl::TimeZone::At(absl::CivilSecond)` +// above), the `tm_isdst` field is consulted to select the desired instant +// (`tm_isdst` > 0 means DST, `tm_isdst` == 0 means no DST, `tm_isdst` < 0 +// means use the post-transition offset). +Time FromTM(const struct tm& tm, TimeZone tz); + +// ToTM() +// +// Converts the given `absl::Time` to a struct tm using the given time zone. +// See ctime(3) for a description of the values of the tm fields. +struct tm ToTM(Time t, TimeZone tz); + +// RFC3339_full +// RFC3339_sec +// +// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings, +// with trailing zeros trimmed or with fractional seconds omitted altogether. +// +// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and +// time with UTC offset. Also note the use of "%Y": RFC3339 mandates that +// years have exactly four digits, but we allow them to take their natural +// width. +ABSL_DLL extern const char RFC3339_full[]; // %Y-%m-%d%ET%H:%M:%E*S%Ez +ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%d%ET%H:%M:%S%Ez + +// RFC1123_full +// RFC1123_no_wday +// +// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings. +ABSL_DLL extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z +ABSL_DLL extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z + +// FormatTime() +// +// Formats the given `absl::Time` in the `absl::TimeZone` according to the +// provided format string. Uses strftime()-like formatting options, with +// the following extensions: +// +// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) +// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) +// - %E#S - Seconds with # digits of fractional precision +// - %E*S - Seconds with full fractional precision (a literal '*') +// - %E#f - Fractional seconds with # digits of precision +// - %E*f - Fractional seconds with full precision (a literal '*') +// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) +// - %ET - The RFC3339 "date-time" separator "T" +// +// Note that %E0S behaves like %S, and %E0f produces no characters. In +// contrast %E*f always produces at least one digit, which may be '0'. +// +// Note that %Y produces as many characters as it takes to fully render the +// year. A year outside of [-999:9999] when formatted with %E4Y will produce +// more than four characters, just like %Y. +// +// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z) +// so that the result uniquely identifies a time instant. +// +// Example: +// +// absl::CivilSecond cs(2013, 1, 2, 3, 4, 5); +// absl::Time t = absl::FromCivil(cs, lax); +// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05" +// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000" +// +// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned +// string will be exactly "infinite-future". If the given `absl::Time` is +// `absl::InfinitePast()`, the returned string will be exactly "infinite-past". +// In both cases the given format string and `absl::TimeZone` are ignored. +// +std::string FormatTime(absl::string_view format, Time t, TimeZone tz); + +// Convenience functions that format the given time using the RFC3339_full +// format. The first overload uses the provided TimeZone, while the second +// uses LocalTimeZone(). +std::string FormatTime(Time t, TimeZone tz); +std::string FormatTime(Time t); + +// Output stream operator. +inline std::ostream& operator<<(std::ostream& os, Time t) { + return os << FormatTime(t); +} + +// ParseTime() +// +// Parses an input string according to the provided format string and +// returns the corresponding `absl::Time`. Uses strftime()-like formatting +// options, with the same extensions as FormatTime(), but with the +// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez +// and %E*z also accept the same inputs, which (along with %z) includes +// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'. +// +// %Y consumes as many numeric characters as it can, so the matching data +// should always be terminated with a non-numeric. %E4Y always consumes +// exactly four characters, including any sign. +// +// Unspecified fields are taken from the default date and time of ... +// +// "1970-01-01 00:00:00.0 +0000" +// +// For example, parsing a string of "15:45" (%H:%M) will return an absl::Time +// that represents "1970-01-01 15:45:00.0 +0000". +// +// Note that since ParseTime() returns time instants, it makes the most sense +// to parse fully-specified date/time strings that include a UTC offset (%z, +// %Ez, or %E*z). +// +// Note also that `absl::ParseTime()` only heeds the fields year, month, day, +// hour, minute, (fractional) second, and UTC offset. Other fields, like +// weekday (%a or %A), while parsed for syntactic validity, are ignored +// in the conversion. +// +// Date and time fields that are out-of-range will be treated as errors +// rather than normalizing them like `absl::CivilSecond` does. For example, +// it is an error to parse the date "Oct 32, 2013" because 32 is out of range. +// +// A leap second of ":60" is normalized to ":00" of the following minute +// with fractional seconds discarded. The following table shows how the +// given seconds and subseconds will be parsed: +// +// "59.x" -> 59.x // exact +// "60.x" -> 00.0 // normalized +// "00.x" -> 00.x // exact +// +// Errors are indicated by returning false and assigning an error message +// to the "err" out param if it is non-null. +// +// Note: If the input string is exactly "infinite-future", the returned +// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned. +// If the input string is "infinite-past", the returned `absl::Time` will be +// `absl::InfinitePast()` and `true` will be returned. +// +bool ParseTime(absl::string_view format, absl::string_view input, Time* time, + std::string* err); + +// Like ParseTime() above, but if the format string does not contain a UTC +// offset specification (%z/%Ez/%E*z) then the input is interpreted in the +// given TimeZone. This means that the input, by itself, does not identify a +// unique instant. Being time-zone dependent, it also admits the possibility +// of ambiguity or non-existence, in which case the "pre" time (as defined +// by TimeZone::TimeInfo) is returned. For these reasons we recommend that +// all date/time strings include a UTC offset so they're context independent. +bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz, + Time* time, std::string* err); + +// ============================================================================ +// Implementation Details Follow +// ============================================================================ + +namespace time_internal { + +// Creates a Duration with a given representation. +// REQUIRES: hi,lo is a valid representation of a Duration as specified +// in time/duration.cc. +constexpr Duration MakeDuration(int64_t hi, uint32_t lo = 0) { + return Duration(hi, lo); +} + +constexpr Duration MakeDuration(int64_t hi, int64_t lo) { + return MakeDuration(hi, static_cast<uint32_t>(lo)); +} + +// Make a Duration value from a floating-point number, as long as that number +// is in the range [ 0 .. numeric_limits<int64_t>::max ), that is, as long as +// it's positive and can be converted to int64_t without risk of UB. +inline Duration MakePosDoubleDuration(double n) { + const int64_t int_secs = static_cast<int64_t>(n); + const uint32_t ticks = static_cast<uint32_t>( + (n - static_cast<double>(int_secs)) * kTicksPerSecond + 0.5); + return ticks < kTicksPerSecond + ? MakeDuration(int_secs, ticks) + : MakeDuration(int_secs + 1, ticks - kTicksPerSecond); +} + +// Creates a normalized Duration from an almost-normalized (sec,ticks) +// pair. sec may be positive or negative. ticks must be in the range +// -kTicksPerSecond < *ticks < kTicksPerSecond. If ticks is negative it +// will be normalized to a positive value in the resulting Duration. +constexpr Duration MakeNormalizedDuration(int64_t sec, int64_t ticks) { + return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond) + : MakeDuration(sec, ticks); +} + +// Provide access to the Duration representation. +constexpr int64_t GetRepHi(Duration d) { return d.rep_hi_; } +constexpr uint32_t GetRepLo(Duration d) { return d.rep_lo_; } + +// Returns true iff d is positive or negative infinity. +constexpr bool IsInfiniteDuration(Duration d) { return GetRepLo(d) == ~0U; } + +// Returns an infinite Duration with the opposite sign. +// REQUIRES: IsInfiniteDuration(d) +constexpr Duration OppositeInfinity(Duration d) { + return GetRepHi(d) < 0 + ? MakeDuration((std::numeric_limits<int64_t>::max)(), ~0U) + : MakeDuration((std::numeric_limits<int64_t>::min)(), ~0U); +} + +// Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow. +constexpr int64_t NegateAndSubtractOne(int64_t n) { + // Note: Good compilers will optimize this expression to ~n when using + // a two's-complement representation (which is required for int64_t). + return (n < 0) ? -(n + 1) : (-n) - 1; +} + +// Map between a Time and a Duration since the Unix epoch. Note that these +// functions depend on the above mentioned choice of the Unix epoch for the +// Time representation (and both need to be Time friends). Without this +// knowledge, we would need to add-in/subtract-out UnixEpoch() respectively. +constexpr Time FromUnixDuration(Duration d) { return Time(d); } +constexpr Duration ToUnixDuration(Time t) { return t.rep_; } + +template <std::intmax_t N> +constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) { + static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio"); + // Subsecond ratios cannot overflow. + return MakeNormalizedDuration( + v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N); +} +constexpr Duration FromInt64(int64_t v, std::ratio<60>) { + return (v <= (std::numeric_limits<int64_t>::max)() / 60 && + v >= (std::numeric_limits<int64_t>::min)() / 60) + ? MakeDuration(v * 60) + : v > 0 ? InfiniteDuration() : -InfiniteDuration(); +} +constexpr Duration FromInt64(int64_t v, std::ratio<3600>) { + return (v <= (std::numeric_limits<int64_t>::max)() / 3600 && + v >= (std::numeric_limits<int64_t>::min)() / 3600) + ? MakeDuration(v * 3600) + : v > 0 ? InfiniteDuration() : -InfiniteDuration(); +} + +// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is +// valid. That is, if a T can be assigned to an int64_t without narrowing. +template <typename T> +constexpr auto IsValidRep64(int) -> decltype(int64_t{std::declval<T>()} == 0) { + return true; +} +template <typename T> +constexpr auto IsValidRep64(char) -> bool { + return false; +} + +// Converts a std::chrono::duration to an absl::Duration. +template <typename Rep, typename Period> +constexpr Duration FromChrono(const std::chrono::duration<Rep, Period>& d) { + static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); + return FromInt64(int64_t{d.count()}, Period{}); +} + +template <typename Ratio> +int64_t ToInt64(Duration d, Ratio) { + // Note: This may be used on MSVC, which may have a system_clock period of + // std::ratio<1, 10 * 1000 * 1000> + return ToInt64Seconds(d * Ratio::den / Ratio::num); +} +// Fastpath implementations for the 6 common duration units. +inline int64_t ToInt64(Duration d, std::nano) { + return ToInt64Nanoseconds(d); +} +inline int64_t ToInt64(Duration d, std::micro) { + return ToInt64Microseconds(d); +} +inline int64_t ToInt64(Duration d, std::milli) { + return ToInt64Milliseconds(d); +} +inline int64_t ToInt64(Duration d, std::ratio<1>) { + return ToInt64Seconds(d); +} +inline int64_t ToInt64(Duration d, std::ratio<60>) { + return ToInt64Minutes(d); +} +inline int64_t ToInt64(Duration d, std::ratio<3600>) { + return ToInt64Hours(d); +} + +// Converts an absl::Duration to a chrono duration of type T. +template <typename T> +T ToChronoDuration(Duration d) { + using Rep = typename T::rep; + using Period = typename T::period; + static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid"); + if (time_internal::IsInfiniteDuration(d)) + return d < ZeroDuration() ? (T::min)() : (T::max)(); + const auto v = ToInt64(d, Period{}); + if (v > (std::numeric_limits<Rep>::max)()) return (T::max)(); + if (v < (std::numeric_limits<Rep>::min)()) return (T::min)(); + return T{v}; +} + +} // namespace time_internal + +constexpr Duration Nanoseconds(int64_t n) { + return time_internal::FromInt64(n, std::nano{}); +} +constexpr Duration Microseconds(int64_t n) { + return time_internal::FromInt64(n, std::micro{}); +} +constexpr Duration Milliseconds(int64_t n) { + return time_internal::FromInt64(n, std::milli{}); +} +constexpr Duration Seconds(int64_t n) { + return time_internal::FromInt64(n, std::ratio<1>{}); +} +constexpr Duration Minutes(int64_t n) { + return time_internal::FromInt64(n, std::ratio<60>{}); +} +constexpr Duration Hours(int64_t n) { + return time_internal::FromInt64(n, std::ratio<3600>{}); +} + +constexpr bool operator<(Duration lhs, Duration rhs) { + return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs) + ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs) + : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)() + ? time_internal::GetRepLo(lhs) + 1 < + time_internal::GetRepLo(rhs) + 1 + : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs); +} + +constexpr bool operator==(Duration lhs, Duration rhs) { + return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) && + time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs); +} + +constexpr Duration operator-(Duration d) { + // This is a little interesting because of the special cases. + // + // If rep_lo_ is zero, we have it easy; it's safe to negate rep_hi_, we're + // dealing with an integral number of seconds, and the only special case is + // the maximum negative finite duration, which can't be negated. + // + // Infinities stay infinite, and just change direction. + // + // Finally we're in the case where rep_lo_ is non-zero, and we can borrow + // a second's worth of ticks and avoid overflow (as negating int64_t-min + 1 + // is safe). + return time_internal::GetRepLo(d) == 0 + ? time_internal::GetRepHi(d) == + (std::numeric_limits<int64_t>::min)() + ? InfiniteDuration() + : time_internal::MakeDuration(-time_internal::GetRepHi(d)) + : time_internal::IsInfiniteDuration(d) + ? time_internal::OppositeInfinity(d) + : time_internal::MakeDuration( + time_internal::NegateAndSubtractOne( + time_internal::GetRepHi(d)), + time_internal::kTicksPerSecond - + time_internal::GetRepLo(d)); +} + +constexpr Duration InfiniteDuration() { + return time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(), + ~0U); +} + +constexpr Duration FromChrono(const std::chrono::nanoseconds& d) { + return time_internal::FromChrono(d); +} +constexpr Duration FromChrono(const std::chrono::microseconds& d) { + return time_internal::FromChrono(d); +} +constexpr Duration FromChrono(const std::chrono::milliseconds& d) { + return time_internal::FromChrono(d); +} +constexpr Duration FromChrono(const std::chrono::seconds& d) { + return time_internal::FromChrono(d); +} +constexpr Duration FromChrono(const std::chrono::minutes& d) { + return time_internal::FromChrono(d); +} +constexpr Duration FromChrono(const std::chrono::hours& d) { + return time_internal::FromChrono(d); +} + +constexpr Time FromUnixNanos(int64_t ns) { + return time_internal::FromUnixDuration(Nanoseconds(ns)); +} + +constexpr Time FromUnixMicros(int64_t us) { + return time_internal::FromUnixDuration(Microseconds(us)); +} + +constexpr Time FromUnixMillis(int64_t ms) { + return time_internal::FromUnixDuration(Milliseconds(ms)); +} + +constexpr Time FromUnixSeconds(int64_t s) { + return time_internal::FromUnixDuration(Seconds(s)); +} + +constexpr Time FromTimeT(time_t t) { + return time_internal::FromUnixDuration(Seconds(t)); +} + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TIME_TIME_H_ diff --git a/third_party/abseil_cpp/absl/time/time_benchmark.cc b/third_party/abseil_cpp/absl/time/time_benchmark.cc new file mode 100644 index 000000000000..99e6279984e6 --- /dev/null +++ b/third_party/abseil_cpp/absl/time/time_benchmark.cc @@ -0,0 +1,316 @@ +// Copyright 2018 The Abseil Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/time.h" + +#if !defined(_WIN32) +#include <sys/time.h> +#endif // _WIN32 +#include <algorithm> +#include <cmath> +#include <cstddef> +#include <cstring> +#include <ctime> +#include <memory> +#include <string> + +#include "absl/time/clock.h" +#include "absl/time/internal/test_util.h" +#include "benchmark/benchmark.h" + +namespace { + +// +// Addition/Subtraction of a duration +// + +void BM_Time_Arithmetic(benchmark::State& state) { + const absl::Duration nano = absl::Nanoseconds(1); + const absl::Duration sec = absl::Seconds(1); + absl::Time t = absl::UnixEpoch(); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(t += nano); + benchmark::DoNotOptimize(t -= sec); + } +} +BENCHMARK(BM_Time_Arithmetic); + +// +// Time difference +// + +void BM_Time_Difference(benchmark::State& state) { + absl::Time start = absl::Now(); + absl::Time end = start + absl::Nanoseconds(1); + absl::Duration diff; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(diff += end - start); + } +} +BENCHMARK(BM_Time_Difference); + +// +// ToDateTime +// +// In each "ToDateTime" benchmark we switch between two instants +// separated by at least one transition in order to defeat any +// internal caching of previous results (e.g., see local_time_hint_). +// +// The "UTC" variants use UTC instead of the Google/local time zone. +// + +void BM_Time_ToDateTime_Absl(benchmark::State& state) { + const absl::TimeZone tz = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + absl::Time t = absl::FromUnixSeconds(1384569027); + absl::Time t2 = absl::FromUnixSeconds(1418962578); + while (state.KeepRunning()) { + std::swap(t, t2); + t += absl::Seconds(1); + benchmark::DoNotOptimize(t.In(tz)); + } +} +BENCHMARK(BM_Time_ToDateTime_Absl); + +void BM_Time_ToDateTime_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + time_t t = 1384569027; + time_t t2 = 1418962578; + while (state.KeepRunning()) { + std::swap(t, t2); + t += 1; + struct tm tm; +#if !defined(_WIN32) + benchmark::DoNotOptimize(localtime_r(&t, &tm)); +#else // _WIN32 + benchmark::DoNotOptimize(localtime_s(&tm, &t)); +#endif // _WIN32 + } +} +BENCHMARK(BM_Time_ToDateTime_Libc); + +void BM_Time_ToDateTimeUTC_Absl(benchmark::State& state) { + const absl::TimeZone tz = absl::UTCTimeZone(); + absl::Time t = absl::FromUnixSeconds(1384569027); + while (state.KeepRunning()) { + t += absl::Seconds(1); + benchmark::DoNotOptimize(t.In(tz)); + } +} +BENCHMARK(BM_Time_ToDateTimeUTC_Absl); + +void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) { + time_t t = 1384569027; + while (state.KeepRunning()) { + t += 1; + struct tm tm; +#if !defined(_WIN32) + benchmark::DoNotOptimize(gmtime_r(&t, &tm)); +#else // _WIN32 + benchmark::DoNotOptimize(gmtime_s(&tm, &t)); +#endif // _WIN32 + } +} +BENCHMARK(BM_Time_ToDateTimeUTC_Libc); + +// +// FromUnixMicros +// + +void BM_Time_FromUnixMicros(benchmark::State& state) { + int i = 0; + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::FromUnixMicros(i)); + ++i; + } +} +BENCHMARK(BM_Time_FromUnixMicros); + +void BM_Time_ToUnixNanos(benchmark::State& state) { + const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(ToUnixNanos(t)); + } +} +BENCHMARK(BM_Time_ToUnixNanos); + +void BM_Time_ToUnixMicros(benchmark::State& state) { + const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(ToUnixMicros(t)); + } +} +BENCHMARK(BM_Time_ToUnixMicros); + +void BM_Time_ToUnixMillis(benchmark::State& state) { + const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(ToUnixMillis(t)); + } +} +BENCHMARK(BM_Time_ToUnixMillis); + +void BM_Time_ToUnixSeconds(benchmark::State& state) { + const absl::Time t = absl::UnixEpoch() + absl::Seconds(123); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToUnixSeconds(t)); + } +} +BENCHMARK(BM_Time_ToUnixSeconds); + +// +// FromCivil +// +// In each "FromCivil" benchmark we switch between two YMDhms values +// separated by at least one transition in order to defeat any internal +// caching of previous results (e.g., see time_local_hint_). +// +// The "UTC" variants use UTC instead of the Google/local time zone. +// The "Day0" variants require normalization of the day of month. +// + +void BM_Time_FromCivil_Absl(benchmark::State& state) { + const absl::TimeZone tz = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + int i = 0; + while (state.KeepRunning()) { + if ((i & 1) == 0) { + absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz); + } else { + absl::FromCivil(absl::CivilSecond(2013, 11, 15, 18, 30, 27), tz); + } + ++i; + } +} +BENCHMARK(BM_Time_FromCivil_Absl); + +void BM_Time_FromCivil_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + int i = 0; + while (state.KeepRunning()) { + struct tm tm; + if ((i & 1) == 0) { + tm.tm_year = 2014 - 1900; + tm.tm_mon = 12 - 1; + tm.tm_mday = 18; + tm.tm_hour = 20; + tm.tm_min = 16; + tm.tm_sec = 18; + } else { + tm.tm_year = 2013 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 15; + tm.tm_hour = 18; + tm.tm_min = 30; + tm.tm_sec = 27; + } + tm.tm_isdst = -1; + mktime(&tm); + ++i; + } +} +BENCHMARK(BM_Time_FromCivil_Libc); + +void BM_Time_FromCivilUTC_Absl(benchmark::State& state) { + const absl::TimeZone tz = absl::UTCTimeZone(); + while (state.KeepRunning()) { + absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz); + } +} +BENCHMARK(BM_Time_FromCivilUTC_Absl); + +void BM_Time_FromCivilDay0_Absl(benchmark::State& state) { + const absl::TimeZone tz = + absl::time_internal::LoadTimeZone("America/Los_Angeles"); + int i = 0; + while (state.KeepRunning()) { + if ((i & 1) == 0) { + absl::FromCivil(absl::CivilSecond(2014, 12, 0, 20, 16, 18), tz); + } else { + absl::FromCivil(absl::CivilSecond(2013, 11, 0, 18, 30, 27), tz); + } + ++i; + } +} +BENCHMARK(BM_Time_FromCivilDay0_Absl); + +void BM_Time_FromCivilDay0_Libc(benchmark::State& state) { + // No timezone support, so just use localtime. + int i = 0; + while (state.KeepRunning()) { + struct tm tm; + if ((i & 1) == 0) { + tm.tm_year = 2014 - 1900; + tm.tm_mon = 12 - 1; + tm.tm_mday = 0; + tm.tm_hour = 20; + tm.tm_min = 16; + tm.tm_sec = 18; + } else { + tm.tm_year = 2013 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 0; + tm.tm_hour = 18; + tm.tm_min = 30; + tm.tm_sec = 27; + } + tm.tm_isdst = -1; + mktime(&tm); + ++i; + } +} +BENCHMARK(BM_Time_FromCivilDay0_Libc); + +// +// To/FromTimespec +// + +void BM_Time_ToTimespec(benchmark::State& state) { + absl::Time now = absl::Now(); + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::ToTimespec(now)); + } +} +BENCHMARK(BM_Time_ToTimespec); + +void BM_Time_FromTimespec(benchmark::State& state) { + timespec ts = absl::ToTimespec(absl::Now()); + while (state.KeepRunning()) { + if (++ts.tv_nsec == 1000 * 1000 * 1000) { + ++ts.tv_sec; + ts.tv_nsec = 0; + } + benchmark::DoNotOptimize(absl::TimeFromTimespec(ts)); + } +} +BENCHMARK(BM_Time_FromTimespec); + +// +// Comparison with InfiniteFuture/Past +// + +void BM_Time_InfiniteFuture(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::InfiniteFuture()); + } +} +BENCHMARK(BM_Time_InfiniteFuture); + +void BM_Time_InfinitePast(benchmark::State& state) { + while (state.KeepRunning()) { + benchmark::DoNotOptimize(absl::InfinitePast()); + } +} +BENCHMARK(BM_Time_InfinitePast); + +} // namespace diff --git a/third_party/abseil_cpp/absl/time/time_test.cc b/third_party/abseil_cpp/absl/time/time_test.cc new file mode 100644 index 000000000000..cde9423feb1a --- /dev/null +++ b/third_party/abseil_cpp/absl/time/time_test.cc @@ -0,0 +1,1280 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/time.h" + +#if defined(_MSC_VER) +#include <winsock2.h> // for timeval +#endif + +#include <chrono> // NOLINT(build/c++11) +#include <cstring> +#include <ctime> +#include <iomanip> +#include <limits> +#include <string> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/numeric/int128.h" +#include "absl/time/clock.h" +#include "absl/time/internal/test_util.h" + +namespace { + +#if defined(GTEST_USES_SIMPLE_RE) && GTEST_USES_SIMPLE_RE +const char kZoneAbbrRE[] = ".*"; // just punt +#else +const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?"; +#endif + +// This helper is a macro so that failed expectations show up with the +// correct line numbers. +#define EXPECT_CIVIL_INFO(ci, y, m, d, h, min, s, off, isdst) \ + do { \ + EXPECT_EQ(y, ci.cs.year()); \ + EXPECT_EQ(m, ci.cs.month()); \ + EXPECT_EQ(d, ci.cs.day()); \ + EXPECT_EQ(h, ci.cs.hour()); \ + EXPECT_EQ(min, ci.cs.minute()); \ + EXPECT_EQ(s, ci.cs.second()); \ + EXPECT_EQ(off, ci.offset); \ + EXPECT_EQ(isdst, ci.is_dst); \ + EXPECT_THAT(ci.zone_abbr, testing::MatchesRegex(kZoneAbbrRE)); \ + } while (0) + +// A gMock matcher to match timespec values. Use this matcher like: +// timespec ts1, ts2; +// EXPECT_THAT(ts1, TimespecMatcher(ts2)); +MATCHER_P(TimespecMatcher, ts, "") { + if (ts.tv_sec == arg.tv_sec && ts.tv_nsec == arg.tv_nsec) return true; + *result_listener << "expected: {" << ts.tv_sec << ", " << ts.tv_nsec << "} "; + *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_nsec << "}"; + return false; +} + +// A gMock matcher to match timeval values. Use this matcher like: +// timeval tv1, tv2; +// EXPECT_THAT(tv1, TimevalMatcher(tv2)); +MATCHER_P(TimevalMatcher, tv, "") { + if (tv.tv_sec == arg.tv_sec && tv.tv_usec == arg.tv_usec) return true; + *result_listener << "expected: {" << tv.tv_sec << ", " << tv.tv_usec << "} "; + *result_listener << "actual: {" << arg.tv_sec << ", " << arg.tv_usec << "}"; + return false; +} + +TEST(Time, ConstExpr) { + constexpr absl::Time t0 = absl::UnixEpoch(); + static_assert(t0 == absl::Time(), "UnixEpoch"); + constexpr absl::Time t1 = absl::InfiniteFuture(); + static_assert(t1 != absl::Time(), "InfiniteFuture"); + constexpr absl::Time t2 = absl::InfinitePast(); + static_assert(t2 != absl::Time(), "InfinitePast"); + constexpr absl::Time t3 = absl::FromUnixNanos(0); + static_assert(t3 == absl::Time(), "FromUnixNanos"); + constexpr absl::Time t4 = absl::FromUnixMicros(0); + static_assert(t4 == absl::Time(), "FromUnixMicros"); + constexpr absl::Time t5 = absl::FromUnixMillis(0); + static_assert(t5 == absl::Time(), "FromUnixMillis"); + constexpr absl::Time t6 = absl::FromUnixSeconds(0); + static_assert(t6 == absl::Time(), "FromUnixSeconds"); + constexpr absl::Time t7 = absl::FromTimeT(0); + static_assert(t7 == absl::Time(), "FromTimeT"); +} + +TEST(Time, ValueSemantics) { + absl::Time a; // Default construction + absl::Time b = a; // Copy construction + EXPECT_EQ(a, b); + absl::Time c(a); // Copy construction (again) + EXPECT_EQ(a, b); + EXPECT_EQ(a, c); + EXPECT_EQ(b, c); + b = c; // Assignment + EXPECT_EQ(a, b); + EXPECT_EQ(a, c); + EXPECT_EQ(b, c); +} + +TEST(Time, UnixEpoch) { + const auto ci = absl::UTCTimeZone().At(absl::UnixEpoch()); + EXPECT_EQ(absl::CivilSecond(1970, 1, 1, 0, 0, 0), ci.cs); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs)); +} + +TEST(Time, Breakdown) { + absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/New_York"); + absl::Time t = absl::UnixEpoch(); + + // The Unix epoch as seen in NYC. + auto ci = tz.At(t); + EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 19, 0, 0, -18000, false); + EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(ci.cs)); + + // Just before the epoch. + t -= absl::Nanoseconds(1); + ci = tz.At(t); + EXPECT_CIVIL_INFO(ci, 1969, 12, 31, 18, 59, 59, -18000, false); + EXPECT_EQ(absl::Nanoseconds(999999999), ci.subsecond); + EXPECT_EQ(absl::Weekday::wednesday, absl::GetWeekday(ci.cs)); + + // Some time later. + t += absl::Hours(24) * 2735; + t += absl::Hours(18) + absl::Minutes(30) + absl::Seconds(15) + + absl::Nanoseconds(9); + ci = tz.At(t); + EXPECT_CIVIL_INFO(ci, 1977, 6, 28, 14, 30, 15, -14400, true); + EXPECT_EQ(8, ci.subsecond / absl::Nanoseconds(1)); + EXPECT_EQ(absl::Weekday::tuesday, absl::GetWeekday(ci.cs)); +} + +TEST(Time, AdditiveOperators) { + const absl::Duration d = absl::Nanoseconds(1); + const absl::Time t0; + const absl::Time t1 = t0 + d; + + EXPECT_EQ(d, t1 - t0); + EXPECT_EQ(-d, t0 - t1); + EXPECT_EQ(t0, t1 - d); + + absl::Time t(t0); + EXPECT_EQ(t0, t); + t += d; + EXPECT_EQ(t0 + d, t); + EXPECT_EQ(d, t - t0); + t -= d; + EXPECT_EQ(t0, t); + + // Tests overflow between subseconds and seconds. + t = absl::UnixEpoch(); + t += absl::Milliseconds(500); + EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t); + t += absl::Milliseconds(600); + EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(1100), t); + t -= absl::Milliseconds(600); + EXPECT_EQ(absl::UnixEpoch() + absl::Milliseconds(500), t); + t -= absl::Milliseconds(500); + EXPECT_EQ(absl::UnixEpoch(), t); +} + +TEST(Time, RelationalOperators) { + constexpr absl::Time t1 = absl::FromUnixNanos(0); + constexpr absl::Time t2 = absl::FromUnixNanos(1); + constexpr absl::Time t3 = absl::FromUnixNanos(2); + + static_assert(absl::Time() == t1, ""); + static_assert(t1 == t1, ""); + static_assert(t2 == t2, ""); + static_assert(t3 == t3, ""); + + static_assert(t1 < t2, ""); + static_assert(t2 < t3, ""); + static_assert(t1 < t3, ""); + + static_assert(t1 <= t1, ""); + static_assert(t1 <= t2, ""); + static_assert(t2 <= t2, ""); + static_assert(t2 <= t3, ""); + static_assert(t3 <= t3, ""); + static_assert(t1 <= t3, ""); + + static_assert(t2 > t1, ""); + static_assert(t3 > t2, ""); + static_assert(t3 > t1, ""); + + static_assert(t2 >= t2, ""); + static_assert(t2 >= t1, ""); + static_assert(t3 >= t3, ""); + static_assert(t3 >= t2, ""); + static_assert(t1 >= t1, ""); + static_assert(t3 >= t1, ""); +} + +TEST(Time, Infinity) { + constexpr absl::Time ifuture = absl::InfiniteFuture(); + constexpr absl::Time ipast = absl::InfinitePast(); + + static_assert(ifuture == ifuture, ""); + static_assert(ipast == ipast, ""); + static_assert(ipast < ifuture, ""); + static_assert(ifuture > ipast, ""); + + // Arithmetic saturates + EXPECT_EQ(ifuture, ifuture + absl::Seconds(1)); + EXPECT_EQ(ifuture, ifuture - absl::Seconds(1)); + EXPECT_EQ(ipast, ipast + absl::Seconds(1)); + EXPECT_EQ(ipast, ipast - absl::Seconds(1)); + + EXPECT_EQ(absl::InfiniteDuration(), ifuture - ifuture); + EXPECT_EQ(absl::InfiniteDuration(), ifuture - ipast); + EXPECT_EQ(-absl::InfiniteDuration(), ipast - ifuture); + EXPECT_EQ(-absl::InfiniteDuration(), ipast - ipast); + + constexpr absl::Time t = absl::UnixEpoch(); // Any finite time. + static_assert(t < ifuture, ""); + static_assert(t > ipast, ""); + + EXPECT_EQ(ifuture, t + absl::InfiniteDuration()); + EXPECT_EQ(ipast, t - absl::InfiniteDuration()); +} + +TEST(Time, FloorConversion) { +#define TEST_FLOOR_CONVERSION(TO, FROM) \ + EXPECT_EQ(1, TO(FROM(1001))); \ + EXPECT_EQ(1, TO(FROM(1000))); \ + EXPECT_EQ(0, TO(FROM(999))); \ + EXPECT_EQ(0, TO(FROM(1))); \ + EXPECT_EQ(0, TO(FROM(0))); \ + EXPECT_EQ(-1, TO(FROM(-1))); \ + EXPECT_EQ(-1, TO(FROM(-999))); \ + EXPECT_EQ(-1, TO(FROM(-1000))); \ + EXPECT_EQ(-2, TO(FROM(-1001))); + + TEST_FLOOR_CONVERSION(absl::ToUnixMicros, absl::FromUnixNanos); + TEST_FLOOR_CONVERSION(absl::ToUnixMillis, absl::FromUnixMicros); + TEST_FLOOR_CONVERSION(absl::ToUnixSeconds, absl::FromUnixMillis); + TEST_FLOOR_CONVERSION(absl::ToTimeT, absl::FromUnixMillis); + +#undef TEST_FLOOR_CONVERSION + + // Tests ToUnixNanos. + EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(3) / 2)); + EXPECT_EQ(1, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1))); + EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(1) / 2)); + EXPECT_EQ(0, absl::ToUnixNanos(absl::UnixEpoch() + absl::Nanoseconds(0))); + EXPECT_EQ(-1, + absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1) / 2)); + EXPECT_EQ(-1, absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(1))); + EXPECT_EQ(-2, + absl::ToUnixNanos(absl::UnixEpoch() - absl::Nanoseconds(3) / 2)); + + // Tests ToUniversal, which uses a different epoch than the tests above. + EXPECT_EQ(1, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(101))); + EXPECT_EQ(1, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(100))); + EXPECT_EQ(0, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(99))); + EXPECT_EQ(0, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(1))); + EXPECT_EQ(0, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(0))); + EXPECT_EQ(-1, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-1))); + EXPECT_EQ(-1, + absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-99))); + EXPECT_EQ( + -1, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-100))); + EXPECT_EQ( + -2, absl::ToUniversal(absl::UniversalEpoch() + absl::Nanoseconds(-101))); + + // Tests ToTimespec()/TimeFromTimespec() + const struct { + absl::Time t; + timespec ts; + } to_ts[] = { + {absl::FromUnixSeconds(1) + absl::Nanoseconds(1), {1, 1}}, + {absl::FromUnixSeconds(1) + absl::Nanoseconds(1) / 2, {1, 0}}, + {absl::FromUnixSeconds(1) + absl::Nanoseconds(0), {1, 0}}, + {absl::FromUnixSeconds(0) + absl::Nanoseconds(0), {0, 0}}, + {absl::FromUnixSeconds(0) - absl::Nanoseconds(1) / 2, {-1, 999999999}}, + {absl::FromUnixSeconds(0) - absl::Nanoseconds(1), {-1, 999999999}}, + {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1), {-1, 1}}, + {absl::FromUnixSeconds(-1) + absl::Nanoseconds(1) / 2, {-1, 0}}, + {absl::FromUnixSeconds(-1) + absl::Nanoseconds(0), {-1, 0}}, + {absl::FromUnixSeconds(-1) - absl::Nanoseconds(1) / 2, {-2, 999999999}}, + }; + for (const auto& test : to_ts) { + EXPECT_THAT(absl::ToTimespec(test.t), TimespecMatcher(test.ts)); + } + const struct { + timespec ts; + absl::Time t; + } from_ts[] = { + {{1, 1}, absl::FromUnixSeconds(1) + absl::Nanoseconds(1)}, + {{1, 0}, absl::FromUnixSeconds(1) + absl::Nanoseconds(0)}, + {{0, 0}, absl::FromUnixSeconds(0) + absl::Nanoseconds(0)}, + {{0, -1}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)}, + {{-1, 999999999}, absl::FromUnixSeconds(0) - absl::Nanoseconds(1)}, + {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(1)}, + {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Nanoseconds(0)}, + {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)}, + {{-2, 999999999}, absl::FromUnixSeconds(-1) - absl::Nanoseconds(1)}, + }; + for (const auto& test : from_ts) { + EXPECT_EQ(test.t, absl::TimeFromTimespec(test.ts)); + } + + // Tests ToTimeval()/TimeFromTimeval() (same as timespec above) + const struct { + absl::Time t; + timeval tv; + } to_tv[] = { + {absl::FromUnixSeconds(1) + absl::Microseconds(1), {1, 1}}, + {absl::FromUnixSeconds(1) + absl::Microseconds(1) / 2, {1, 0}}, + {absl::FromUnixSeconds(1) + absl::Microseconds(0), {1, 0}}, + {absl::FromUnixSeconds(0) + absl::Microseconds(0), {0, 0}}, + {absl::FromUnixSeconds(0) - absl::Microseconds(1) / 2, {-1, 999999}}, + {absl::FromUnixSeconds(0) - absl::Microseconds(1), {-1, 999999}}, + {absl::FromUnixSeconds(-1) + absl::Microseconds(1), {-1, 1}}, + {absl::FromUnixSeconds(-1) + absl::Microseconds(1) / 2, {-1, 0}}, + {absl::FromUnixSeconds(-1) + absl::Microseconds(0), {-1, 0}}, + {absl::FromUnixSeconds(-1) - absl::Microseconds(1) / 2, {-2, 999999}}, + }; + for (const auto& test : to_tv) { + EXPECT_THAT(ToTimeval(test.t), TimevalMatcher(test.tv)); + } + const struct { + timeval tv; + absl::Time t; + } from_tv[] = { + {{1, 1}, absl::FromUnixSeconds(1) + absl::Microseconds(1)}, + {{1, 0}, absl::FromUnixSeconds(1) + absl::Microseconds(0)}, + {{0, 0}, absl::FromUnixSeconds(0) + absl::Microseconds(0)}, + {{0, -1}, absl::FromUnixSeconds(0) - absl::Microseconds(1)}, + {{-1, 999999}, absl::FromUnixSeconds(0) - absl::Microseconds(1)}, + {{-1, 1}, absl::FromUnixSeconds(-1) + absl::Microseconds(1)}, + {{-1, 0}, absl::FromUnixSeconds(-1) + absl::Microseconds(0)}, + {{-1, -1}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)}, + {{-2, 999999}, absl::FromUnixSeconds(-1) - absl::Microseconds(1)}, + }; + for (const auto& test : from_tv) { + EXPECT_EQ(test.t, absl::TimeFromTimeval(test.tv)); + } + + // Tests flooring near negative infinity. + const int64_t min_plus_1 = std::numeric_limits<int64_t>::min() + 1; + EXPECT_EQ(min_plus_1, absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1))); + EXPECT_EQ(std::numeric_limits<int64_t>::min(), + absl::ToUnixSeconds(absl::FromUnixSeconds(min_plus_1) - + absl::Nanoseconds(1) / 2)); + + // Tests flooring near positive infinity. + EXPECT_EQ(std::numeric_limits<int64_t>::max(), + absl::ToUnixSeconds( + absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) + + absl::Nanoseconds(1) / 2)); + EXPECT_EQ(std::numeric_limits<int64_t>::max(), + absl::ToUnixSeconds( + absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()))); + EXPECT_EQ(std::numeric_limits<int64_t>::max() - 1, + absl::ToUnixSeconds( + absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()) - + absl::Nanoseconds(1) / 2)); +} + +TEST(Time, RoundtripConversion) { +#define TEST_CONVERSION_ROUND_TRIP(SOURCE, FROM, TO, MATCHER) \ + EXPECT_THAT(TO(FROM(SOURCE)), MATCHER(SOURCE)) + + // FromUnixNanos() and ToUnixNanos() + int64_t now_ns = absl::GetCurrentTimeNanos(); + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixNanos, absl::ToUnixNanos, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixNanos, absl::ToUnixNanos, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixNanos, absl::ToUnixNanos, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(now_ns, absl::FromUnixNanos, absl::ToUnixNanos, + testing::Eq) + << now_ns; + + // FromUnixMicros() and ToUnixMicros() + int64_t now_us = absl::GetCurrentTimeNanos() / 1000; + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMicros, absl::ToUnixMicros, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMicros, absl::ToUnixMicros, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMicros, absl::ToUnixMicros, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(now_us, absl::FromUnixMicros, absl::ToUnixMicros, + testing::Eq) + << now_us; + + // FromUnixMillis() and ToUnixMillis() + int64_t now_ms = absl::GetCurrentTimeNanos() / 1000000; + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixMillis, absl::ToUnixMillis, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixMillis, absl::ToUnixMillis, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixMillis, absl::ToUnixMillis, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(now_ms, absl::FromUnixMillis, absl::ToUnixMillis, + testing::Eq) + << now_ms; + + // FromUnixSeconds() and ToUnixSeconds() + int64_t now_s = std::time(nullptr); + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUnixSeconds, absl::ToUnixSeconds, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromUnixSeconds, absl::ToUnixSeconds, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromUnixSeconds, absl::ToUnixSeconds, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(now_s, absl::FromUnixSeconds, absl::ToUnixSeconds, + testing::Eq) + << now_s; + + // FromTimeT() and ToTimeT() + time_t now_time_t = std::time(nullptr); + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromTimeT, absl::ToTimeT, testing::Eq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromTimeT, absl::ToTimeT, testing::Eq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromTimeT, absl::ToTimeT, testing::Eq); + TEST_CONVERSION_ROUND_TRIP(now_time_t, absl::FromTimeT, absl::ToTimeT, + testing::Eq) + << now_time_t; + + // TimeFromTimeval() and ToTimeval() + timeval tv; + tv.tv_sec = -1; + tv.tv_usec = 0; + TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, + TimevalMatcher); + tv.tv_sec = -1; + tv.tv_usec = 999999; + TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, + TimevalMatcher); + tv.tv_sec = 0; + tv.tv_usec = 0; + TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, + TimevalMatcher); + tv.tv_sec = 0; + tv.tv_usec = 1; + TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, + TimevalMatcher); + tv.tv_sec = 1; + tv.tv_usec = 0; + TEST_CONVERSION_ROUND_TRIP(tv, absl::TimeFromTimeval, absl::ToTimeval, + TimevalMatcher); + + // TimeFromTimespec() and ToTimespec() + timespec ts; + ts.tv_sec = -1; + ts.tv_nsec = 0; + TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, + TimespecMatcher); + ts.tv_sec = -1; + ts.tv_nsec = 999999999; + TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, + TimespecMatcher); + ts.tv_sec = 0; + ts.tv_nsec = 0; + TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, + TimespecMatcher); + ts.tv_sec = 0; + ts.tv_nsec = 1; + TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, + TimespecMatcher); + ts.tv_sec = 1; + ts.tv_nsec = 0; + TEST_CONVERSION_ROUND_TRIP(ts, absl::TimeFromTimespec, absl::ToTimespec, + TimespecMatcher); + + // FromUDate() and ToUDate() + double now_ud = absl::GetCurrentTimeNanos() / 1000000; + TEST_CONVERSION_ROUND_TRIP(-1.5, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(-0.5, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(0.5, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(1.5, absl::FromUDate, absl::ToUDate, + testing::DoubleEq); + TEST_CONVERSION_ROUND_TRIP(now_ud, absl::FromUDate, absl::ToUDate, + testing::DoubleEq) + << std::fixed << std::setprecision(17) << now_ud; + + // FromUniversal() and ToUniversal() + int64_t now_uni = ((719162LL * (24 * 60 * 60)) * (1000 * 1000 * 10)) + + (absl::GetCurrentTimeNanos() / 100); + TEST_CONVERSION_ROUND_TRIP(-1, absl::FromUniversal, absl::ToUniversal, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(0, absl::FromUniversal, absl::ToUniversal, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(1, absl::FromUniversal, absl::ToUniversal, + testing::Eq); + TEST_CONVERSION_ROUND_TRIP(now_uni, absl::FromUniversal, absl::ToUniversal, + testing::Eq) + << now_uni; + +#undef TEST_CONVERSION_ROUND_TRIP +} + +template <typename Duration> +std::chrono::system_clock::time_point MakeChronoUnixTime(const Duration& d) { + return std::chrono::system_clock::from_time_t(0) + d; +} + +TEST(Time, FromChrono) { + EXPECT_EQ(absl::FromTimeT(-1), + absl::FromChrono(std::chrono::system_clock::from_time_t(-1))); + EXPECT_EQ(absl::FromTimeT(0), + absl::FromChrono(std::chrono::system_clock::from_time_t(0))); + EXPECT_EQ(absl::FromTimeT(1), + absl::FromChrono(std::chrono::system_clock::from_time_t(1))); + + EXPECT_EQ( + absl::FromUnixMillis(-1), + absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(-1)))); + EXPECT_EQ(absl::FromUnixMillis(0), + absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(0)))); + EXPECT_EQ(absl::FromUnixMillis(1), + absl::FromChrono(MakeChronoUnixTime(std::chrono::milliseconds(1)))); + + // Chrono doesn't define exactly its range and precision (neither does + // absl::Time), so let's simply test +/- ~100 years to make sure things work. + const auto century_sec = 60 * 60 * 24 * 365 * int64_t{100}; + const auto century = std::chrono::seconds(century_sec); + const auto chrono_future = MakeChronoUnixTime(century); + const auto chrono_past = MakeChronoUnixTime(-century); + EXPECT_EQ(absl::FromUnixSeconds(century_sec), + absl::FromChrono(chrono_future)); + EXPECT_EQ(absl::FromUnixSeconds(-century_sec), absl::FromChrono(chrono_past)); + + // Roundtrip them both back to chrono. + EXPECT_EQ(chrono_future, + absl::ToChronoTime(absl::FromUnixSeconds(century_sec))); + EXPECT_EQ(chrono_past, + absl::ToChronoTime(absl::FromUnixSeconds(-century_sec))); +} + +TEST(Time, ToChronoTime) { + EXPECT_EQ(std::chrono::system_clock::from_time_t(-1), + absl::ToChronoTime(absl::FromTimeT(-1))); + EXPECT_EQ(std::chrono::system_clock::from_time_t(0), + absl::ToChronoTime(absl::FromTimeT(0))); + EXPECT_EQ(std::chrono::system_clock::from_time_t(1), + absl::ToChronoTime(absl::FromTimeT(1))); + + EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(-1)), + absl::ToChronoTime(absl::FromUnixMillis(-1))); + EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(0)), + absl::ToChronoTime(absl::FromUnixMillis(0))); + EXPECT_EQ(MakeChronoUnixTime(std::chrono::milliseconds(1)), + absl::ToChronoTime(absl::FromUnixMillis(1))); + + // Time before the Unix epoch should floor, not trunc. + const auto tick = absl::Nanoseconds(1) / 4; + EXPECT_EQ(std::chrono::system_clock::from_time_t(0) - + std::chrono::system_clock::duration(1), + absl::ToChronoTime(absl::UnixEpoch() - tick)); +} + +// Check that absl::int128 works as a std::chrono::duration representation. +TEST(Time, Chrono128) { + // Define a std::chrono::time_point type whose time[sic]_since_epoch() is + // a signed 128-bit count of attoseconds. This has a range and resolution + // (currently) beyond those of absl::Time, and undoubtedly also beyond those + // of std::chrono::system_clock::time_point. + // + // Note: The to/from-chrono support should probably be updated to handle + // such wide representations. + using Timestamp = + std::chrono::time_point<std::chrono::system_clock, + std::chrono::duration<absl::int128, std::atto>>; + + // Expect that we can round-trip the std::chrono::system_clock::time_point + // extremes through both absl::Time and Timestamp, and that Timestamp can + // handle the (current) absl::Time extremes. + // + // Note: We should use std::chrono::floor() instead of time_point_cast(), + // but floor() is only available since c++17. + for (const auto tp : {std::chrono::system_clock::time_point::min(), + std::chrono::system_clock::time_point::max()}) { + EXPECT_EQ(tp, absl::ToChronoTime(absl::FromChrono(tp))); + EXPECT_EQ(tp, std::chrono::time_point_cast< + std::chrono::system_clock::time_point::duration>( + std::chrono::time_point_cast<Timestamp::duration>(tp))); + } + Timestamp::duration::rep v = std::numeric_limits<int64_t>::min(); + v *= Timestamp::duration::period::den; + auto ts = Timestamp(Timestamp::duration(v)); + ts += std::chrono::duration<int64_t, std::atto>(0); + EXPECT_EQ(std::numeric_limits<int64_t>::min(), + ts.time_since_epoch().count() / Timestamp::duration::period::den); + EXPECT_EQ(0, + ts.time_since_epoch().count() % Timestamp::duration::period::den); + v = std::numeric_limits<int64_t>::max(); + v *= Timestamp::duration::period::den; + ts = Timestamp(Timestamp::duration(v)); + ts += std::chrono::duration<int64_t, std::atto>(999999999750000000); + EXPECT_EQ(std::numeric_limits<int64_t>::max(), + ts.time_since_epoch().count() / Timestamp::duration::period::den); + EXPECT_EQ(999999999750000000, + ts.time_since_epoch().count() % Timestamp::duration::period::den); +} + +TEST(Time, TimeZoneAt) { + const absl::TimeZone nyc = + absl::time_internal::LoadTimeZone("America/New_York"); + const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)"; + + // A non-transition where the civil time is unique. + absl::CivilSecond nov01(2013, 11, 1, 8, 30, 0); + const auto nov01_ci = nyc.At(nov01); + EXPECT_EQ(absl::TimeZone::TimeInfo::UNIQUE, nov01_ci.kind); + EXPECT_EQ("Fri, 1 Nov 2013 08:30:00 -0400 (EDT)", + absl::FormatTime(fmt, nov01_ci.pre, nyc)); + EXPECT_EQ(nov01_ci.pre, nov01_ci.trans); + EXPECT_EQ(nov01_ci.pre, nov01_ci.post); + EXPECT_EQ(nov01_ci.pre, absl::FromCivil(nov01, nyc)); + + // A Spring DST transition, when there is a gap in civil time + // and we prefer the later of the possible interpretations of a + // non-existent time. + absl::CivilSecond mar13(2011, 3, 13, 2, 15, 0); + const auto mar_ci = nyc.At(mar13); + EXPECT_EQ(absl::TimeZone::TimeInfo::SKIPPED, mar_ci.kind); + EXPECT_EQ("Sun, 13 Mar 2011 03:15:00 -0400 (EDT)", + absl::FormatTime(fmt, mar_ci.pre, nyc)); + EXPECT_EQ("Sun, 13 Mar 2011 03:00:00 -0400 (EDT)", + absl::FormatTime(fmt, mar_ci.trans, nyc)); + EXPECT_EQ("Sun, 13 Mar 2011 01:15:00 -0500 (EST)", + absl::FormatTime(fmt, mar_ci.post, nyc)); + EXPECT_EQ(mar_ci.trans, absl::FromCivil(mar13, nyc)); + + // A Fall DST transition, when civil times are repeated and + // we prefer the earlier of the possible interpretations of an + // ambiguous time. + absl::CivilSecond nov06(2011, 11, 6, 1, 15, 0); + const auto nov06_ci = nyc.At(nov06); + EXPECT_EQ(absl::TimeZone::TimeInfo::REPEATED, nov06_ci.kind); + EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0400 (EDT)", + absl::FormatTime(fmt, nov06_ci.pre, nyc)); + EXPECT_EQ("Sun, 6 Nov 2011 01:00:00 -0500 (EST)", + absl::FormatTime(fmt, nov06_ci.trans, nyc)); + EXPECT_EQ("Sun, 6 Nov 2011 01:15:00 -0500 (EST)", + absl::FormatTime(fmt, nov06_ci.post, nyc)); + EXPECT_EQ(nov06_ci.pre, absl::FromCivil(nov06, nyc)); + + // Check that (time_t) -1 is handled correctly. + absl::CivilSecond minus1(1969, 12, 31, 18, 59, 59); + const auto minus1_cl = nyc.At(minus1); + EXPECT_EQ(absl::TimeZone::TimeInfo::UNIQUE, minus1_cl.kind); + EXPECT_EQ(-1, absl::ToTimeT(minus1_cl.pre)); + EXPECT_EQ("Wed, 31 Dec 1969 18:59:59 -0500 (EST)", + absl::FormatTime(fmt, minus1_cl.pre, nyc)); + EXPECT_EQ("Wed, 31 Dec 1969 23:59:59 +0000 (UTC)", + absl::FormatTime(fmt, minus1_cl.pre, absl::UTCTimeZone())); +} + +// FromCivil(CivilSecond(year, mon, day, hour, min, sec), UTCTimeZone()) +// has a specialized fastpath implementation, which we exercise here. +TEST(Time, FromCivilUTC) { + const absl::TimeZone utc = absl::UTCTimeZone(); + const std::string fmt = "%a, %e %b %Y %H:%M:%S %z (%Z)"; + const int kMax = std::numeric_limits<int>::max(); + const int kMin = std::numeric_limits<int>::min(); + absl::Time t; + + // 292091940881 is the last positive year to use the fastpath. + t = absl::FromCivil( + absl::CivilSecond(292091940881, kMax, kMax, kMax, kMax, kMax), utc); + EXPECT_EQ("Fri, 25 Nov 292277026596 12:21:07 +0000 (UTC)", + absl::FormatTime(fmt, t, utc)); + t = absl::FromCivil( + absl::CivilSecond(292091940882, kMax, kMax, kMax, kMax, kMax), utc); + EXPECT_EQ("infinite-future", absl::FormatTime(fmt, t, utc)); // no overflow + + // -292091936940 is the last negative year to use the fastpath. + t = absl::FromCivil( + absl::CivilSecond(-292091936940, kMin, kMin, kMin, kMin, kMin), utc); + EXPECT_EQ("Fri, 1 Nov -292277022657 10:37:52 +0000 (UTC)", + absl::FormatTime(fmt, t, utc)); + t = absl::FromCivil( + absl::CivilSecond(-292091936941, kMin, kMin, kMin, kMin, kMin), utc); + EXPECT_EQ("infinite-past", absl::FormatTime(fmt, t, utc)); // no underflow + + // Check that we're counting leap years correctly. + t = absl::FromCivil(absl::CivilSecond(1900, 2, 28, 23, 59, 59), utc); + EXPECT_EQ("Wed, 28 Feb 1900 23:59:59 +0000 (UTC)", + absl::FormatTime(fmt, t, utc)); + t = absl::FromCivil(absl::CivilSecond(1900, 3, 1, 0, 0, 0), utc); + EXPECT_EQ("Thu, 1 Mar 1900 00:00:00 +0000 (UTC)", + absl::FormatTime(fmt, t, utc)); + t = absl::FromCivil(absl::CivilSecond(2000, 2, 29, 23, 59, 59), utc); + EXPECT_EQ("Tue, 29 Feb 2000 23:59:59 +0000 (UTC)", + absl::FormatTime(fmt, t, utc)); + t = absl::FromCivil(absl::CivilSecond(2000, 3, 1, 0, 0, 0), utc); + EXPECT_EQ("Wed, 1 Mar 2000 00:00:00 +0000 (UTC)", + absl::FormatTime(fmt, t, utc)); +} + +TEST(Time, ToTM) { + const absl::TimeZone utc = absl::UTCTimeZone(); + + // Compares the results of ToTM() to gmtime_r() for lots of times over the + // course of a few days. + const absl::Time start = + absl::FromCivil(absl::CivilSecond(2014, 1, 2, 3, 4, 5), utc); + const absl::Time end = + absl::FromCivil(absl::CivilSecond(2014, 1, 5, 3, 4, 5), utc); + for (absl::Time t = start; t < end; t += absl::Seconds(30)) { + const struct tm tm_bt = ToTM(t, utc); + const time_t tt = absl::ToTimeT(t); + struct tm tm_lc; +#ifdef _WIN32 + gmtime_s(&tm_lc, &tt); +#else + gmtime_r(&tt, &tm_lc); +#endif + EXPECT_EQ(tm_lc.tm_year, tm_bt.tm_year); + EXPECT_EQ(tm_lc.tm_mon, tm_bt.tm_mon); + EXPECT_EQ(tm_lc.tm_mday, tm_bt.tm_mday); + EXPECT_EQ(tm_lc.tm_hour, tm_bt.tm_hour); + EXPECT_EQ(tm_lc.tm_min, tm_bt.tm_min); + EXPECT_EQ(tm_lc.tm_sec, tm_bt.tm_sec); + EXPECT_EQ(tm_lc.tm_wday, tm_bt.tm_wday); + EXPECT_EQ(tm_lc.tm_yday, tm_bt.tm_yday); + EXPECT_EQ(tm_lc.tm_isdst, tm_bt.tm_isdst); + + ASSERT_FALSE(HasFailure()); + } + + // Checks that the tm_isdst field is correct when in standard time. + const absl::TimeZone nyc = + absl::time_internal::LoadTimeZone("America/New_York"); + absl::Time t = absl::FromCivil(absl::CivilSecond(2014, 3, 1, 0, 0, 0), nyc); + struct tm tm = ToTM(t, nyc); + EXPECT_FALSE(tm.tm_isdst); + + // Checks that the tm_isdst field is correct when in daylight time. + t = absl::FromCivil(absl::CivilSecond(2014, 4, 1, 0, 0, 0), nyc); + tm = ToTM(t, nyc); + EXPECT_TRUE(tm.tm_isdst); + + // Checks overflow. + tm = ToTM(absl::InfiniteFuture(), nyc); + EXPECT_EQ(std::numeric_limits<int>::max() - 1900, tm.tm_year); + EXPECT_EQ(11, tm.tm_mon); + EXPECT_EQ(31, tm.tm_mday); + EXPECT_EQ(23, tm.tm_hour); + EXPECT_EQ(59, tm.tm_min); + EXPECT_EQ(59, tm.tm_sec); + EXPECT_EQ(4, tm.tm_wday); + EXPECT_EQ(364, tm.tm_yday); + EXPECT_FALSE(tm.tm_isdst); + + // Checks underflow. + tm = ToTM(absl::InfinitePast(), nyc); + EXPECT_EQ(std::numeric_limits<int>::min(), tm.tm_year); + EXPECT_EQ(0, tm.tm_mon); + EXPECT_EQ(1, tm.tm_mday); + EXPECT_EQ(0, tm.tm_hour); + EXPECT_EQ(0, tm.tm_min); + EXPECT_EQ(0, tm.tm_sec); + EXPECT_EQ(0, tm.tm_wday); + EXPECT_EQ(0, tm.tm_yday); + EXPECT_FALSE(tm.tm_isdst); +} + +TEST(Time, FromTM) { + const absl::TimeZone nyc = + absl::time_internal::LoadTimeZone("America/New_York"); + + // Verifies that tm_isdst doesn't affect anything when the time is unique. + struct tm tm; + std::memset(&tm, 0, sizeof(tm)); + tm.tm_year = 2014 - 1900; + tm.tm_mon = 6 - 1; + tm.tm_mday = 28; + tm.tm_hour = 1; + tm.tm_min = 2; + tm.tm_sec = 3; + tm.tm_isdst = -1; + absl::Time t = FromTM(tm, nyc); + EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST + tm.tm_isdst = 0; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST + tm.tm_isdst = 1; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-06-28T01:02:03-04:00", absl::FormatTime(t, nyc)); // DST + + // Adjusts tm to refer to an ambiguous time. + tm.tm_year = 2014 - 1900; + tm.tm_mon = 11 - 1; + tm.tm_mday = 2; + tm.tm_hour = 1; + tm.tm_min = 30; + tm.tm_sec = 42; + tm.tm_isdst = -1; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc)); // DST + tm.tm_isdst = 0; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-11-02T01:30:42-05:00", absl::FormatTime(t, nyc)); // STD + tm.tm_isdst = 1; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-11-02T01:30:42-04:00", absl::FormatTime(t, nyc)); // DST + + // Adjusts tm to refer to a skipped time. + tm.tm_year = 2014 - 1900; + tm.tm_mon = 3 - 1; + tm.tm_mday = 9; + tm.tm_hour = 2; + tm.tm_min = 30; + tm.tm_sec = 42; + tm.tm_isdst = -1; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST + tm.tm_isdst = 0; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-03-09T01:30:42-05:00", absl::FormatTime(t, nyc)); // STD + tm.tm_isdst = 1; + t = FromTM(tm, nyc); + EXPECT_EQ("2014-03-09T03:30:42-04:00", absl::FormatTime(t, nyc)); // DST + + // Adjusts tm to refer to a time with a year larger than 2147483647. + tm.tm_year = 2147483647 - 1900 + 1; + tm.tm_mon = 6 - 1; + tm.tm_mday = 28; + tm.tm_hour = 1; + tm.tm_min = 2; + tm.tm_sec = 3; + tm.tm_isdst = -1; + t = FromTM(tm, absl::UTCTimeZone()); + EXPECT_EQ("2147483648-06-28T01:02:03+00:00", + absl::FormatTime(t, absl::UTCTimeZone())); + + // Adjusts tm to refer to a time with a very large month. + tm.tm_year = 2019 - 1900; + tm.tm_mon = 2147483647; + tm.tm_mday = 28; + tm.tm_hour = 1; + tm.tm_min = 2; + tm.tm_sec = 3; + tm.tm_isdst = -1; + t = FromTM(tm, absl::UTCTimeZone()); + EXPECT_EQ("178958989-08-28T01:02:03+00:00", + absl::FormatTime(t, absl::UTCTimeZone())); +} + +TEST(Time, TMRoundTrip) { + const absl::TimeZone nyc = + absl::time_internal::LoadTimeZone("America/New_York"); + + // Test round-tripping across a skipped transition + absl::Time start = absl::FromCivil(absl::CivilHour(2014, 3, 9, 0), nyc); + absl::Time end = absl::FromCivil(absl::CivilHour(2014, 3, 9, 4), nyc); + for (absl::Time t = start; t < end; t += absl::Minutes(1)) { + struct tm tm = ToTM(t, nyc); + absl::Time rt = FromTM(tm, nyc); + EXPECT_EQ(rt, t); + } + + // Test round-tripping across an ambiguous transition + start = absl::FromCivil(absl::CivilHour(2014, 11, 2, 0), nyc); + end = absl::FromCivil(absl::CivilHour(2014, 11, 2, 4), nyc); + for (absl::Time t = start; t < end; t += absl::Minutes(1)) { + struct tm tm = ToTM(t, nyc); + absl::Time rt = FromTM(tm, nyc); + EXPECT_EQ(rt, t); + } + + // Test round-tripping of unique instants crossing a day boundary + start = absl::FromCivil(absl::CivilHour(2014, 6, 27, 22), nyc); + end = absl::FromCivil(absl::CivilHour(2014, 6, 28, 4), nyc); + for (absl::Time t = start; t < end; t += absl::Minutes(1)) { + struct tm tm = ToTM(t, nyc); + absl::Time rt = FromTM(tm, nyc); + EXPECT_EQ(rt, t); + } +} + +TEST(Time, Range) { + // The API's documented range is +/- 100 billion years. + const absl::Duration range = absl::Hours(24) * 365.2425 * 100000000000; + + // Arithmetic and comparison still works at +/-range around base values. + absl::Time bases[2] = {absl::UnixEpoch(), absl::Now()}; + for (const auto base : bases) { + absl::Time bottom = base - range; + EXPECT_GT(bottom, bottom - absl::Nanoseconds(1)); + EXPECT_LT(bottom, bottom + absl::Nanoseconds(1)); + absl::Time top = base + range; + EXPECT_GT(top, top - absl::Nanoseconds(1)); + EXPECT_LT(top, top + absl::Nanoseconds(1)); + absl::Duration full_range = 2 * range; + EXPECT_EQ(full_range, top - bottom); + EXPECT_EQ(-full_range, bottom - top); + } +} + +TEST(Time, Limits) { + // It is an implementation detail that Time().rep_ == ZeroDuration(), + // and that the resolution of a Duration is 1/4 of a nanosecond. + const absl::Time zero; + const absl::Time max = + zero + absl::Seconds(std::numeric_limits<int64_t>::max()) + + absl::Nanoseconds(999999999) + absl::Nanoseconds(3) / 4; + const absl::Time min = + zero + absl::Seconds(std::numeric_limits<int64_t>::min()); + + // Some simple max/min bounds checks. + EXPECT_LT(max, absl::InfiniteFuture()); + EXPECT_GT(min, absl::InfinitePast()); + EXPECT_LT(zero, max); + EXPECT_GT(zero, min); + EXPECT_GE(absl::UnixEpoch(), min); + EXPECT_LT(absl::UnixEpoch(), max); + + // Check sign of Time differences. + EXPECT_LT(absl::ZeroDuration(), max - zero); + EXPECT_LT(absl::ZeroDuration(), + zero - absl::Nanoseconds(1) / 4 - min); // avoid zero - min + + // Arithmetic works at max - 0.25ns and min + 0.25ns. + EXPECT_GT(max, max - absl::Nanoseconds(1) / 4); + EXPECT_LT(min, min + absl::Nanoseconds(1) / 4); +} + +TEST(Time, ConversionSaturation) { + const absl::TimeZone utc = absl::UTCTimeZone(); + absl::Time t; + + const auto max_time_t = std::numeric_limits<time_t>::max(); + const auto min_time_t = std::numeric_limits<time_t>::min(); + time_t tt = max_time_t - 1; + t = absl::FromTimeT(tt); + tt = absl::ToTimeT(t); + EXPECT_EQ(max_time_t - 1, tt); + t += absl::Seconds(1); + tt = absl::ToTimeT(t); + EXPECT_EQ(max_time_t, tt); + t += absl::Seconds(1); // no effect + tt = absl::ToTimeT(t); + EXPECT_EQ(max_time_t, tt); + + tt = min_time_t + 1; + t = absl::FromTimeT(tt); + tt = absl::ToTimeT(t); + EXPECT_EQ(min_time_t + 1, tt); + t -= absl::Seconds(1); + tt = absl::ToTimeT(t); + EXPECT_EQ(min_time_t, tt); + t -= absl::Seconds(1); // no effect + tt = absl::ToTimeT(t); + EXPECT_EQ(min_time_t, tt); + + const auto max_timeval_sec = + std::numeric_limits<decltype(timeval::tv_sec)>::max(); + const auto min_timeval_sec = + std::numeric_limits<decltype(timeval::tv_sec)>::min(); + timeval tv; + tv.tv_sec = max_timeval_sec; + tv.tv_usec = 999998; + t = absl::TimeFromTimeval(tv); + tv = ToTimeval(t); + EXPECT_EQ(max_timeval_sec, tv.tv_sec); + EXPECT_EQ(999998, tv.tv_usec); + t += absl::Microseconds(1); + tv = ToTimeval(t); + EXPECT_EQ(max_timeval_sec, tv.tv_sec); + EXPECT_EQ(999999, tv.tv_usec); + t += absl::Microseconds(1); // no effect + tv = ToTimeval(t); + EXPECT_EQ(max_timeval_sec, tv.tv_sec); + EXPECT_EQ(999999, tv.tv_usec); + + tv.tv_sec = min_timeval_sec; + tv.tv_usec = 1; + t = absl::TimeFromTimeval(tv); + tv = ToTimeval(t); + EXPECT_EQ(min_timeval_sec, tv.tv_sec); + EXPECT_EQ(1, tv.tv_usec); + t -= absl::Microseconds(1); + tv = ToTimeval(t); + EXPECT_EQ(min_timeval_sec, tv.tv_sec); + EXPECT_EQ(0, tv.tv_usec); + t -= absl::Microseconds(1); // no effect + tv = ToTimeval(t); + EXPECT_EQ(min_timeval_sec, tv.tv_sec); + EXPECT_EQ(0, tv.tv_usec); + + const auto max_timespec_sec = + std::numeric_limits<decltype(timespec::tv_sec)>::max(); + const auto min_timespec_sec = + std::numeric_limits<decltype(timespec::tv_sec)>::min(); + timespec ts; + ts.tv_sec = max_timespec_sec; + ts.tv_nsec = 999999998; + t = absl::TimeFromTimespec(ts); + ts = absl::ToTimespec(t); + EXPECT_EQ(max_timespec_sec, ts.tv_sec); + EXPECT_EQ(999999998, ts.tv_nsec); + t += absl::Nanoseconds(1); + ts = absl::ToTimespec(t); + EXPECT_EQ(max_timespec_sec, ts.tv_sec); + EXPECT_EQ(999999999, ts.tv_nsec); + t += absl::Nanoseconds(1); // no effect + ts = absl::ToTimespec(t); + EXPECT_EQ(max_timespec_sec, ts.tv_sec); + EXPECT_EQ(999999999, ts.tv_nsec); + + ts.tv_sec = min_timespec_sec; + ts.tv_nsec = 1; + t = absl::TimeFromTimespec(ts); + ts = absl::ToTimespec(t); + EXPECT_EQ(min_timespec_sec, ts.tv_sec); + EXPECT_EQ(1, ts.tv_nsec); + t -= absl::Nanoseconds(1); + ts = absl::ToTimespec(t); + EXPECT_EQ(min_timespec_sec, ts.tv_sec); + EXPECT_EQ(0, ts.tv_nsec); + t -= absl::Nanoseconds(1); // no effect + ts = absl::ToTimespec(t); + EXPECT_EQ(min_timespec_sec, ts.tv_sec); + EXPECT_EQ(0, ts.tv_nsec); + + // Checks how TimeZone::At() saturates on infinities. + auto ci = utc.At(absl::InfiniteFuture()); + EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::max(), 12, 31, 23, 59, 59, + 0, false); + EXPECT_EQ(absl::InfiniteDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::thursday, absl::GetWeekday(ci.cs)); + EXPECT_EQ(365, absl::GetYearDay(ci.cs)); + EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At() + ci = utc.At(absl::InfinitePast()); + EXPECT_CIVIL_INFO(ci, std::numeric_limits<int64_t>::min(), 1, 1, 0, 0, 0, 0, + false); + EXPECT_EQ(-absl::InfiniteDuration(), ci.subsecond); + EXPECT_EQ(absl::Weekday::sunday, absl::GetWeekday(ci.cs)); + EXPECT_EQ(1, absl::GetYearDay(ci.cs)); + EXPECT_STREQ("-00", ci.zone_abbr); // artifact of TimeZone::At() + + // Approach the maximal Time value from below. + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 6), utc); + EXPECT_EQ("292277026596-12-04T15:30:06+00:00", + absl::FormatTime(absl::RFC3339_full, t, utc)); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 7), utc); + EXPECT_EQ("292277026596-12-04T15:30:07+00:00", + absl::FormatTime(absl::RFC3339_full, t, utc)); + EXPECT_EQ( + absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), + t); + + // Checks that we can also get the maximal Time value for a far-east zone. + const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 5, 30, 7), plus14); + EXPECT_EQ("292277026596-12-05T05:30:07+14:00", + absl::FormatTime(absl::RFC3339_full, t, plus14)); + EXPECT_EQ( + absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), + t); + + // One second later should push us to infinity. + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc); + EXPECT_EQ("infinite-future", absl::FormatTime(absl::RFC3339_full, t, utc)); + + // Approach the minimal Time value from above. + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 53), utc); + EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", + absl::FormatTime(absl::RFC3339_full, t, utc)); + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 52), utc); + EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", + absl::FormatTime(absl::RFC3339_full, t, utc)); + EXPECT_EQ( + absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), + t); + + // Checks that we can also get the minimal Time value for a far-west zone. + const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60); + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 26, 20, 29, 52), + minus12); + EXPECT_EQ("-292277022657-01-26T20:29:52-12:00", + absl::FormatTime(absl::RFC3339_full, t, minus12)); + EXPECT_EQ( + absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), + t); + + // One second before should push us to -infinity. + t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc); + EXPECT_EQ("infinite-past", absl::FormatTime(absl::RFC3339_full, t, utc)); +} + +// In zones with POSIX-style recurring rules we use special logic to +// handle conversions in the distant future. Here we check the limits +// of those conversions, particularly with respect to integer overflow. +TEST(Time, ExtendedConversionSaturation) { + const absl::TimeZone syd = + absl::time_internal::LoadTimeZone("Australia/Sydney"); + const absl::TimeZone nyc = + absl::time_internal::LoadTimeZone("America/New_York"); + const absl::Time max = + absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()); + absl::TimeZone::CivilInfo ci; + absl::Time t; + + // The maximal time converted in each zone. + ci = syd.At(max); + EXPECT_CIVIL_INFO(ci, 292277026596, 12, 5, 2, 30, 7, 39600, true); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 7), syd); + EXPECT_EQ(max, t); + ci = nyc.At(max); + EXPECT_CIVIL_INFO(ci, 292277026596, 12, 4, 10, 30, 7, -18000, false); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 7), nyc); + EXPECT_EQ(max, t); + + // One second later should push us to infinity. + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 8), syd); + EXPECT_EQ(absl::InfiniteFuture(), t); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 8), nyc); + EXPECT_EQ(absl::InfiniteFuture(), t); + + // And we should stick there. + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 5, 2, 30, 9), syd); + EXPECT_EQ(absl::InfiniteFuture(), t); + t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 10, 30, 9), nyc); + EXPECT_EQ(absl::InfiniteFuture(), t); + + // All the way up to a saturated date/time, without overflow. + t = absl::FromCivil(absl::CivilSecond::max(), syd); + EXPECT_EQ(absl::InfiniteFuture(), t); + t = absl::FromCivil(absl::CivilSecond::max(), nyc); + EXPECT_EQ(absl::InfiniteFuture(), t); +} + +TEST(Time, FromCivilAlignment) { + const absl::TimeZone utc = absl::UTCTimeZone(); + const absl::CivilSecond cs(2015, 2, 3, 4, 5, 6); + absl::Time t = absl::FromCivil(cs, utc); + EXPECT_EQ("2015-02-03T04:05:06+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilMinute(cs), utc); + EXPECT_EQ("2015-02-03T04:05:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilHour(cs), utc); + EXPECT_EQ("2015-02-03T04:00:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilDay(cs), utc); + EXPECT_EQ("2015-02-03T00:00:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilMonth(cs), utc); + EXPECT_EQ("2015-02-01T00:00:00+00:00", absl::FormatTime(t, utc)); + t = absl::FromCivil(absl::CivilYear(cs), utc); + EXPECT_EQ("2015-01-01T00:00:00+00:00", absl::FormatTime(t, utc)); +} + +TEST(Time, LegacyDateTime) { + const absl::TimeZone utc = absl::UTCTimeZone(); + const std::string ymdhms = "%Y-%m-%d %H:%M:%S"; + const int kMax = std::numeric_limits<int>::max(); + const int kMin = std::numeric_limits<int>::min(); + absl::Time t; + + t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::max(), kMax, + kMax, kMax, kMax, kMax, utc); + EXPECT_EQ("infinite-future", + absl::FormatTime(ymdhms, t, utc)); // no overflow + t = absl::FromDateTime(std::numeric_limits<absl::civil_year_t>::min(), kMin, + kMin, kMin, kMin, kMin, utc); + EXPECT_EQ("infinite-past", absl::FormatTime(ymdhms, t, utc)); // no overflow + + // Check normalization. + EXPECT_TRUE(absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, utc).normalized); + t = absl::FromDateTime(2015, 1, 1, 0, 0, 60, utc); + EXPECT_EQ("2015-01-01 00:01:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 0, 60, 0, utc); + EXPECT_EQ("2015-01-01 01:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 24, 0, 0, utc); + EXPECT_EQ("2015-01-02 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 32, 0, 0, 0, utc); + EXPECT_EQ("2015-02-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 13, 1, 0, 0, 0, utc); + EXPECT_EQ("2016-01-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 13, 32, 60, 60, 60, utc); + EXPECT_EQ("2016-02-03 13:01:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 0, 0, -1, utc); + EXPECT_EQ("2014-12-31 23:59:59", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, 0, -1, 0, utc); + EXPECT_EQ("2014-12-31 23:59:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, 1, -1, 0, 0, utc); + EXPECT_EQ("2014-12-31 23:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, 1, -1, 0, 0, 0, utc); + EXPECT_EQ("2014-12-30 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, -1, 1, 0, 0, 0, utc); + EXPECT_EQ("2014-11-01 00:00:00", absl::FormatTime(ymdhms, t, utc)); + t = absl::FromDateTime(2015, -1, -1, -1, -1, -1, utc); + 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 diff --git a/third_party/abseil_cpp/absl/time/time_zone_test.cc b/third_party/abseil_cpp/absl/time/time_zone_test.cc new file mode 100644 index 000000000000..229fcfccb0ad --- /dev/null +++ b/third_party/abseil_cpp/absl/time/time_zone_test.cc @@ -0,0 +1,97 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/time/internal/cctz/include/cctz/time_zone.h" + +#include "gtest/gtest.h" +#include "absl/time/internal/test_util.h" +#include "absl/time/time.h" + +namespace cctz = absl::time_internal::cctz; + +namespace { + +TEST(TimeZone, ValueSemantics) { + absl::TimeZone tz; + absl::TimeZone tz2 = tz; // Copy-construct + EXPECT_EQ(tz, tz2); + tz2 = tz; // Copy-assign + EXPECT_EQ(tz, tz2); +} + +TEST(TimeZone, Equality) { + absl::TimeZone a, b; + EXPECT_EQ(a, b); + EXPECT_EQ(a.name(), b.name()); + + absl::TimeZone implicit_utc; + absl::TimeZone explicit_utc = absl::UTCTimeZone(); + EXPECT_EQ(implicit_utc, explicit_utc); + EXPECT_EQ(implicit_utc.name(), explicit_utc.name()); + + absl::TimeZone la = absl::time_internal::LoadTimeZone("America/Los_Angeles"); + absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York"); + EXPECT_NE(la, nyc); +} + +TEST(TimeZone, CCTZConversion) { + const cctz::time_zone cz = cctz::utc_time_zone(); + const absl::TimeZone tz(cz); + EXPECT_EQ(cz, cctz::time_zone(tz)); +} + +TEST(TimeZone, DefaultTimeZones) { + absl::TimeZone tz; + EXPECT_EQ("UTC", absl::TimeZone().name()); + EXPECT_EQ("UTC", absl::UTCTimeZone().name()); +} + +TEST(TimeZone, FixedTimeZone) { + const absl::TimeZone tz = absl::FixedTimeZone(123); + const cctz::time_zone cz = cctz::fixed_time_zone(cctz::seconds(123)); + EXPECT_EQ(tz, absl::TimeZone(cz)); +} + +TEST(TimeZone, LocalTimeZone) { + const absl::TimeZone local_tz = absl::LocalTimeZone(); + absl::TimeZone tz = absl::time_internal::LoadTimeZone("localtime"); + EXPECT_EQ(tz, local_tz); +} + +TEST(TimeZone, NamedTimeZones) { + absl::TimeZone nyc = absl::time_internal::LoadTimeZone("America/New_York"); + EXPECT_EQ("America/New_York", nyc.name()); + absl::TimeZone syd = absl::time_internal::LoadTimeZone("Australia/Sydney"); + EXPECT_EQ("Australia/Sydney", syd.name()); + absl::TimeZone fixed = absl::FixedTimeZone((((3 * 60) + 25) * 60) + 45); + EXPECT_EQ("Fixed/UTC+03:25:45", fixed.name()); +} + +TEST(TimeZone, Failures) { + absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); + EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz)); + EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC + + // Ensures that the load still fails on a subsequent attempt. + tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); + EXPECT_FALSE(LoadTimeZone("Invalid/TimeZone", &tz)); + EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC + + // Loading an empty string timezone should fail. + tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); + EXPECT_FALSE(LoadTimeZone("", &tz)); + EXPECT_EQ(absl::UTCTimeZone(), tz); // guaranteed fallback to UTC +} + +} // namespace |