diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index d4095fa06d1..5d9de4e898d 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -17,6 +17,7 @@ add_subdirectory (libcityhash) add_subdirectory (libfarmhash) add_subdirectory (libmetrohash) add_subdirectory (libzlib-ng) +add_subdirectory (libcctz) if (ENABLE_LIBTCMALLOC AND USE_INTERNAL_GPERFTOOLS_LIBRARY) add_subdirectory (libtcmalloc) diff --git a/contrib/libcctz/CMakeLists.txt b/contrib/libcctz/CMakeLists.txt new file mode 100644 index 00000000000..8771edef02e --- /dev/null +++ b/contrib/libcctz/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories (include) + +add_library(cctz + src/time_zone_libc.cc + src/time_zone_posix.cc + src/time_zone_lookup.cc + src/time_zone_info.cc + src/time_zone_if.cc + src/time_zone_format.cc + src/time_tool.cc + src/time_zone_impl.cc + + src/time_zone_libc.h + src/time_zone_if.h + src/tzfile.h + src/time_zone_impl.h + src/time_zone_posix.h + src/time_zone_info.h + + include/time_zone.h + include/civil_time_detail.h + include/civil_time.h) diff --git a/contrib/libcctz/src/civil_time_test.cc b/contrib/libcctz/src/civil_time_test.cc deleted file mode 100644 index 8aef10015f1..00000000000 --- a/contrib/libcctz/src/civil_time_test.cc +++ /dev/null @@ -1,1045 +0,0 @@ -// 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 -// -// http://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 "civil_time.h" - -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" - -namespace cctz { - -namespace { - -template -std::string Format(const T& t) { - std::stringstream ss; - ss << t; - return ss.str(); -} - -} // namespace - -#if __clang__ && __cpp_constexpr >= 201304 -// 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, 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 // __clang__ && __cpp_constexpr >= 201304 - -// 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::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::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::value)); - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - - EXPECT_FALSE((std::is_convertible::value)); - EXPECT_FALSE((std::is_convertible::value)); - - EXPECT_FALSE((std::is_convertible::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 -struct HasDifference { - template - static std::false_type test(...); - template - static std::true_type test(decltype(std::declval() - std::declval())); - static constexpr bool value = decltype(test(0))::value; -}; - -TEST(CivilTime, DisallowCrossAlignedDifference) { - // Difference is allowed between types with the same alignment. - static_assert(HasDifference::value, ""); - static_assert(HasDifference::value, ""); - static_assert(HasDifference::value, ""); - static_assert(HasDifference::value, ""); - static_assert(HasDifference::value, ""); - static_assert(HasDifference::value, ""); - - // Difference is disallowed between types with different alignments. - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - - static_assert(!HasDifference::value, ""); - static_assert(!HasDifference::value, ""); - - static_assert(!HasDifference::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 CivilTime 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::max(); - const int kIntMin = std::numeric_limits::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, Difference) { - 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::max(); - const int kIntMin = std::numeric_limits::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()); - - 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()); - - 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()); - - 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()); - - 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()); -} - -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 = prev_weekday(nov1, weekday::thursday) + 7; - 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 diff --git a/contrib/libcctz/src/time_zone_format_test.cc b/contrib/libcctz/src/time_zone_format_test.cc deleted file mode 100644 index be757f1874e..00000000000 --- a/contrib/libcctz/src/time_zone_format_test.cc +++ /dev/null @@ -1,1263 +0,0 @@ -// 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 -// -// http://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.h" - -#include -#include -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using std::chrono::time_point_cast; -using std::chrono::system_clock; -using std::chrono::nanoseconds; -using std::chrono::microseconds; -using std::chrono::milliseconds; -using std::chrono::seconds; -using std::chrono::minutes; -using std::chrono::hours; -using testing::HasSubstr; - -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_EQ(zone, al.abbr); \ - } while (0) - -const char RFC3339_full[] = "%Y-%m-%dT%H:%M:%E*S%Ez"; -const char RFC3339_sec[] = "%Y-%m-%dT%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 -void TestFormatSpecifier(time_point 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 t0 = system_clock::from_time_t(1420167845) + - milliseconds(123) + microseconds(456) + - nanoseconds(789); - EXPECT_EQ("03:04:05.123456789", - format(kFmt, time_point_cast(t0), utc)); - EXPECT_EQ("03:04:05.123456", - format(kFmt, time_point_cast(t0), utc)); - EXPECT_EQ("03:04:05.123", - format(kFmt, time_point_cast(t0), utc)); - EXPECT_EQ("03:04:05", - format(kFmt, time_point_cast(t0), utc)); - EXPECT_EQ("03:04:05", - format(kFmt, time_point_cast(t0), utc)); - EXPECT_EQ("03:04:00", - format(kFmt, time_point_cast(t0), utc)); - EXPECT_EQ("03:00:00", - format(kFmt, time_point_cast(t0), utc)); -} - -TEST(Format, TimePointExtendedResolution) { - const char kFmt[] = "%H:%M:%E*S"; - const time_zone utc = utc_time_zone(); - const time_point tp = - std::chrono::time_point_cast( - std::chrono::system_clock::from_time_t(0)) + - std::chrono::hours(12) + std::chrono::minutes(34) + - std::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 tp = 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 += hours(13) + minutes(4) + seconds(5); - tp += milliseconds(6) + microseconds(7) + 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 = 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"); - TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday - 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 = 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, HasSubstr("1970")); - EXPECT_THAT(s, 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 = 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 tp = system_clock::from_time_t(0); - tp += 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 += milliseconds(6) + microseconds(7) + 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 = system_clock::from_time_t(0) + 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 = system_clock::from_time_t(0) + microseconds(1395024427333304); - EXPECT_EQ("2014-03-17 02:47:07.333304", - format("%Y-%m-%d %H:%M:%E*S", tp, tz)); - tp += 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 tp = system_clock::from_time_t(0); - tp += 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 += milliseconds(6) + microseconds(7) + 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 = system_clock::from_time_t(0) + 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 = system_clock::from_time_t(0) + microseconds(1395024427333304); - EXPECT_EQ("2014-03-17 02:47:07.333304", - format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz)); - tp += 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: %ES - // fmt_B: %S.%Ef - 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 tp = system_clock::from_time_t(0); - tp += 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)); - // ... %ES and %S.%Ef 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 += milliseconds(6) + microseconds(7) + 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)); - // ... %ES and %S.%Ef 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) { - auto tp = system_clock::from_time_t(0); - - time_zone tz = utc_time_zone(); - TestFormatSpecifier(tp, tz, "%Ez", "+00:00"); - - EXPECT_TRUE(load_time_zone("America/New_York", &tz)); - TestFormatSpecifier(tp, tz, "%Ez", "-05:00"); - - EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz)); - TestFormatSpecifier(tp, tz, "%Ez", "-08:00"); - - EXPECT_TRUE(load_time_zone("Australia/Sydney", &tz)); - TestFormatSpecifier(tp, tz, "%Ez", "+10:00"); - - EXPECT_TRUE(load_time_zone("Africa/Monrovia", &tz)); - // The true offset is -00:44:30 but %z only gives (truncated) minutes. - TestFormatSpecifier(tp, tz, "%z", "-0044"); - TestFormatSpecifier(tp, tz, "%Ez", "-00:44"); -} - -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 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 += 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 += 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 += 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 += 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 += 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 += 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 += 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 += 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 += 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)); -} - -// -// Testing parse() -// - -TEST(Parse, TimePointResolution) { - const char kFmt[] = "%H:%M:%E*S"; - const time_zone utc = utc_time_zone(); - - time_point 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 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 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 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 tp_m; - EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m)); - EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc)); - - time_point 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 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 tp = system_clock::from_time_t(1234567890); - - // Simple edge cases. - EXPECT_TRUE(parse("", "", tz, &tp)); - EXPECT_EQ(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 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() returns - // the preferred-offset result, as defined for ConvertDateTime(). - 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() returns - // the preferred-offset result, as defined for ConvertDateTime(). - 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 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 = 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 = 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 - - tp = reset; - EXPECT_TRUE(parse("%C", "20", tz, &tp)); - EXPECT_EQ(2000, convert(tp, tz).year()); - - 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(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(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(system_clock::from_time_t(1414917000), tp); - tp = reset; - EXPECT_TRUE(parse("%s", "1414920600", lax, &tp)); - EXPECT_EQ(system_clock::from_time_t(1414920600), tp); -#endif -} - -TEST(Parse, LocaleSpecific) { - time_zone tz = utc_time_zone(); - auto tp = 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)); - 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("%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("%EC", "20", tz, &tp)); - EXPECT_EQ(2000, convert(tp, tz).year()); - - 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 %Ey case. -#if 0 - tp = reset; - EXPECT_TRUE(parse("%Ey", "04", tz, &tp)); - EXPECT_EQ(2004, convert(tp, tz).year()); -#endif - - 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 unix_epoch = system_clock::from_time_t(0); - - // All %ES 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 tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "5", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.0", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.00", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.6", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5) + milliseconds(600), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.60", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5) + milliseconds(600), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.600", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5) + milliseconds(600), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.67", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5) + milliseconds(670), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.670", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5) + milliseconds(670), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "05.678", tz, &tp)); - EXPECT_EQ(unix_epoch + seconds(5) + 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 tp = unix_epoch; - EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp)); - EXPECT_EQ(unix_epoch + nanoseconds(214748364), tp); - tp = unix_epoch; - EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp)); - EXPECT_EQ(unix_epoch + 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 + nanoseconds(214748364), tp); -} - -TEST(Parse, ExtendedSecondsScan) { - const time_zone tz = utc_time_zone(); - time_point 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 = - system_clock::from_time_t(0) + 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 unix_epoch = system_clock::from_time_t(0); - - // All %Ef 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 tp = unix_epoch - 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 + milliseconds(600), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "60", tz, &tp)); - EXPECT_EQ(unix_epoch + milliseconds(600), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "600", tz, &tp)); - EXPECT_EQ(unix_epoch + milliseconds(600), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "67", tz, &tp)); - EXPECT_EQ(unix_epoch + milliseconds(670), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "670", tz, &tp)); - EXPECT_EQ(unix_epoch + milliseconds(670), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "678", tz, &tp)); - EXPECT_EQ(unix_epoch + milliseconds(678), tp); - tp = unix_epoch; - EXPECT_TRUE(parse(fmt, "6789", tz, &tp)); - EXPECT_EQ(unix_epoch + milliseconds(678) + 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 tp = unix_epoch; - EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp)); - EXPECT_EQ(unix_epoch + nanoseconds(214748364), tp); - tp = unix_epoch; - EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp)); - EXPECT_EQ(unix_epoch + 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 + nanoseconds(214748364), tp); -} - -TEST(Parse, ExtendedSubecondsScan) { - time_point 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 = - system_clock::from_time_t(0) + nanoseconds(micros * 1000 + ns); - for (int ps = 0; ps < 1000; ps += 250) { - std::ostringstream oss; - oss << std::setfill('0') << std::setw(3) << ps; - const std::string input = nanos + oss.str() + "999"; - EXPECT_TRUE(parse("%E*f", input, tz, &tp)); - EXPECT_EQ(expected + nanoseconds(ps) / 1000, tp) << input; - } - } - } - } -} - -TEST(Parse, ExtendedOffset) { - const time_zone utc = utc_time_zone(); - time_point tp; - - // %z against +-HHMM. - EXPECT_TRUE(parse("%z", "+0000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%z", "-1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); - EXPECT_TRUE(parse("%z", "+1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); - EXPECT_FALSE(parse("%z", "-123", utc, &tp)); - - // %z against +-HH. - EXPECT_TRUE(parse("%z", "+00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%z", "-12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); - EXPECT_TRUE(parse("%z", "+12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); - EXPECT_FALSE(parse("%z", "-1", utc, &tp)); - - // %Ez against +-HH:MM. - 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)); - - // %Ez against +-HHMM. - EXPECT_TRUE(parse("%Ez", "+0000", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "-1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "+1234", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp); - EXPECT_FALSE(parse("%Ez", "-123", utc, &tp)); - - // %Ez against +-HH. - EXPECT_TRUE(parse("%Ez", "+00", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "-12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp); - EXPECT_TRUE(parse("%Ez", "+12", utc, &tp)); - EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp); - EXPECT_FALSE(parse("%Ez", "-1", utc, &tp)); -} - -TEST(Parse, ExtendedYears) { - const time_zone utc = utc_time_zone(); - const char e4y_fmt[] = "%E4Y%m%d"; // no separators - time_point 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 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 %Ez also accepts "Z" as a synonym for "+00:00". - time_point tp2; - EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp2)); - EXPECT_EQ(tp, tp2); -} - -// -// 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 = nanoseconds(654321); - - // RFC3339, which renders subseconds. - { - time_point 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 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 - } - - // Even though we don't know what %c will produce, it should roundtrip, - // but only in the 0-offset timezone. - { - time_point 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); - } -} - -TEST(FormatParse, RoundTripDistantFuture) { - const time_zone utc = utc_time_zone(); - const time_point in = time_point::max(); - const std::string s = format(RFC3339_full, in, utc); - time_point 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 in = time_point::min(); - const std::string s = format(RFC3339_full, in, utc); - time_point out; - EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s; - EXPECT_EQ(in, out); -} - -} // namespace cctz diff --git a/contrib/libcctz/src/time_zone_lookup_test.cc b/contrib/libcctz/src/time_zone_lookup_test.cc deleted file mode 100644 index 57fc95966d7..00000000000 --- a/contrib/libcctz/src/time_zone_lookup_test.cc +++ /dev/null @@ -1,1094 +0,0 @@ -// 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 -// -// http://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.h" - -#include -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" - -using std::chrono::system_clock; - -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/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/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/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/East-Saskatchewan", - "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/Pacific-New", - "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_EQ(zone, al.abbr); \ - } while (0) - -} // namespace - -TEST(TimeZones, LoadZonesConcurrently) { - std::promise ready_promise; - std::shared_future ready_future(ready_promise.get_future()); - auto load_zones = [ready_future](std::promise* started) { - started->set_value(); - ready_future.wait(); - time_zone tz; - for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) { - EXPECT_TRUE(load_time_zone(*np, &tz)); - EXPECT_EQ(*np, tz.name()); - } - }; - - std::vector threads; - for (std::size_t i = 0; i != 256; ++i) { - std::promise started; - threads.emplace_back(load_zones, &started); - started.get_future().wait(); - } - - ready_promise.set_value(); - - for (auto& thread : threads) { - thread.join(); - } -} - -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(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(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(system_clock::from_time_t(0), - convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC -} - -TEST(TimeZone, Equality) { - time_zone a, b; - EXPECT_EQ(a, b); - EXPECT_EQ(a.name(), b.name()); - - time_zone implicit_utc; - time_zone explicit_utc = utc_time_zone(); - EXPECT_EQ(implicit_utc, explicit_utc); - EXPECT_EQ(implicit_utc.name(), explicit_utc.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. - using TP = std::chrono::system_clock::time_point; - auto diff = TP() - std::chrono::system_clock::from_time_t(0); - EXPECT_EQ(TP::duration::zero(), diff % std::chrono::seconds(1)); -} - -TEST(BreakTime, TimePointResolution) { - using std::chrono::time_point_cast; - const time_zone utc = utc_time_zone(); - const auto t0 = system_clock::from_time_t(0); - - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - ExpectTime(time_point_cast(t0), utc, - 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); -} - -TEST(BreakTime, LocalTimeInUTC) { - const auto tp = system_clock::from_time_t(0); - const time_zone::absolute_lookup al = utc_time_zone().lookup(tp); - ExpectTime(tp, utc_time_zone(), 1970, 1, 1, 0, 0, 0, 0, false, "UTC"); - EXPECT_EQ(weekday::thursday, - get_weekday(civil_day(convert(tp, utc_time_zone())))); -} - -TEST(BreakTime, LocalTimePosix) { - // See IEEE Std 1003.1-1988 B.2.3 General Terms, Epoch. - const auto tp = system_clock::from_time_t(536457599); - const time_zone::absolute_lookup al = utc_time_zone().lookup(tp); - ExpectTime(tp, utc_time_zone(), 1986, 12, 31, 23, 59, 59, 0, false, "UTC"); - EXPECT_EQ(weekday::wednesday, - get_weekday(civil_day(convert(tp, utc_time_zone())))); -} - -TEST(BreakTime, LocalTimeInNewYork) { - const time_zone tz = LoadZone("America/New_York"); - const auto tp = 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(civil_day(convert(tp, tz)))); -} - -TEST(BreakTime, LocalTimeInMTV) { - const time_zone tz = LoadZone("America/Los_Angeles"); - const auto tp = 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(civil_day(convert(tp, tz)))); -} - -TEST(BreakTime, LocalTimeInSydney) { - const time_zone tz = LoadZone("Australia/Sydney"); - const auto tp = system_clock::from_time_t(90); - const time_zone::absolute_lookup al = tz.lookup(tp); - ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST"); - EXPECT_EQ(weekday::thursday, get_weekday(civil_day(convert(tp, tz)))); -} - -TEST(MakeTime, TimePointResolution) { - const time_zone utc = utc_time_zone(); - const time_point 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 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 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 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 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 time_point_cast because the conversion from a - // resolution of seconds (the return value of convert()) to a coarser - // resolution requires an explicit cast. - using std::chrono::time_point_cast; - const time_point tp_m = - time_point_cast( - convert(civil_second(2015, 1, 2, 3, 4, 5), utc)); - EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc)); - const time_point tp_h = - time_point_cast( - 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(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 -} - -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 += std::chrono::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 += std::chrono::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 += std::chrono::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 += std::chrono::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 += std::chrono::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 += std::chrono::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 (IST) - // 504901800 == Wed, 1 Jan 1986 00:15:00 +0545 (NPT) - 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, "IST"); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 1986, 1, 1, 0, 15, 0, 5.75 * 3600, false, "NPT"); -} - -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 (CHADT) - // 1365256800 == Sun, 7 Apr 2013 02:45:00 +1245 (CHAST) - 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, "CHADT"); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 2013, 4, 7, 2, 45, 0, 12.75 * 3600, false, "CHAST"); - - // 1380376799 == Sun, 29 Sep 2013 02:44:59 +1245 (CHAST) - // 1380376800 == Sun, 29 Sep 2013 03:45:00 +1345 (CHADT) - tp = convert(civil_second(2013, 9, 29, 2, 44, 59), tz); - ExpectTime(tp, tz, 2013, 9, 29, 2, 44, 59, 12.75 * 3600, false, - "CHAST"); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 2013, 9, 29, 3, 45, 0, 13.75 * 3600, true, "CHADT"); -} - -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 (LHDT) - // 1365260400 == Sun, 7 Apr 2013 01:30:00 +1030 (LHST) - auto tp = convert(civil_second(2013, 4, 7, 1, 59, 59), tz); - ExpectTime(tp, tz, 2013, 4, 7, 1, 59, 59, 11 * 3600, true, "LHDT"); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 2013, 4, 7, 1, 30, 0, 10.5 * 3600, false, "LHST"); - - // 1380986999 == Sun, 6 Oct 2013 01:59:59 +1030 (LHST) - // 1380987000 == Sun, 6 Oct 2013 02:30:00 +1100 (LHDT) - tp = convert(civil_second(2013, 10, 6, 1, 59, 59), tz); - ExpectTime(tp, tz, 2013, 10, 6, 1, 59, 59, 10.5 * 3600, false, "LHST"); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 2013, 10, 6, 2, 30, 0, 11 * 3600, true, "LHDT"); -} - -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 (SDT) - // 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (WSDT) - auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz); - ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "SDT"); - EXPECT_EQ(363, get_yearday(civil_day(convert(tp, tz)))); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "WSDT"); - EXPECT_EQ(365, get_yearday(civil_day(convert(tp, tz)))); -} - -TEST(TimeZoneEdgeCase, AfricaCairo) { - const time_zone tz = LoadZone("Africa/Cairo"); - - // 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 += std::chrono::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"); - - // Strange offset change -00:44:30 -> +00:00:00 (non-DST) - // - // 73529069 == Sun, 30 Apr 1972 23:59:59 -0044 (LRT) - // 73529070 == Mon, 1 May 1972 00:44:30 +0000 (GMT) - auto tp = convert(civil_second(1972, 4, 30, 23, 59, 59), tz); - ExpectTime(tp, tz, 1972, 4, 30, 23, 59, 59, -44.5 * 60, false, "LRT"); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 1972, 5, 1, 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. - auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz); - ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18431, 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, -18431, false, - tz.lookup(tp).abbr); - tp += std::chrono::seconds(1); - ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18431, 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) - 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 += std::chrono::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 += std::chrono::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(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(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); - time_zone::absolute_lookup al = tz.lookup(tp); - ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC"); - EXPECT_EQ(weekday::saturday, get_weekday(civil_day(convert(tp, tz)))); - tp -= std::chrono::seconds(1); - ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC"); - EXPECT_EQ(weekday::friday, get_weekday(civil_day(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 += std::chrono::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 += std::chrono::seconds(1); - ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC"); -} - -} // namespace cctz