aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/cctz/test
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/libs/cctz/test
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
downloadydb-718c552901d703c502ccbefdfc3c9028d608b947.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/cctz/test')
-rw-r--r--contrib/libs/cctz/test/civil_time_test.cc72
-rw-r--r--contrib/libs/cctz/test/time_zone_format_test.cc3176
-rw-r--r--contrib/libs/cctz/test/time_zone_lookup_test.cc694
-rw-r--r--contrib/libs/cctz/test/ya.make20
4 files changed, 1981 insertions, 1981 deletions
diff --git a/contrib/libs/cctz/test/civil_time_test.cc b/contrib/libs/cctz/test/civil_time_test.cc
index 5ec0ca8d38..0b13cc1b7a 100644
--- a/contrib/libs/cctz/test/civil_time_test.cc
+++ b/contrib/libs/cctz/test/civil_time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "cctz/civil_time.h"
+#include "cctz/civil_time.h"
#include <iomanip>
#include <limits>
@@ -20,7 +20,7 @@
#include <string>
#include <type_traits>
-#include "gtest/gtest.h"
+#include "gtest/gtest.h"
namespace cctz {
@@ -35,7 +35,7 @@ std::string Format(const T& t) {
} // namespace
-#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
+#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
// Construction constexpr tests
TEST(CivilTime, Normal) {
@@ -223,7 +223,7 @@ TEST(CivilTime, Subtraction) {
static_assert(cs2.second() == 22, "Subtraction.second");
}
-TEST(CivilTime, Difference) {
+TEST(CivilTime, Difference) {
constexpr civil_day cd1(2016, 1, 28);
constexpr civil_day cd2(2015, 1, 28);
constexpr int diff = cd1 - cd2;
@@ -231,16 +231,16 @@ TEST(CivilTime, Difference) {
}
// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
-TEST(CivilTime, ConstructionWithHugeYear) {
- constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
- static_assert(h.year() == -9223372036854775807 - 1,
- "ConstructionWithHugeYear");
- static_assert(h.month() == 12, "ConstructionWithHugeYear");
- static_assert(h.day() == 31, "ConstructionWithHugeYear");
- static_assert(h.hour() == 23, "ConstructionWithHugeYear");
-}
-
-// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, ConstructionWithHugeYear) {
+ constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
+ static_assert(h.year() == -9223372036854775807 - 1,
+ "ConstructionWithHugeYear");
+ static_assert(h.month() == 12, "ConstructionWithHugeYear");
+ static_assert(h.day() == 31, "ConstructionWithHugeYear");
+ static_assert(h.hour() == 23, "ConstructionWithHugeYear");
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
TEST(CivilTime, DifferenceWithHugeYear) {
{
constexpr civil_day d1(9223372036854775807, 1, 1);
@@ -327,7 +327,7 @@ TEST(CivilTime, YearDay) {
constexpr int yd = get_yearday(cd);
static_assert(yd == 28, "YearDay");
}
-#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
+#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
// The remaining tests do not use constexpr.
@@ -628,7 +628,7 @@ TEST(CivilTime, Relational) {
TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 1, 0),
civil_second(2014, 1, 1, 1, 1, 1));
- // Tests the relational operators of two different civil-time types.
+ // Tests the relational operators of two different civil-time types.
TEST_RELATIONAL(civil_day(2014, 1, 1), civil_minute(2014, 1, 1, 1, 1));
TEST_RELATIONAL(civil_day(2014, 1, 1), civil_month(2014, 2));
@@ -768,7 +768,7 @@ TEST(CivilTime, ArithmeticLimits) {
EXPECT_EQ("0", Format(year));
}
-TEST(CivilTime, ArithmeticDifference) {
+TEST(CivilTime, ArithmeticDifference) {
civil_second second(2015, 1, 2, 3, 4, 5);
EXPECT_EQ(0, second - second);
EXPECT_EQ(10, (second + 10) - second);
@@ -829,8 +829,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, ss.hour());
EXPECT_EQ(5, ss.minute());
EXPECT_EQ(6, ss.second());
- EXPECT_EQ(weekday::tuesday, get_weekday(ss));
- EXPECT_EQ(34, get_yearday(ss));
+ EXPECT_EQ(weekday::tuesday, get_weekday(ss));
+ EXPECT_EQ(34, get_yearday(ss));
civil_minute mm(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, mm.year());
@@ -839,8 +839,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, mm.hour());
EXPECT_EQ(5, mm.minute());
EXPECT_EQ(0, mm.second());
- EXPECT_EQ(weekday::tuesday, get_weekday(mm));
- EXPECT_EQ(34, get_yearday(mm));
+ EXPECT_EQ(weekday::tuesday, get_weekday(mm));
+ EXPECT_EQ(34, get_yearday(mm));
civil_hour hh(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, hh.year());
@@ -849,8 +849,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, hh.hour());
EXPECT_EQ(0, hh.minute());
EXPECT_EQ(0, hh.second());
- EXPECT_EQ(weekday::tuesday, get_weekday(hh));
- EXPECT_EQ(34, get_yearday(hh));
+ EXPECT_EQ(weekday::tuesday, get_weekday(hh));
+ EXPECT_EQ(34, get_yearday(hh));
civil_day d(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, d.year());
@@ -869,8 +869,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, m.hour());
EXPECT_EQ(0, m.minute());
EXPECT_EQ(0, m.second());
- EXPECT_EQ(weekday::sunday, get_weekday(m));
- EXPECT_EQ(32, get_yearday(m));
+ EXPECT_EQ(weekday::sunday, get_weekday(m));
+ EXPECT_EQ(32, get_yearday(m));
civil_year y(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, y.year());
@@ -879,8 +879,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, y.hour());
EXPECT_EQ(0, y.minute());
EXPECT_EQ(0, y.second());
- EXPECT_EQ(weekday::thursday, get_weekday(y));
- EXPECT_EQ(1, get_yearday(y));
+ EXPECT_EQ(weekday::thursday, get_weekday(y));
+ EXPECT_EQ(1, get_yearday(y));
}
TEST(CivilTime, OutputStream) {
@@ -966,37 +966,37 @@ TEST(CivilTime, NextPrevWeekday) {
// Thursday -> Thursday
civil_day d = next_weekday(thursday, weekday::thursday);
- EXPECT_EQ(7, d - thursday) << Format(d);
+ 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(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(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(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(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(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(6, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::wednesday));
}
@@ -1053,7 +1053,7 @@ TEST(CivilTime, LeapYears) {
TEST(CivilTime, FirstThursdayInMonth) {
const civil_day nov1(2014, 11, 1);
- const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
+ const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
EXPECT_EQ("2014-11-06", Format(thursday));
// Bonus: Date of Thanksgiving in the United States
diff --git a/contrib/libs/cctz/test/time_zone_format_test.cc b/contrib/libs/cctz/test/time_zone_format_test.cc
index 0d07dad5c0..724836fa14 100644
--- a/contrib/libs/cctz/test/time_zone_format_test.cc
+++ b/contrib/libs/cctz/test/time_zone_format_test.cc
@@ -1,1588 +1,1588 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cctz/time_zone.h"
-
-#include <chrono>
-#include <iomanip>
-#include <sstream>
-#include <string>
-
-#include "cctz/civil_time.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace chrono = std::chrono;
-
-namespace cctz {
-
-namespace {
-
-// This helper is a macro so that failed expectations show up with the
-// correct line numbers.
-#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \
- do { \
- time_zone::absolute_lookup al = tz.lookup(tp); \
- EXPECT_EQ(y, al.cs.year()); \
- EXPECT_EQ(m, al.cs.month()); \
- EXPECT_EQ(d, al.cs.day()); \
- EXPECT_EQ(hh, al.cs.hour()); \
- EXPECT_EQ(mm, al.cs.minute()); \
- EXPECT_EQ(ss, al.cs.second()); \
- EXPECT_EQ(off, al.offset); \
- EXPECT_TRUE(isdst == al.is_dst); \
- EXPECT_STREQ(zone, al.abbr); \
- } while (0)
-
-const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
-const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
-
-const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
-const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
-
-// A helper that tests the given format specifier by itself, and with leading
-// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu").
-template <typename D>
-void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt,
- const std::string& ans) {
- EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt;
- EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz));
- EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz));
- EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
-}
-
-} // namespace
-
-//
-// Testing format()
-//
-
-TEST(Format, TimePointResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
- const time_point<chrono::nanoseconds> t0 =
- chrono::system_clock::from_time_t(1420167845) +
- chrono::milliseconds(123) + chrono::microseconds(456) +
- chrono::nanoseconds(789);
- EXPECT_EQ(
- "03:04:05.123456789",
- format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc));
- EXPECT_EQ(
- "03:04:05.123456",
- format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc));
- EXPECT_EQ(
- "03:04:05.123",
- format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
- EXPECT_EQ("03:04:05",
- format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
- EXPECT_EQ("03:04:05",
- format(kFmt, chrono::time_point_cast<cctz::seconds>(t0), utc));
- EXPECT_EQ("03:04:00",
- format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
- EXPECT_EQ("03:00:00",
- format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc));
-}
-
-TEST(Format, TimePointExtendedResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
- const time_point<cctz::seconds> tp =
- chrono::time_point_cast<cctz::seconds>(
- chrono::system_clock::from_time_t(0)) +
- chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56);
-
- EXPECT_EQ(
- "12:34:56.123456789012345",
- detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc));
- EXPECT_EQ(
- "12:34:56.012345678901234",
- detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
- EXPECT_EQ(
- "12:34:56.001234567890123",
- detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
- EXPECT_EQ(
- "12:34:56.000123456789012",
- detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
-
- EXPECT_EQ("12:34:56.000000000000123",
- detail::format(kFmt, tp, detail::femtoseconds(123), utc));
- EXPECT_EQ("12:34:56.000000000000012",
- detail::format(kFmt, tp, detail::femtoseconds(12), utc));
- EXPECT_EQ("12:34:56.000000000000001",
- detail::format(kFmt, tp, detail::femtoseconds(1), utc));
-}
-
-TEST(Format, Basics) {
- time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
-
- // Starts with a couple basic edge cases.
- EXPECT_EQ("", format("", tp, tz));
- EXPECT_EQ(" ", format(" ", tp, tz));
- EXPECT_EQ(" ", format(" ", tp, tz));
- EXPECT_EQ("xxx", format("xxx", tp, tz));
- std::string big(128, 'x');
- EXPECT_EQ(big, format(big, tp, tz));
- // Cause the 1024-byte buffer to grow.
- std::string bigger(100000, 'x');
- EXPECT_EQ(bigger, format(bigger, tp, tz));
-
- tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5);
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz));
- EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz));
- EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz));
- EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz));
- EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz));
-}
-
-TEST(Format, PosixConversions) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- TestFormatSpecifier(tp, tz, "%d", "01");
- TestFormatSpecifier(tp, tz, "%e", " 1"); // extension but internal support
- TestFormatSpecifier(tp, tz, "%H", "00");
- TestFormatSpecifier(tp, tz, "%I", "12");
- TestFormatSpecifier(tp, tz, "%j", "001");
- TestFormatSpecifier(tp, tz, "%m", "01");
- TestFormatSpecifier(tp, tz, "%M", "00");
- TestFormatSpecifier(tp, tz, "%S", "00");
- TestFormatSpecifier(tp, tz, "%U", "00");
- 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 = chrono::system_clock::from_time_t(0);
-
- TestFormatSpecifier(tp, tz, "%a", "Thu");
- TestFormatSpecifier(tp, tz, "%A", "Thursday");
- TestFormatSpecifier(tp, tz, "%b", "Jan");
- TestFormatSpecifier(tp, tz, "%B", "January");
-
- // %c should at least produce the numeric year and time-of-day.
- const std::string s = format("%c", tp, utc_time_zone());
- EXPECT_THAT(s, testing::HasSubstr("1970"));
- EXPECT_THAT(s, testing::HasSubstr("00:00:00"));
-
- TestFormatSpecifier(tp, tz, "%p", "AM");
- TestFormatSpecifier(tp, tz, "%x", "01/01/70");
- TestFormatSpecifier(tp, tz, "%X", "00:00:00");
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
- TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b
- TestFormatSpecifier(tp, tz, "%P", "am");
- TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM");
-
- // Modified conversion specifiers %E_
- TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan 1 00:00:00 1970");
- TestFormatSpecifier(tp, tz, "%EC", "19");
- TestFormatSpecifier(tp, tz, "%Ex", "01/01/70");
- TestFormatSpecifier(tp, tz, "%EX", "00:00:00");
- TestFormatSpecifier(tp, tz, "%Ey", "70");
- TestFormatSpecifier(tp, tz, "%EY", "1970");
-
- // Modified conversion specifiers %O_
- TestFormatSpecifier(tp, tz, "%Od", "01");
- TestFormatSpecifier(tp, tz, "%Oe", " 1");
- TestFormatSpecifier(tp, tz, "%OH", "00");
- TestFormatSpecifier(tp, tz, "%OI", "12");
- TestFormatSpecifier(tp, tz, "%Om", "01");
- TestFormatSpecifier(tp, tz, "%OM", "00");
- TestFormatSpecifier(tp, tz, "%OS", "00");
- TestFormatSpecifier(tp, tz, "%Ou", "4"); // 4=Thursday
- TestFormatSpecifier(tp, tz, "%OU", "00");
- TestFormatSpecifier(tp, tz, "%OV", "01");
- TestFormatSpecifier(tp, tz, "%Ow", "4"); // 4=Thursday
- TestFormatSpecifier(tp, tz, "%OW", "00");
- TestFormatSpecifier(tp, tz, "%Oy", "70");
-#endif
-}
-
-TEST(Format, Escaping) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- TestFormatSpecifier(tp, tz, "%%", "%");
- TestFormatSpecifier(tp, tz, "%%a", "%a");
- TestFormatSpecifier(tp, tz, "%%b", "%b");
- TestFormatSpecifier(tp, tz, "%%Ea", "%Ea");
- TestFormatSpecifier(tp, tz, "%%Es", "%Es");
- TestFormatSpecifier(tp, tz, "%%E3S", "%E3S");
- TestFormatSpecifier(tp, tz, "%%OS", "%OS");
- TestFormatSpecifier(tp, tz, "%%O3S", "%O3S");
-
- // Multiple levels of escaping.
- TestFormatSpecifier(tp, tz, "%%%Y", "%1970");
- TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000");
- TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S");
-}
-
-TEST(Format, ExtendedSeconds) {
- const time_zone tz = utc_time_zone();
-
- // No subseconds.
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
- tp += chrono::seconds(5);
- EXPECT_EQ("05", format("%E*S", tp, tz));
- EXPECT_EQ("05", format("%E0S", tp, tz));
- EXPECT_EQ("05.0", format("%E1S", tp, tz));
- EXPECT_EQ("05.00", format("%E2S", tp, tz));
- EXPECT_EQ("05.000", format("%E3S", tp, tz));
- EXPECT_EQ("05.0000", format("%E4S", tp, tz));
- EXPECT_EQ("05.00000", format("%E5S", tp, tz));
- EXPECT_EQ("05.000000", format("%E6S", tp, tz));
- EXPECT_EQ("05.0000000", format("%E7S", tp, tz));
- EXPECT_EQ("05.00000000", format("%E8S", tp, tz));
- EXPECT_EQ("05.000000000", format("%E9S", tp, tz));
- EXPECT_EQ("05.0000000000", format("%E10S", tp, tz));
- EXPECT_EQ("05.00000000000", format("%E11S", tp, tz));
- EXPECT_EQ("05.000000000000", format("%E12S", tp, tz));
- EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz));
- EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz));
- EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz));
-
- // With subseconds.
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("05.006007008", format("%E*S", tp, tz));
- EXPECT_EQ("05", format("%E0S", tp, tz));
- EXPECT_EQ("05.0", format("%E1S", tp, tz));
- EXPECT_EQ("05.00", format("%E2S", tp, tz));
- EXPECT_EQ("05.006", format("%E3S", tp, tz));
- EXPECT_EQ("05.0060", format("%E4S", tp, tz));
- EXPECT_EQ("05.00600", format("%E5S", tp, tz));
- EXPECT_EQ("05.006007", format("%E6S", tp, tz));
- EXPECT_EQ("05.0060070", format("%E7S", tp, tz));
- EXPECT_EQ("05.00600700", format("%E8S", tp, tz));
- EXPECT_EQ("05.006007008", format("%E9S", tp, tz));
- EXPECT_EQ("05.0060070080", format("%E10S", tp, tz));
- EXPECT_EQ("05.00600700800", format("%E11S", tp, tz));
- EXPECT_EQ("05.006007008000", format("%E12S", tp, tz));
- EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz));
- EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz));
- EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz));
-
- // Times before the Unix epoch.
- tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
- EXPECT_EQ("1969-12-31 23:59:59.999999",
- format("%Y-%m-%d %H:%M:%E*S", tp, tz));
-
- // Here is a "%E*S" case we got wrong for a while. While the first
- // instant below is correctly rendered as "...:07.333304", the second
- // one used to appear as "...:07.33330499999999999".
- tp = chrono::system_clock::from_time_t(0) +
- chrono::microseconds(1395024427333304);
- EXPECT_EQ("2014-03-17 02:47:07.333304",
- format("%Y-%m-%d %H:%M:%E*S", tp, tz));
- tp += chrono::microseconds(1);
- EXPECT_EQ("2014-03-17 02:47:07.333305",
- format("%Y-%m-%d %H:%M:%E*S", tp, tz));
-}
-
-TEST(Format, ExtendedSubeconds) {
- const time_zone tz = utc_time_zone();
-
- // No subseconds.
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
- tp += chrono::seconds(5);
- EXPECT_EQ("0", format("%E*f", tp, tz));
- EXPECT_EQ("", format("%E0f", tp, tz));
- EXPECT_EQ("0", format("%E1f", tp, tz));
- EXPECT_EQ("00", format("%E2f", tp, tz));
- EXPECT_EQ("000", format("%E3f", tp, tz));
- EXPECT_EQ("0000", format("%E4f", tp, tz));
- EXPECT_EQ("00000", format("%E5f", tp, tz));
- EXPECT_EQ("000000", format("%E6f", tp, tz));
- EXPECT_EQ("0000000", format("%E7f", tp, tz));
- EXPECT_EQ("00000000", format("%E8f", tp, tz));
- EXPECT_EQ("000000000", format("%E9f", tp, tz));
- EXPECT_EQ("0000000000", format("%E10f", tp, tz));
- EXPECT_EQ("00000000000", format("%E11f", tp, tz));
- EXPECT_EQ("000000000000", format("%E12f", tp, tz));
- EXPECT_EQ("0000000000000", format("%E13f", tp, tz));
- EXPECT_EQ("00000000000000", format("%E14f", tp, tz));
- EXPECT_EQ("000000000000000", format("%E15f", tp, tz));
-
- // With subseconds.
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("006007008", format("%E*f", tp, tz));
- EXPECT_EQ("", format("%E0f", tp, tz));
- EXPECT_EQ("0", format("%E1f", tp, tz));
- EXPECT_EQ("00", format("%E2f", tp, tz));
- EXPECT_EQ("006", format("%E3f", tp, tz));
- EXPECT_EQ("0060", format("%E4f", tp, tz));
- EXPECT_EQ("00600", format("%E5f", tp, tz));
- EXPECT_EQ("006007", format("%E6f", tp, tz));
- EXPECT_EQ("0060070", format("%E7f", tp, tz));
- EXPECT_EQ("00600700", format("%E8f", tp, tz));
- EXPECT_EQ("006007008", format("%E9f", tp, tz));
- EXPECT_EQ("0060070080", format("%E10f", tp, tz));
- EXPECT_EQ("00600700800", format("%E11f", tp, tz));
- EXPECT_EQ("006007008000", format("%E12f", tp, tz));
- EXPECT_EQ("0060070080000", format("%E13f", tp, tz));
- EXPECT_EQ("00600700800000", format("%E14f", tp, tz));
- EXPECT_EQ("006007008000000", format("%E15f", tp, tz));
-
- // Times before the Unix epoch.
- tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
- EXPECT_EQ("1969-12-31 23:59:59.999999",
- format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
-
- // Here is a "%E*S" case we got wrong for a while. While the first
- // instant below is correctly rendered as "...:07.333304", the second
- // one used to appear as "...:07.33330499999999999".
- tp = chrono::system_clock::from_time_t(0) +
- chrono::microseconds(1395024427333304);
- EXPECT_EQ("2014-03-17 02:47:07.333304",
- format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
- tp += chrono::microseconds(1);
- EXPECT_EQ("2014-03-17 02:47:07.333305",
- format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
-}
-
-TEST(Format, CompareExtendSecondsVsSubseconds) {
- const time_zone tz = utc_time_zone();
-
- // This test case illustrates the differences/similarities between:
- // fmt_A: %E<prec>S
- // fmt_B: %S.%E<prec>f
- auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; };
- auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; };
-
- // No subseconds:
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
- tp += chrono::seconds(5);
- // ... %E*S and %S.%E*f are different.
- EXPECT_EQ("05", format(fmt_A("*"), tp, tz));
- EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz));
- // ... %E0S and %S.%E0f are different.
- EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
- EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
- // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
- for (int prec = 1; prec <= 15; ++prec) {
- const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
- const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
- EXPECT_EQ(a, b) << "prec=" << prec;
- }
-
- // With subseconds:
- // ... %E*S and %S.%E*f are the same.
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz));
- EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz));
- // ... %E0S and %S.%E0f are different.
- EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
- EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
- // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
- for (int prec = 1; prec <= 15; ++prec) {
- const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
- const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
- EXPECT_EQ(a, b) << "prec=" << prec;
- }
-}
-
-TEST(Format, ExtendedOffset) {
- const auto tp = chrono::system_clock::from_time_t(0);
-
- auto tz = fixed_time_zone(cctz::seconds::zero());
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%:z", "+00:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
-
- tz = fixed_time_zone(chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%:z", "+00:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
-
- tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%:z", "+00:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
-
- tz = fixed_time_zone(chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "+0034");
- TestFormatSpecifier(tp, tz, "%:z", "+00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
-
- tz = fixed_time_zone(-chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "-0034");
- TestFormatSpecifier(tp, tz, "%:z", "-00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
-
- tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+0034");
- TestFormatSpecifier(tp, tz, "%:z", "+00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
-
- tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "-0034");
- TestFormatSpecifier(tp, tz, "%:z", "-00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
-
- tz = fixed_time_zone(chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%z", "+1200");
- TestFormatSpecifier(tp, tz, "%:z", "+12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
-
- tz = fixed_time_zone(-chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%z", "-1200");
- TestFormatSpecifier(tp, tz, "%:z", "-12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+1200");
- TestFormatSpecifier(tp, tz, "%:z", "+12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "-1200");
- TestFormatSpecifier(tp, tz, "%:z", "-12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "+1234");
- TestFormatSpecifier(tp, tz, "%:z", "+12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "-1234");
- TestFormatSpecifier(tp, tz, "%:z", "-12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+1234");
- TestFormatSpecifier(tp, tz, "%:z", "+12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "-1234");
- TestFormatSpecifier(tp, tz, "%:z", "-12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
-}
-
-TEST(Format, ExtendedSecondOffset) {
- const auto tp = chrono::system_clock::from_time_t(0);
-
- auto tz = fixed_time_zone(cctz::seconds::zero());
- TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00");
- TestFormatSpecifier(tp, tz, "%::z", "+00:00:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+00");
-
- tz = fixed_time_zone(chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "+00:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56");
-
- tz = fixed_time_zone(-chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "-00:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56");
-
- tz = fixed_time_zone(chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "+00:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+00:34");
-
- tz = fixed_time_zone(-chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "-00:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "-00:34");
-
- tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "+00:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56");
-
- tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "-00:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56");
-
- tz = fixed_time_zone(chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00");
- TestFormatSpecifier(tp, tz, "%::z", "+12:00:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+12");
-
- tz = fixed_time_zone(-chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00");
- TestFormatSpecifier(tp, tz, "%::z", "-12:00:00");
- TestFormatSpecifier(tp, tz, "%:::z", "-12");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "+12:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "-12:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "+12:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+12:34");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "-12:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "-12:34");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "+12:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "-12:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56");
-}
-
-TEST(Format, ExtendedYears) {
- const time_zone utc = utc_time_zone();
- const char e4y_fmt[] = "%E4Y%m%d"; // no separators
-
- // %E4Y zero-pads the year to produce at least 4 chars, including the sign.
- auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00001127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00011127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00091127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("09991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("99991127", format(e4y_fmt, tp, utc));
-
- // When the year is outside [-999:9999], more than 4 chars are produced.
- tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("100001127", format(e4y_fmt, tp, utc));
-}
-
-TEST(Format, RFC3339Format) {
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
-
- time_point<chrono::nanoseconds> tp =
- convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::milliseconds(100);
- EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::milliseconds(20);
- EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::milliseconds(3);
- EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::microseconds(400);
- EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::microseconds(50);
- EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::microseconds(6);
- EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::nanoseconds(700);
- EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::nanoseconds(80);
- EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::nanoseconds(9);
- EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00",
- format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-}
-
-TEST(Format, RFC1123Format) { // locale specific
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
-
- auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
- EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz));
- EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
-}
-
-TEST(Format, Week) {
- const time_zone utc = utc_time_zone();
-
- auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
- EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
- EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
- EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
-}
-
-//
-// Testing parse()
-//
-
-TEST(Parse, TimePointResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
-
- time_point<chrono::nanoseconds> tp_ns;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns));
- EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns));
- EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc));
-
- time_point<chrono::microseconds> tp_us;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us));
- EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us));
- EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us));
- EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc));
-
- time_point<chrono::milliseconds> tp_ms;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms));
- EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms));
- EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms));
- EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc));
-
- time_point<chrono::seconds> tp_s;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s));
- EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s));
- EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
-
- time_point<chrono::minutes> tp_m;
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m));
- EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc));
-
- time_point<chrono::hours> tp_h;
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h));
- EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc));
-}
-
-TEST(Parse, TimePointExtendedResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
-
- time_point<cctz::seconds> tp;
- detail::femtoseconds fs;
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc));
-}
-
-TEST(Parse, Basics) {
- time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp =
- chrono::system_clock::from_time_t(1234567890);
-
- // Simple edge cases.
- EXPECT_TRUE(parse("", "", tz, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(0), tp); // everything defaulted
- EXPECT_TRUE(parse(" ", " ", tz, &tp));
- EXPECT_TRUE(parse(" ", " ", tz, &tp));
- EXPECT_TRUE(parse("x", "x", tz, &tp));
- EXPECT_TRUE(parse("xxx", "xxx", tz, &tp));
-
- EXPECT_TRUE(
- parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC");
-}
-
-TEST(Parse, WithTimeZone) {
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
- time_point<chrono::nanoseconds> tp;
-
- // We can parse a string without a UTC offset if we supply a timezone.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
-
- // But the timezone is ignored when a UTC offset is present.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800",
- utc_time_zone(), &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT");
-
- // Check a skipped time (a Spring DST transition). parse() uses the
- // pre-transition offset.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp));
- ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT");
-
- // Check a repeated time (a Fall DST transition). parse() uses the
- // pre-transition offset.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp));
- ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT");
-}
-
-TEST(Parse, LeapSecond) {
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
- time_point<chrono::nanoseconds> tp;
-
- // ":59" -> ":59"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
-
- // ":59.5" -> ":59.5"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
-
- // ":60" -> ":00"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
-
- // ":60.5" -> ":00.0"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
-
- // ":61" -> error
- EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp));
-}
-
-TEST(Parse, ErrorCases) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- // Illegal trailing data.
- EXPECT_FALSE(parse("%S", "123", tz, &tp));
-
- // Can't parse an illegal format specifier.
- EXPECT_FALSE(parse("%Q", "x", tz, &tp));
-
- // Fails because of trailing, unparsed data "blah".
- EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp));
-
- // Trailing whitespace is allowed.
- EXPECT_TRUE(parse("%m-%d", "2-3 ", tz, &tp));
- EXPECT_EQ(2, convert(tp, utc_time_zone()).month());
- EXPECT_EQ(3, convert(tp, utc_time_zone()).day());
-
- // Feb 31 requires normalization.
- EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp));
-
- // Check that we cannot have spaces in UTC offsets.
- EXPECT_TRUE(parse("%z", "-0203", tz, &tp));
- EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp));
- EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp));
-
- // Check that we reject other malformed UTC offsets.
- EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp));
-
- // Check that we do not accept "-0" in fields that allow zero.
- EXPECT_FALSE(parse("%Y", "-0", tz, &tp));
- EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp));
- EXPECT_FALSE(parse("%H", "-0", tz, &tp));
- EXPECT_FALSE(parse("%M", "-0", tz, &tp));
- EXPECT_FALSE(parse("%S", "-0", tz, &tp));
- EXPECT_FALSE(parse("%z", "+-000", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp));
- EXPECT_FALSE(parse("%z", "-00-0", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
-}
-
-TEST(Parse, PosixConversions) {
- time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
- const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
-
- tp = reset;
- EXPECT_TRUE(parse("%d", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day());
-
- // %e is an extension, but is supported internally.
- tp = reset;
- EXPECT_TRUE(parse("%e", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
-
- tp = reset;
- EXPECT_TRUE(parse("%H", "17", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%I", "5", tz, &tp));
- EXPECT_EQ(5, convert(tp, tz).hour());
-
- // %j is parsed but ignored.
- EXPECT_TRUE(parse("%j", "32", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%m", "11", tz, &tp));
- EXPECT_EQ(11, convert(tp, tz).month());
-
- tp = reset;
- EXPECT_TRUE(parse("%M", "33", tz, &tp));
- EXPECT_EQ(33, convert(tp, tz).minute());
-
- tp = reset;
- EXPECT_TRUE(parse("%S", "55", tz, &tp));
- EXPECT_EQ(55, convert(tp, tz).second());
-
- // %U is parsed but ignored.
- EXPECT_TRUE(parse("%U", "15", tz, &tp));
-
- // %w is parsed but ignored.
- EXPECT_TRUE(parse("%w", "2", tz, &tp));
-
- // %W is parsed but ignored.
- EXPECT_TRUE(parse("%W", "22", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%y", "04", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- tp = reset;
- EXPECT_TRUE(parse("%Y", "2004", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- EXPECT_TRUE(parse("%%", "%", tz, &tp));
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
-
- // Because we handle each (non-internal) specifier in a separate call
- // to strptime(), there is no way to group %C and %y together. So we
- // just skip the %C/%y case.
-#if 0
- tp = reset;
- EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-#endif
-
- tp = reset;
- EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
- EXPECT_EQ(3, convert(tp, tz).day());
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- EXPECT_TRUE(parse("%n", "\n", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%R", "03:44", tz, &tp));
- EXPECT_EQ(3, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
-
- EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp));
- EXPECT_EQ(3, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
- tp = reset;
- EXPECT_TRUE(parse("%s", "1234567890", tz, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
-
- // %s conversion, like %z/%Ez, pays no heed to the optional zone.
- time_zone lax;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
- tp = reset;
- EXPECT_TRUE(parse("%s", "1234567890", lax, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
-
- // This is most important when the time has the same YMDhms
- // breakdown in the zone as some other time. For example, ...
- // 1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT)
- // 1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST)
- tp = reset;
- EXPECT_TRUE(parse("%s", "1414917000", lax, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp);
- tp = reset;
- EXPECT_TRUE(parse("%s", "1414920600", lax, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp);
-#endif
-}
-
-TEST(Parse, LocaleSpecific) {
- time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
- const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
-
- // %a is parsed but ignored.
- EXPECT_TRUE(parse("%a", "Mon", tz, &tp));
-
- // %A is parsed but ignored.
- EXPECT_TRUE(parse("%A", "Monday", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%b", "Feb", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
-
- tp = reset;
- EXPECT_TRUE(parse("%B", "February", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
-
- // %p is parsed but ignored if it's alone. But it's used with %I.
- EXPECT_TRUE(parse("%p", "AM", tz, &tp));
- tp = reset;
- EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp));
- if (convert(tp, tz).month() == 2) {
- EXPECT_EQ(3, convert(tp, tz).day());
- } else {
- EXPECT_EQ(2, convert(tp, tz).day());
- EXPECT_EQ(3, convert(tp, tz).month());
- }
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- tp = reset;
- EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
-
- tp = reset;
- EXPECT_TRUE(parse("%h", "Feb", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month()); // Equivalent to %b
-
- tp = reset;
- EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
- tp = reset;
- EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp));
- EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp);
-
- // Modified conversion specifiers %E_
-
- tp = reset;
- EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
- EXPECT_EQ(3, convert(tp, tz).day());
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- tp = reset;
- EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
- // %Ey, the year offset from %EC, doesn't really make sense alone as there
- // is no way to represent it in tm_year (%EC is not simply the century).
- // Yet, because we handle each (non-internal) specifier in a separate call
- // to strptime(), there is no way to group %EC and %Ey either. So we just
- // skip the %EC and %Ey cases.
-
- tp = reset;
- EXPECT_TRUE(parse("%EY", "2004", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- // Modified conversion specifiers %O_
-
- tp = reset;
- EXPECT_TRUE(parse("%Od", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day());
-
- tp = reset;
- EXPECT_TRUE(parse("%Oe", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
-
- tp = reset;
- EXPECT_TRUE(parse("%OH", "17", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%OI", "5", tz, &tp));
- EXPECT_EQ(5, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%Om", "11", tz, &tp));
- EXPECT_EQ(11, convert(tp, tz).month());
-
- tp = reset;
- EXPECT_TRUE(parse("%OM", "33", tz, &tp));
- EXPECT_EQ(33, convert(tp, tz).minute());
-
- tp = reset;
- EXPECT_TRUE(parse("%OS", "55", tz, &tp));
- EXPECT_EQ(55, convert(tp, tz).second());
-
- // %OU is parsed but ignored.
- EXPECT_TRUE(parse("%OU", "15", tz, &tp));
-
- // %Ow is parsed but ignored.
- EXPECT_TRUE(parse("%Ow", "2", tz, &tp));
-
- // %OW is parsed but ignored.
- EXPECT_TRUE(parse("%OW", "22", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%Oy", "04", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-#endif
-}
-
-TEST(Parse, ExtendedSeconds) {
- const time_zone tz = utc_time_zone();
- const time_point<chrono::nanoseconds> unix_epoch =
- chrono::system_clock::from_time_t(0);
-
- // All %E<prec>S cases are treated the same as %E*S on input.
- auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15"};
- for (const std::string& prec : precisions) {
- const std::string fmt = "%E" + prec + "S";
- SCOPED_TRACE(fmt);
- time_point<chrono::nanoseconds> tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "5", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.0", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.00", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.6", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.60", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.600", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.67", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.670", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.678", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp);
- }
-
- // Here is a "%E*S" case we got wrong for a while. The fractional
- // part of the first instant is less than 2^31 and was correctly
- // parsed, while the second (and any subsecond field >=2^31) failed.
- time_point<chrono::nanoseconds> tp = unix_epoch;
- EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-
- // We should also be able to specify long strings of digits far
- // beyond the current resolution and have them convert the same way.
- tp = unix_epoch;
- EXPECT_TRUE(parse(
- "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
- tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-}
-
-TEST(Parse, ExtendedSecondsScan) {
- const time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp;
- for (int ms = 0; ms < 1000; ms += 111) {
- for (int us = 0; us < 1000; us += 27) {
- const int micros = ms * 1000 + us;
- for (int ns = 0; ns < 1000; ns += 9) {
- const auto expected = chrono::system_clock::from_time_t(0) +
- chrono::nanoseconds(micros * 1000 + ns);
- std::ostringstream oss;
- oss << "0." << std::setfill('0') << std::setw(3);
- oss << ms << std::setw(3) << us << std::setw(3) << ns;
- const std::string input = oss.str();
- EXPECT_TRUE(parse("%E*S", input, tz, &tp));
- EXPECT_EQ(expected, tp) << input;
- }
- }
- }
-}
-
-TEST(Parse, ExtendedSubeconds) {
- const time_zone tz = utc_time_zone();
- const time_point<chrono::nanoseconds> unix_epoch =
- chrono::system_clock::from_time_t(0);
-
- // All %E<prec>f cases are treated the same as %E*f on input.
- auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15"};
- for (const std::string& prec : precisions) {
- const std::string fmt = "%E" + prec + "f";
- SCOPED_TRACE(fmt);
- time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1);
- EXPECT_TRUE(parse(fmt, "", tz, &tp));
- EXPECT_EQ(unix_epoch, tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "6", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "60", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "600", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "67", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "670", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "678", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "6789", tz, &tp));
- EXPECT_EQ(
- unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp);
- }
-
- // Here is a "%E*f" case we got wrong for a while. The fractional
- // part of the first instant is less than 2^31 and was correctly
- // parsed, while the second (and any subsecond field >=2^31) failed.
- time_point<chrono::nanoseconds> tp = unix_epoch;
- EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-
- // We should also be able to specify long strings of digits far
- // beyond the current resolution and have them convert the same way.
- tp = unix_epoch;
- EXPECT_TRUE(parse(
- "%E*f", "214748364801234567890123456789012345678901234567890123456789",
- tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-}
-
-TEST(Parse, ExtendedSubecondsScan) {
- time_point<chrono::nanoseconds> tp;
- const time_zone tz = utc_time_zone();
- for (int ms = 0; ms < 1000; ms += 111) {
- for (int us = 0; us < 1000; us += 27) {
- const int micros = ms * 1000 + us;
- for (int ns = 0; ns < 1000; ns += 9) {
- std::ostringstream oss;
- oss << std::setfill('0') << std::setw(3) << ms;
- oss << std::setw(3) << us << std::setw(3) << ns;
- const std::string nanos = oss.str();
- const auto expected = chrono::system_clock::from_time_t(0) +
- chrono::nanoseconds(micros * 1000 + ns);
- for (int ps = 0; ps < 1000; ps += 250) {
- std::ostringstream ps_oss;
- oss << std::setfill('0') << std::setw(3) << ps;
- const std::string input = nanos + ps_oss.str() + "999";
- EXPECT_TRUE(parse("%E*f", input, tz, &tp));
- EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input;
- }
- }
- }
- }
-}
-
-TEST(Parse, ExtendedOffset) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
-
- for (auto fmt : {"%Ez", "%z"}) {
- EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
- }
-}
-
-TEST(Parse, ExtendedSecondOffset) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) {
- EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+000000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse(fmt, "+123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse(fmt, "-12345", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
- }
-}
-
-TEST(Parse, ExtendedYears) {
- const time_zone utc = utc_time_zone();
- const char e4y_fmt[] = "%E4Y%m%d"; // no separators
- time_point<cctz::seconds> tp;
-
- // %E4Y consumes exactly four chars, including any sign.
- EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp));
- EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp));
- EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp));
- EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp);
-
- // When the year is outside [-999:9999], the parse fails.
- EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp));
- EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp));
-}
-
-TEST(Parse, RFC3339Format) {
- const time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
- ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
-
- // Check that %ET also accepts "t".
- time_point<chrono::nanoseconds> tp2;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
- EXPECT_EQ(tp, tp2);
-
- // Check that %Ez also accepts "Z" as a synonym for "+00:00".
- time_point<chrono::nanoseconds> tp3;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
- EXPECT_EQ(tp, tp3);
-
- // Check that %Ez also accepts "z" as a synonym for "+00:00".
- time_point<chrono::nanoseconds> tp4;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
- EXPECT_EQ(tp, tp4);
-}
-
-TEST(Parse, Week) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
- EXPECT_EQ(exp, tp);
-}
-
-TEST(Parse, WeekYearShift) {
- // %U/%W conversions with week values in {0, 52, 53} can slip
- // into the previous/following calendar years.
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- // Slipping into the previous/following calendar years should fail when
- // we're already at the extremes.
- EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
- EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
-}
-
-TEST(Parse, MaxRange) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- // tests the upper limit using +00:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::max());
- EXPECT_FALSE(
- parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp));
-
- // tests the upper limit using -01:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::max());
- EXPECT_FALSE(
- parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp));
-
- // tests the lower limit using +00:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::min());
- EXPECT_FALSE(
- parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp));
-
- // tests the lower limit using +01:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::min());
- EXPECT_FALSE(
- parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
-
- // tests max/min civil-second overflow
- EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
- utc, &tp));
- EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
- utc, &tp));
-
- // TODO: Add tests that parsing times with fractional seconds overflow
- // appropriately. This can't be done until cctz::parse() properly detects
- // overflow when combining the chrono seconds and femto.
-}
-
-//
-// Roundtrip test for format()/parse().
-//
-
-TEST(FormatParse, RoundTrip) {
- time_zone lax;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
- const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax);
- const auto subseconds = chrono::nanoseconds(654321);
-
- // RFC3339, which renders subseconds.
- {
- time_point<chrono::nanoseconds> out;
- const std::string s = format(RFC3339_full, in + subseconds, lax);
- EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s;
- EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
- }
-
- // RFC1123, which only does whole seconds.
- {
- time_point<chrono::nanoseconds> out;
- const std::string s = format(RFC1123_full, in, lax);
- EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s;
- EXPECT_EQ(in, out); // RFC1123_full includes %z
- }
-
-#if defined(_WIN32) || defined(_WIN64)
- // Initial investigations indicate the %c does not roundtrip on Windows.
- // TODO: Figure out what is going on here (perhaps a locale problem).
-#else
- // Even though we don't know what %c will produce, it should roundtrip,
- // but only in the 0-offset timezone.
- {
- time_point<chrono::nanoseconds> out;
- time_zone utc = utc_time_zone();
- const std::string s = format("%c", in, utc);
- EXPECT_TRUE(parse("%c", s, utc, &out)) << s;
- EXPECT_EQ(in, out);
- }
-#endif
-}
-
-TEST(FormatParse, RoundTripDistantFuture) {
- const time_zone utc = utc_time_zone();
- const time_point<cctz::seconds> in = time_point<cctz::seconds>::max();
- const std::string s = format(RFC3339_full, in, utc);
- time_point<cctz::seconds> out;
- EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
- EXPECT_EQ(in, out);
-}
-
-TEST(FormatParse, RoundTripDistantPast) {
- const time_zone utc = utc_time_zone();
- const time_point<cctz::seconds> in = time_point<cctz::seconds>::min();
- const std::string s = format(RFC3339_full, in, utc);
- time_point<cctz::seconds> out;
- EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
- EXPECT_EQ(in, out);
-}
-
-} // namespace cctz
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cctz/time_zone.h"
+
+#include <chrono>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "cctz/civil_time.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace chrono = std::chrono;
+
+namespace cctz {
+
+namespace {
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \
+ do { \
+ time_zone::absolute_lookup al = tz.lookup(tp); \
+ EXPECT_EQ(y, al.cs.year()); \
+ EXPECT_EQ(m, al.cs.month()); \
+ EXPECT_EQ(d, al.cs.day()); \
+ EXPECT_EQ(hh, al.cs.hour()); \
+ EXPECT_EQ(mm, al.cs.minute()); \
+ EXPECT_EQ(ss, al.cs.second()); \
+ EXPECT_EQ(off, al.offset); \
+ EXPECT_TRUE(isdst == al.is_dst); \
+ EXPECT_STREQ(zone, al.abbr); \
+ } while (0)
+
+const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
+
+const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
+const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
+
+// A helper that tests the given format specifier by itself, and with leading
+// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu").
+template <typename D>
+void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt,
+ const std::string& ans) {
+ EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt;
+ EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz));
+ EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz));
+ EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
+}
+
+} // namespace
+
+//
+// Testing format()
+//
+
+TEST(Format, TimePointResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+ const time_point<chrono::nanoseconds> t0 =
+ chrono::system_clock::from_time_t(1420167845) +
+ chrono::milliseconds(123) + chrono::microseconds(456) +
+ chrono::nanoseconds(789);
+ EXPECT_EQ(
+ "03:04:05.123456789",
+ format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc));
+ EXPECT_EQ(
+ "03:04:05.123456",
+ format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc));
+ EXPECT_EQ(
+ "03:04:05.123",
+ format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
+ EXPECT_EQ("03:04:05",
+ format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
+ EXPECT_EQ("03:04:05",
+ format(kFmt, chrono::time_point_cast<cctz::seconds>(t0), utc));
+ EXPECT_EQ("03:04:00",
+ format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
+ EXPECT_EQ("03:00:00",
+ format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc));
+}
+
+TEST(Format, TimePointExtendedResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+ const time_point<cctz::seconds> tp =
+ chrono::time_point_cast<cctz::seconds>(
+ chrono::system_clock::from_time_t(0)) +
+ chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56);
+
+ EXPECT_EQ(
+ "12:34:56.123456789012345",
+ detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc));
+ EXPECT_EQ(
+ "12:34:56.012345678901234",
+ detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
+ EXPECT_EQ(
+ "12:34:56.001234567890123",
+ detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
+ EXPECT_EQ(
+ "12:34:56.000123456789012",
+ detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
+
+ EXPECT_EQ("12:34:56.000000000000123",
+ detail::format(kFmt, tp, detail::femtoseconds(123), utc));
+ EXPECT_EQ("12:34:56.000000000000012",
+ detail::format(kFmt, tp, detail::femtoseconds(12), utc));
+ EXPECT_EQ("12:34:56.000000000000001",
+ detail::format(kFmt, tp, detail::femtoseconds(1), utc));
+}
+
+TEST(Format, Basics) {
+ time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+
+ // Starts with a couple basic edge cases.
+ EXPECT_EQ("", format("", tp, tz));
+ EXPECT_EQ(" ", format(" ", tp, tz));
+ EXPECT_EQ(" ", format(" ", tp, tz));
+ EXPECT_EQ("xxx", format("xxx", tp, tz));
+ std::string big(128, 'x');
+ EXPECT_EQ(big, format(big, tp, tz));
+ // Cause the 1024-byte buffer to grow.
+ std::string bigger(100000, 'x');
+ EXPECT_EQ(bigger, format(bigger, tp, tz));
+
+ tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5);
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz));
+ EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz));
+ EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz));
+ EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz));
+ EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz));
+}
+
+TEST(Format, PosixConversions) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ TestFormatSpecifier(tp, tz, "%d", "01");
+ TestFormatSpecifier(tp, tz, "%e", " 1"); // extension but internal support
+ TestFormatSpecifier(tp, tz, "%H", "00");
+ TestFormatSpecifier(tp, tz, "%I", "12");
+ TestFormatSpecifier(tp, tz, "%j", "001");
+ TestFormatSpecifier(tp, tz, "%m", "01");
+ TestFormatSpecifier(tp, tz, "%M", "00");
+ TestFormatSpecifier(tp, tz, "%S", "00");
+ TestFormatSpecifier(tp, tz, "%U", "00");
+ 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 = chrono::system_clock::from_time_t(0);
+
+ TestFormatSpecifier(tp, tz, "%a", "Thu");
+ TestFormatSpecifier(tp, tz, "%A", "Thursday");
+ TestFormatSpecifier(tp, tz, "%b", "Jan");
+ TestFormatSpecifier(tp, tz, "%B", "January");
+
+ // %c should at least produce the numeric year and time-of-day.
+ const std::string s = format("%c", tp, utc_time_zone());
+ EXPECT_THAT(s, testing::HasSubstr("1970"));
+ EXPECT_THAT(s, testing::HasSubstr("00:00:00"));
+
+ TestFormatSpecifier(tp, tz, "%p", "AM");
+ TestFormatSpecifier(tp, tz, "%x", "01/01/70");
+ TestFormatSpecifier(tp, tz, "%X", "00:00:00");
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+ TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b
+ TestFormatSpecifier(tp, tz, "%P", "am");
+ TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM");
+
+ // Modified conversion specifiers %E_
+ TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan 1 00:00:00 1970");
+ TestFormatSpecifier(tp, tz, "%EC", "19");
+ TestFormatSpecifier(tp, tz, "%Ex", "01/01/70");
+ TestFormatSpecifier(tp, tz, "%EX", "00:00:00");
+ TestFormatSpecifier(tp, tz, "%Ey", "70");
+ TestFormatSpecifier(tp, tz, "%EY", "1970");
+
+ // Modified conversion specifiers %O_
+ TestFormatSpecifier(tp, tz, "%Od", "01");
+ TestFormatSpecifier(tp, tz, "%Oe", " 1");
+ TestFormatSpecifier(tp, tz, "%OH", "00");
+ TestFormatSpecifier(tp, tz, "%OI", "12");
+ TestFormatSpecifier(tp, tz, "%Om", "01");
+ TestFormatSpecifier(tp, tz, "%OM", "00");
+ TestFormatSpecifier(tp, tz, "%OS", "00");
+ TestFormatSpecifier(tp, tz, "%Ou", "4"); // 4=Thursday
+ TestFormatSpecifier(tp, tz, "%OU", "00");
+ TestFormatSpecifier(tp, tz, "%OV", "01");
+ TestFormatSpecifier(tp, tz, "%Ow", "4"); // 4=Thursday
+ TestFormatSpecifier(tp, tz, "%OW", "00");
+ TestFormatSpecifier(tp, tz, "%Oy", "70");
+#endif
+}
+
+TEST(Format, Escaping) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ TestFormatSpecifier(tp, tz, "%%", "%");
+ TestFormatSpecifier(tp, tz, "%%a", "%a");
+ TestFormatSpecifier(tp, tz, "%%b", "%b");
+ TestFormatSpecifier(tp, tz, "%%Ea", "%Ea");
+ TestFormatSpecifier(tp, tz, "%%Es", "%Es");
+ TestFormatSpecifier(tp, tz, "%%E3S", "%E3S");
+ TestFormatSpecifier(tp, tz, "%%OS", "%OS");
+ TestFormatSpecifier(tp, tz, "%%O3S", "%O3S");
+
+ // Multiple levels of escaping.
+ TestFormatSpecifier(tp, tz, "%%%Y", "%1970");
+ TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000");
+ TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S");
+}
+
+TEST(Format, ExtendedSeconds) {
+ const time_zone tz = utc_time_zone();
+
+ // No subseconds.
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+ tp += chrono::seconds(5);
+ EXPECT_EQ("05", format("%E*S", tp, tz));
+ EXPECT_EQ("05", format("%E0S", tp, tz));
+ EXPECT_EQ("05.0", format("%E1S", tp, tz));
+ EXPECT_EQ("05.00", format("%E2S", tp, tz));
+ EXPECT_EQ("05.000", format("%E3S", tp, tz));
+ EXPECT_EQ("05.0000", format("%E4S", tp, tz));
+ EXPECT_EQ("05.00000", format("%E5S", tp, tz));
+ EXPECT_EQ("05.000000", format("%E6S", tp, tz));
+ EXPECT_EQ("05.0000000", format("%E7S", tp, tz));
+ EXPECT_EQ("05.00000000", format("%E8S", tp, tz));
+ EXPECT_EQ("05.000000000", format("%E9S", tp, tz));
+ EXPECT_EQ("05.0000000000", format("%E10S", tp, tz));
+ EXPECT_EQ("05.00000000000", format("%E11S", tp, tz));
+ EXPECT_EQ("05.000000000000", format("%E12S", tp, tz));
+ EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz));
+ EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz));
+ EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz));
+
+ // With subseconds.
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("05.006007008", format("%E*S", tp, tz));
+ EXPECT_EQ("05", format("%E0S", tp, tz));
+ EXPECT_EQ("05.0", format("%E1S", tp, tz));
+ EXPECT_EQ("05.00", format("%E2S", tp, tz));
+ EXPECT_EQ("05.006", format("%E3S", tp, tz));
+ EXPECT_EQ("05.0060", format("%E4S", tp, tz));
+ EXPECT_EQ("05.00600", format("%E5S", tp, tz));
+ EXPECT_EQ("05.006007", format("%E6S", tp, tz));
+ EXPECT_EQ("05.0060070", format("%E7S", tp, tz));
+ EXPECT_EQ("05.00600700", format("%E8S", tp, tz));
+ EXPECT_EQ("05.006007008", format("%E9S", tp, tz));
+ EXPECT_EQ("05.0060070080", format("%E10S", tp, tz));
+ EXPECT_EQ("05.00600700800", format("%E11S", tp, tz));
+ EXPECT_EQ("05.006007008000", format("%E12S", tp, tz));
+ EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz));
+ EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz));
+ EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz));
+
+ // Times before the Unix epoch.
+ tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
+ EXPECT_EQ("1969-12-31 23:59:59.999999",
+ format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+
+ // Here is a "%E*S" case we got wrong for a while. While the first
+ // instant below is correctly rendered as "...:07.333304", the second
+ // one used to appear as "...:07.33330499999999999".
+ tp = chrono::system_clock::from_time_t(0) +
+ chrono::microseconds(1395024427333304);
+ EXPECT_EQ("2014-03-17 02:47:07.333304",
+ format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+ tp += chrono::microseconds(1);
+ EXPECT_EQ("2014-03-17 02:47:07.333305",
+ format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+}
+
+TEST(Format, ExtendedSubeconds) {
+ const time_zone tz = utc_time_zone();
+
+ // No subseconds.
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+ tp += chrono::seconds(5);
+ EXPECT_EQ("0", format("%E*f", tp, tz));
+ EXPECT_EQ("", format("%E0f", tp, tz));
+ EXPECT_EQ("0", format("%E1f", tp, tz));
+ EXPECT_EQ("00", format("%E2f", tp, tz));
+ EXPECT_EQ("000", format("%E3f", tp, tz));
+ EXPECT_EQ("0000", format("%E4f", tp, tz));
+ EXPECT_EQ("00000", format("%E5f", tp, tz));
+ EXPECT_EQ("000000", format("%E6f", tp, tz));
+ EXPECT_EQ("0000000", format("%E7f", tp, tz));
+ EXPECT_EQ("00000000", format("%E8f", tp, tz));
+ EXPECT_EQ("000000000", format("%E9f", tp, tz));
+ EXPECT_EQ("0000000000", format("%E10f", tp, tz));
+ EXPECT_EQ("00000000000", format("%E11f", tp, tz));
+ EXPECT_EQ("000000000000", format("%E12f", tp, tz));
+ EXPECT_EQ("0000000000000", format("%E13f", tp, tz));
+ EXPECT_EQ("00000000000000", format("%E14f", tp, tz));
+ EXPECT_EQ("000000000000000", format("%E15f", tp, tz));
+
+ // With subseconds.
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("006007008", format("%E*f", tp, tz));
+ EXPECT_EQ("", format("%E0f", tp, tz));
+ EXPECT_EQ("0", format("%E1f", tp, tz));
+ EXPECT_EQ("00", format("%E2f", tp, tz));
+ EXPECT_EQ("006", format("%E3f", tp, tz));
+ EXPECT_EQ("0060", format("%E4f", tp, tz));
+ EXPECT_EQ("00600", format("%E5f", tp, tz));
+ EXPECT_EQ("006007", format("%E6f", tp, tz));
+ EXPECT_EQ("0060070", format("%E7f", tp, tz));
+ EXPECT_EQ("00600700", format("%E8f", tp, tz));
+ EXPECT_EQ("006007008", format("%E9f", tp, tz));
+ EXPECT_EQ("0060070080", format("%E10f", tp, tz));
+ EXPECT_EQ("00600700800", format("%E11f", tp, tz));
+ EXPECT_EQ("006007008000", format("%E12f", tp, tz));
+ EXPECT_EQ("0060070080000", format("%E13f", tp, tz));
+ EXPECT_EQ("00600700800000", format("%E14f", tp, tz));
+ EXPECT_EQ("006007008000000", format("%E15f", tp, tz));
+
+ // Times before the Unix epoch.
+ tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
+ EXPECT_EQ("1969-12-31 23:59:59.999999",
+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+
+ // Here is a "%E*S" case we got wrong for a while. While the first
+ // instant below is correctly rendered as "...:07.333304", the second
+ // one used to appear as "...:07.33330499999999999".
+ tp = chrono::system_clock::from_time_t(0) +
+ chrono::microseconds(1395024427333304);
+ EXPECT_EQ("2014-03-17 02:47:07.333304",
+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+ tp += chrono::microseconds(1);
+ EXPECT_EQ("2014-03-17 02:47:07.333305",
+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+}
+
+TEST(Format, CompareExtendSecondsVsSubseconds) {
+ const time_zone tz = utc_time_zone();
+
+ // This test case illustrates the differences/similarities between:
+ // fmt_A: %E<prec>S
+ // fmt_B: %S.%E<prec>f
+ auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; };
+ auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; };
+
+ // No subseconds:
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+ tp += chrono::seconds(5);
+ // ... %E*S and %S.%E*f are different.
+ EXPECT_EQ("05", format(fmt_A("*"), tp, tz));
+ EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz));
+ // ... %E0S and %S.%E0f are different.
+ EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
+ EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
+ // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
+ for (int prec = 1; prec <= 15; ++prec) {
+ const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
+ const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
+ EXPECT_EQ(a, b) << "prec=" << prec;
+ }
+
+ // With subseconds:
+ // ... %E*S and %S.%E*f are the same.
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz));
+ EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz));
+ // ... %E0S and %S.%E0f are different.
+ EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
+ EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
+ // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
+ for (int prec = 1; prec <= 15; ++prec) {
+ const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
+ const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
+ EXPECT_EQ(a, b) << "prec=" << prec;
+ }
+}
+
+TEST(Format, ExtendedOffset) {
+ const auto tp = chrono::system_clock::from_time_t(0);
+
+ auto tz = fixed_time_zone(cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+ tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
+}
+
+TEST(Format, ExtendedSecondOffset) {
+ const auto tp = chrono::system_clock::from_time_t(0);
+
+ auto tz = fixed_time_zone(cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00");
+
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56");
+
+ tz = fixed_time_zone(-chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56");
+
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56");
+}
+
+TEST(Format, ExtendedYears) {
+ const time_zone utc = utc_time_zone();
+ const char e4y_fmt[] = "%E4Y%m%d"; // no separators
+
+ // %E4Y zero-pads the year to produce at least 4 chars, including the sign.
+ auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00001127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00011127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00091127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("09991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("99991127", format(e4y_fmt, tp, utc));
+
+ // When the year is outside [-999:9999], more than 4 chars are produced.
+ tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("100001127", format(e4y_fmt, tp, utc));
+}
+
+TEST(Format, RFC3339Format) {
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+
+ time_point<chrono::nanoseconds> tp =
+ convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::milliseconds(100);
+ EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::milliseconds(20);
+ EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::milliseconds(3);
+ EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::microseconds(400);
+ EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::microseconds(50);
+ EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::microseconds(6);
+ EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::nanoseconds(700);
+ EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::nanoseconds(80);
+ EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::nanoseconds(9);
+ EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00",
+ format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+}
+
+TEST(Format, RFC1123Format) { // locale specific
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+
+ auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+ EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz));
+ EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
+}
+
+TEST(Format, Week) {
+ const time_zone utc = utc_time_zone();
+
+ auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
+}
+
+//
+// Testing parse()
+//
+
+TEST(Parse, TimePointResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+
+ time_point<chrono::nanoseconds> tp_ns;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns));
+ EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns));
+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc));
+
+ time_point<chrono::microseconds> tp_us;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us));
+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us));
+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us));
+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc));
+
+ time_point<chrono::milliseconds> tp_ms;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms));
+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms));
+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms));
+ EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc));
+
+ time_point<chrono::seconds> tp_s;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s));
+ EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s));
+ EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
+
+ time_point<chrono::minutes> tp_m;
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m));
+ EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc));
+
+ time_point<chrono::hours> tp_h;
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h));
+ EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc));
+}
+
+TEST(Parse, TimePointExtendedResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+
+ time_point<cctz::seconds> tp;
+ detail::femtoseconds fs;
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc));
+}
+
+TEST(Parse, Basics) {
+ time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp =
+ chrono::system_clock::from_time_t(1234567890);
+
+ // Simple edge cases.
+ EXPECT_TRUE(parse("", "", tz, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(0), tp); // everything defaulted
+ EXPECT_TRUE(parse(" ", " ", tz, &tp));
+ EXPECT_TRUE(parse(" ", " ", tz, &tp));
+ EXPECT_TRUE(parse("x", "x", tz, &tp));
+ EXPECT_TRUE(parse("xxx", "xxx", tz, &tp));
+
+ EXPECT_TRUE(
+ parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC");
+}
+
+TEST(Parse, WithTimeZone) {
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+ time_point<chrono::nanoseconds> tp;
+
+ // We can parse a string without a UTC offset if we supply a timezone.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
+
+ // But the timezone is ignored when a UTC offset is present.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800",
+ utc_time_zone(), &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT");
+
+ // Check a skipped time (a Spring DST transition). parse() uses the
+ // pre-transition offset.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp));
+ ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT");
+
+ // Check a repeated time (a Fall DST transition). parse() uses the
+ // pre-transition offset.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp));
+ ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT");
+}
+
+TEST(Parse, LeapSecond) {
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+ time_point<chrono::nanoseconds> tp;
+
+ // ":59" -> ":59"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
+
+ // ":59.5" -> ":59.5"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
+
+ // ":60" -> ":00"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
+
+ // ":60.5" -> ":00.0"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
+
+ // ":61" -> error
+ EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp));
+}
+
+TEST(Parse, ErrorCases) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ // Illegal trailing data.
+ EXPECT_FALSE(parse("%S", "123", tz, &tp));
+
+ // Can't parse an illegal format specifier.
+ EXPECT_FALSE(parse("%Q", "x", tz, &tp));
+
+ // Fails because of trailing, unparsed data "blah".
+ EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp));
+
+ // Trailing whitespace is allowed.
+ EXPECT_TRUE(parse("%m-%d", "2-3 ", tz, &tp));
+ EXPECT_EQ(2, convert(tp, utc_time_zone()).month());
+ EXPECT_EQ(3, convert(tp, utc_time_zone()).day());
+
+ // Feb 31 requires normalization.
+ EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp));
+
+ // Check that we cannot have spaces in UTC offsets.
+ EXPECT_TRUE(parse("%z", "-0203", tz, &tp));
+ EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp));
+ EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp));
+
+ // Check that we reject other malformed UTC offsets.
+ EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp));
+
+ // Check that we do not accept "-0" in fields that allow zero.
+ EXPECT_FALSE(parse("%Y", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%H", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%M", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%S", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%z", "+-000", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp));
+ EXPECT_FALSE(parse("%z", "-00-0", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
+}
+
+TEST(Parse, PosixConversions) {
+ time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+ const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+
+ tp = reset;
+ EXPECT_TRUE(parse("%d", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day());
+
+ // %e is an extension, but is supported internally.
+ tp = reset;
+ EXPECT_TRUE(parse("%e", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
+
+ tp = reset;
+ EXPECT_TRUE(parse("%H", "17", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%I", "5", tz, &tp));
+ EXPECT_EQ(5, convert(tp, tz).hour());
+
+ // %j is parsed but ignored.
+ EXPECT_TRUE(parse("%j", "32", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%m", "11", tz, &tp));
+ EXPECT_EQ(11, convert(tp, tz).month());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%M", "33", tz, &tp));
+ EXPECT_EQ(33, convert(tp, tz).minute());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%S", "55", tz, &tp));
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ // %U is parsed but ignored.
+ EXPECT_TRUE(parse("%U", "15", tz, &tp));
+
+ // %w is parsed but ignored.
+ EXPECT_TRUE(parse("%w", "2", tz, &tp));
+
+ // %W is parsed but ignored.
+ EXPECT_TRUE(parse("%W", "22", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%y", "04", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Y", "2004", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ EXPECT_TRUE(parse("%%", "%", tz, &tp));
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+
+ // Because we handle each (non-internal) specifier in a separate call
+ // to strptime(), there is no way to group %C and %y together. So we
+ // just skip the %C/%y case.
+#if 0
+ tp = reset;
+ EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+#endif
+
+ tp = reset;
+ EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+ EXPECT_EQ(3, convert(tp, tz).day());
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ EXPECT_TRUE(parse("%n", "\n", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%R", "03:44", tz, &tp));
+ EXPECT_EQ(3, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+
+ EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp));
+ EXPECT_EQ(3, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1234567890", tz, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+ // %s conversion, like %z/%Ez, pays no heed to the optional zone.
+ time_zone lax;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1234567890", lax, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+ // This is most important when the time has the same YMDhms
+ // breakdown in the zone as some other time. For example, ...
+ // 1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT)
+ // 1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST)
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1414917000", lax, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp);
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1414920600", lax, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp);
+#endif
+}
+
+TEST(Parse, LocaleSpecific) {
+ time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+ const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+
+ // %a is parsed but ignored.
+ EXPECT_TRUE(parse("%a", "Mon", tz, &tp));
+
+ // %A is parsed but ignored.
+ EXPECT_TRUE(parse("%A", "Monday", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%b", "Feb", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%B", "February", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+
+ // %p is parsed but ignored if it's alone. But it's used with %I.
+ EXPECT_TRUE(parse("%p", "AM", tz, &tp));
+ tp = reset;
+ EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp));
+ if (convert(tp, tz).month() == 2) {
+ EXPECT_EQ(3, convert(tp, tz).day());
+ } else {
+ EXPECT_EQ(2, convert(tp, tz).day());
+ EXPECT_EQ(3, convert(tp, tz).month());
+ }
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+
+ tp = reset;
+ EXPECT_TRUE(parse("%h", "Feb", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month()); // Equivalent to %b
+
+ tp = reset;
+ EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp));
+ EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp);
+
+ // Modified conversion specifiers %E_
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+ EXPECT_EQ(3, convert(tp, tz).day());
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ // %Ey, the year offset from %EC, doesn't really make sense alone as there
+ // is no way to represent it in tm_year (%EC is not simply the century).
+ // Yet, because we handle each (non-internal) specifier in a separate call
+ // to strptime(), there is no way to group %EC and %Ey either. So we just
+ // skip the %EC and %Ey cases.
+
+ tp = reset;
+ EXPECT_TRUE(parse("%EY", "2004", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ // Modified conversion specifiers %O_
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Od", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Oe", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OH", "17", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OI", "5", tz, &tp));
+ EXPECT_EQ(5, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Om", "11", tz, &tp));
+ EXPECT_EQ(11, convert(tp, tz).month());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OM", "33", tz, &tp));
+ EXPECT_EQ(33, convert(tp, tz).minute());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OS", "55", tz, &tp));
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ // %OU is parsed but ignored.
+ EXPECT_TRUE(parse("%OU", "15", tz, &tp));
+
+ // %Ow is parsed but ignored.
+ EXPECT_TRUE(parse("%Ow", "2", tz, &tp));
+
+ // %OW is parsed but ignored.
+ EXPECT_TRUE(parse("%OW", "22", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Oy", "04", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+#endif
+}
+
+TEST(Parse, ExtendedSeconds) {
+ const time_zone tz = utc_time_zone();
+ const time_point<chrono::nanoseconds> unix_epoch =
+ chrono::system_clock::from_time_t(0);
+
+ // All %E<prec>S cases are treated the same as %E*S on input.
+ auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15"};
+ for (const std::string& prec : precisions) {
+ const std::string fmt = "%E" + prec + "S";
+ SCOPED_TRACE(fmt);
+ time_point<chrono::nanoseconds> tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "5", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.0", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.00", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.6", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.60", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.600", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.67", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.670", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.678", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp);
+ }
+
+ // Here is a "%E*S" case we got wrong for a while. The fractional
+ // part of the first instant is less than 2^31 and was correctly
+ // parsed, while the second (and any subsecond field >=2^31) failed.
+ time_point<chrono::nanoseconds> tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+
+ // We should also be able to specify long strings of digits far
+ // beyond the current resolution and have them convert the same way.
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(
+ "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
+ tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+}
+
+TEST(Parse, ExtendedSecondsScan) {
+ const time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp;
+ for (int ms = 0; ms < 1000; ms += 111) {
+ for (int us = 0; us < 1000; us += 27) {
+ const int micros = ms * 1000 + us;
+ for (int ns = 0; ns < 1000; ns += 9) {
+ const auto expected = chrono::system_clock::from_time_t(0) +
+ chrono::nanoseconds(micros * 1000 + ns);
+ std::ostringstream oss;
+ oss << "0." << std::setfill('0') << std::setw(3);
+ oss << ms << std::setw(3) << us << std::setw(3) << ns;
+ const std::string input = oss.str();
+ EXPECT_TRUE(parse("%E*S", input, tz, &tp));
+ EXPECT_EQ(expected, tp) << input;
+ }
+ }
+ }
+}
+
+TEST(Parse, ExtendedSubeconds) {
+ const time_zone tz = utc_time_zone();
+ const time_point<chrono::nanoseconds> unix_epoch =
+ chrono::system_clock::from_time_t(0);
+
+ // All %E<prec>f cases are treated the same as %E*f on input.
+ auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15"};
+ for (const std::string& prec : precisions) {
+ const std::string fmt = "%E" + prec + "f";
+ SCOPED_TRACE(fmt);
+ time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1);
+ EXPECT_TRUE(parse(fmt, "", tz, &tp));
+ EXPECT_EQ(unix_epoch, tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "6", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "60", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "600", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "67", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "670", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "678", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "6789", tz, &tp));
+ EXPECT_EQ(
+ unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp);
+ }
+
+ // Here is a "%E*f" case we got wrong for a while. The fractional
+ // part of the first instant is less than 2^31 and was correctly
+ // parsed, while the second (and any subsecond field >=2^31) failed.
+ time_point<chrono::nanoseconds> tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+
+ // We should also be able to specify long strings of digits far
+ // beyond the current resolution and have them convert the same way.
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(
+ "%E*f", "214748364801234567890123456789012345678901234567890123456789",
+ tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+}
+
+TEST(Parse, ExtendedSubecondsScan) {
+ time_point<chrono::nanoseconds> tp;
+ const time_zone tz = utc_time_zone();
+ for (int ms = 0; ms < 1000; ms += 111) {
+ for (int us = 0; us < 1000; us += 27) {
+ const int micros = ms * 1000 + us;
+ for (int ns = 0; ns < 1000; ns += 9) {
+ std::ostringstream oss;
+ oss << std::setfill('0') << std::setw(3) << ms;
+ oss << std::setw(3) << us << std::setw(3) << ns;
+ const std::string nanos = oss.str();
+ const auto expected = chrono::system_clock::from_time_t(0) +
+ chrono::nanoseconds(micros * 1000 + ns);
+ for (int ps = 0; ps < 1000; ps += 250) {
+ std::ostringstream ps_oss;
+ oss << std::setfill('0') << std::setw(3) << ps;
+ const std::string input = nanos + ps_oss.str() + "999";
+ EXPECT_TRUE(parse("%E*f", input, tz, &tp));
+ EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input;
+ }
+ }
+ }
+ }
+}
+
+TEST(Parse, ExtendedOffset) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
+
+ for (auto fmt : {"%Ez", "%z"}) {
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
+}
+
+TEST(Parse, ExtendedSecondOffset) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) {
+ EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+000000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12345", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
+}
+
+TEST(Parse, ExtendedYears) {
+ const time_zone utc = utc_time_zone();
+ const char e4y_fmt[] = "%E4Y%m%d"; // no separators
+ time_point<cctz::seconds> tp;
+
+ // %E4Y consumes exactly four chars, including any sign.
+ EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp);
+
+ // When the year is outside [-999:9999], the parse fails.
+ EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp));
+ EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp));
+}
+
+TEST(Parse, RFC3339Format) {
+ const time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
+ ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
+
+ // Check that %ET also accepts "t".
+ time_point<chrono::nanoseconds> tp2;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
+ EXPECT_EQ(tp, tp2);
+
+ // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+ time_point<chrono::nanoseconds> tp3;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
+ EXPECT_EQ(tp, tp3);
+
+ // Check that %Ez also accepts "z" as a synonym for "+00:00".
+ time_point<chrono::nanoseconds> tp4;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
+ EXPECT_EQ(tp, tp4);
+}
+
+TEST(Parse, Week) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+}
+
+TEST(Parse, WeekYearShift) {
+ // %U/%W conversions with week values in {0, 52, 53} can slip
+ // into the previous/following calendar years.
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ // Slipping into the previous/following calendar years should fail when
+ // we're already at the extremes.
+ EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
+ EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
+}
+
+TEST(Parse, MaxRange) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ // tests the upper limit using +00:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::max());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp));
+
+ // tests the upper limit using -01:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::max());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp));
+
+ // tests the lower limit using +00:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::min());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp));
+
+ // tests the lower limit using +01:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::min());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
+
+ // tests max/min civil-second overflow
+ EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
+ utc, &tp));
+ EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
+ utc, &tp));
+
+ // TODO: Add tests that parsing times with fractional seconds overflow
+ // appropriately. This can't be done until cctz::parse() properly detects
+ // overflow when combining the chrono seconds and femto.
+}
+
+//
+// Roundtrip test for format()/parse().
+//
+
+TEST(FormatParse, RoundTrip) {
+ time_zone lax;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
+ const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax);
+ const auto subseconds = chrono::nanoseconds(654321);
+
+ // RFC3339, which renders subseconds.
+ {
+ time_point<chrono::nanoseconds> out;
+ const std::string s = format(RFC3339_full, in + subseconds, lax);
+ EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s;
+ EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
+ }
+
+ // RFC1123, which only does whole seconds.
+ {
+ time_point<chrono::nanoseconds> out;
+ const std::string s = format(RFC1123_full, in, lax);
+ EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s;
+ EXPECT_EQ(in, out); // RFC1123_full includes %z
+ }
+
+#if defined(_WIN32) || defined(_WIN64)
+ // Initial investigations indicate the %c does not roundtrip on Windows.
+ // TODO: Figure out what is going on here (perhaps a locale problem).
+#else
+ // Even though we don't know what %c will produce, it should roundtrip,
+ // but only in the 0-offset timezone.
+ {
+ time_point<chrono::nanoseconds> out;
+ time_zone utc = utc_time_zone();
+ const std::string s = format("%c", in, utc);
+ EXPECT_TRUE(parse("%c", s, utc, &out)) << s;
+ EXPECT_EQ(in, out);
+ }
+#endif
+}
+
+TEST(FormatParse, RoundTripDistantFuture) {
+ const time_zone utc = utc_time_zone();
+ const time_point<cctz::seconds> in = time_point<cctz::seconds>::max();
+ const std::string s = format(RFC3339_full, in, utc);
+ time_point<cctz::seconds> out;
+ EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
+ EXPECT_EQ(in, out);
+}
+
+TEST(FormatParse, RoundTripDistantPast) {
+ const time_zone utc = utc_time_zone();
+ const time_point<cctz::seconds> in = time_point<cctz::seconds>::min();
+ const std::string s = format(RFC3339_full, in, utc);
+ time_point<cctz::seconds> out;
+ EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
+ EXPECT_EQ(in, out);
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/test/time_zone_lookup_test.cc b/contrib/libs/cctz/test/time_zone_lookup_test.cc
index 991d7af1c8..bf816ac6e9 100644
--- a/contrib/libs/cctz/test/time_zone_lookup_test.cc
+++ b/contrib/libs/cctz/test/time_zone_lookup_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,21 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "cctz/time_zone.h"
+#include "cctz/time_zone.h"
#include <chrono>
#include <cstddef>
-#include <cstdlib>
+#include <cstdlib>
#include <future>
-#include <limits>
+#include <limits>
#include <string>
#include <thread>
#include <vector>
-#include "cctz/civil_time.h"
-#include "gtest/gtest.h"
+#include "cctz/civil_time.h"
+#include "gtest/gtest.h"
-namespace chrono = std::chrono;
+namespace chrono = std::chrono;
namespace cctz {
@@ -209,7 +209,7 @@ const char* const kTimeZoneNames[] = {
"America/North_Dakota/Beulah",
"America/North_Dakota/Center",
"America/North_Dakota/New_Salem",
- "America/Nuuk",
+ "America/Nuuk",
"America/Ojinaga",
"America/Panama",
"America/Pangnirtung",
@@ -336,7 +336,7 @@ const char* const kTimeZoneNames[] = {
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
- "Asia/Qostanay",
+ "Asia/Qostanay",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
@@ -653,17 +653,17 @@ time_zone LoadZone(const std::string& name) {
/* EXPECT_STREQ(zone, al.abbr); */ \
} while (0)
-// These tests sometimes run on platforms that have zoneinfo data so old
-// that the transition we are attempting to check does not exist, most
-// notably Android emulators. Fortunately, AndroidZoneInfoSource supports
-// time_zone::version() so, in cases where we've learned that it matters,
-// we can make the check conditionally.
-int VersionCmp(time_zone tz, const std::string& target) {
- std::string version = tz.version();
- if (version.empty() && !target.empty()) return 1; // unknown > known
- return version.compare(target);
-}
-
+// These tests sometimes run on platforms that have zoneinfo data so old
+// that the transition we are attempting to check does not exist, most
+// notably Android emulators. Fortunately, AndroidZoneInfoSource supports
+// time_zone::version() so, in cases where we've learned that it matters,
+// we can make the check conditionally.
+int VersionCmp(time_zone tz, const std::string& target) {
+ std::string version = tz.version();
+ if (version.empty() && !target.empty()) return 1; // unknown > known
+ return version.compare(target);
+}
+
} // namespace
TEST(TimeZones, LoadZonesConcurrently) {
@@ -684,7 +684,7 @@ TEST(TimeZones, LoadZonesConcurrently) {
}
};
- const std::size_t n_threads = 128;
+ const std::size_t n_threads = 128;
std::vector<std::thread> threads;
std::vector<std::set<std::string>> thread_failures(n_threads);
for (std::size_t i = 0; i != n_threads; ++i) {
@@ -699,19 +699,19 @@ TEST(TimeZones, LoadZonesConcurrently) {
// Allow a small number of failures to account for skew between
// the contents of kTimeZoneNames and the zoneinfo data source.
-#if defined(__ANDROID__)
- // Cater to the possibility of using an even older zoneinfo data
- // source when running on Android, where it is difficult to override
- // the bionic tzdata provided by the test environment.
- const std::size_t max_failures = 20;
-#else
+#if defined(__ANDROID__)
+ // Cater to the possibility of using an even older zoneinfo data
+ // source when running on Android, where it is difficult to override
+ // the bionic tzdata provided by the test environment.
+ const std::size_t max_failures = 20;
+#else
const std::size_t max_failures = 3;
-#endif
+#endif
std::set<std::string> failures;
for (const auto& thread_failure : thread_failures) {
failures.insert(thread_failure.begin(), thread_failure.end());
}
- EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
+ EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
}
TEST(TimeZone, NamedTimeZones) {
@@ -721,13 +721,13 @@ TEST(TimeZone, NamedTimeZones) {
EXPECT_EQ("America/New_York", nyc.name());
const time_zone syd = LoadZone("Australia/Sydney");
EXPECT_EQ("Australia/Sydney", syd.name());
- const time_zone fixed0 = fixed_time_zone(cctz::seconds::zero());
+ const time_zone fixed0 = fixed_time_zone(cctz::seconds::zero());
EXPECT_EQ("UTC", fixed0.name());
- const time_zone fixed_pos = fixed_time_zone(
- chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
+ const time_zone fixed_pos = fixed_time_zone(
+ chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
EXPECT_EQ("Fixed/UTC+03:25:45", fixed_pos.name());
- const time_zone fixed_neg = fixed_time_zone(
- -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
+ const time_zone fixed_neg = fixed_time_zone(
+ -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
EXPECT_EQ("Fixed/UTC-12:34:56", fixed_neg.name());
}
@@ -737,34 +737,34 @@ TEST(TimeZone, Failures) {
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz));
- EXPECT_EQ(chrono::system_clock::from_time_t(0),
+ EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
// Ensures that the load still fails on a subsequent attempt.
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz));
- EXPECT_EQ(chrono::system_clock::from_time_t(0),
+ EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
// Loading an empty string timezone should fail.
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("", &tz));
- EXPECT_EQ(chrono::system_clock::from_time_t(0),
+ EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
}
TEST(TimeZone, Equality) {
- const time_zone a;
- const time_zone b;
+ const time_zone a;
+ const time_zone b;
EXPECT_EQ(a, b);
EXPECT_EQ(a.name(), b.name());
- const time_zone implicit_utc;
+ const time_zone implicit_utc;
const time_zone explicit_utc = utc_time_zone();
EXPECT_EQ(implicit_utc, explicit_utc);
EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
- const time_zone fixed_zero = fixed_time_zone(cctz::seconds::zero());
+ const time_zone fixed_zero = fixed_time_zone(cctz::seconds::zero());
EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name()));
EXPECT_EQ(fixed_zero, explicit_utc);
@@ -772,25 +772,25 @@ TEST(TimeZone, Equality) {
EXPECT_EQ(fixed_utc, LoadZone(fixed_utc.name()));
EXPECT_EQ(fixed_utc, explicit_utc);
- const time_zone fixed_pos = fixed_time_zone(
- chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
+ const time_zone fixed_pos = fixed_time_zone(
+ chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
EXPECT_EQ(fixed_pos, LoadZone(fixed_pos.name()));
EXPECT_NE(fixed_pos, explicit_utc);
- const time_zone fixed_neg = fixed_time_zone(
- -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
+ const time_zone fixed_neg = fixed_time_zone(
+ -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
EXPECT_EQ(fixed_neg, LoadZone(fixed_neg.name()));
EXPECT_NE(fixed_neg, explicit_utc);
- const time_zone fixed_lim = fixed_time_zone(chrono::hours(24));
+ const time_zone fixed_lim = fixed_time_zone(chrono::hours(24));
EXPECT_EQ(fixed_lim, LoadZone(fixed_lim.name()));
EXPECT_NE(fixed_lim, explicit_utc);
- const time_zone fixed_ovfl =
- fixed_time_zone(chrono::hours(24) + chrono::seconds(1));
+ const time_zone fixed_ovfl =
+ fixed_time_zone(chrono::hours(24) + chrono::seconds(1));
EXPECT_EQ(fixed_ovfl, LoadZone(fixed_ovfl.name()));
EXPECT_EQ(fixed_ovfl, explicit_utc);
- EXPECT_EQ(fixed_time_zone(chrono::seconds(1)),
- fixed_time_zone(chrono::seconds(1)));
+ EXPECT_EQ(fixed_time_zone(chrono::seconds(1)),
+ fixed_time_zone(chrono::seconds(1)));
const time_zone local = local_time_zone();
EXPECT_EQ(local, LoadZone(local.name()));
@@ -803,113 +803,113 @@ TEST(TimeZone, Equality) {
TEST(StdChronoTimePoint, TimeTAlignment) {
// Ensures that the Unix epoch and the system clock epoch are an integral
// number of seconds apart. This simplifies conversions to/from time_t.
- auto diff = chrono::system_clock::time_point() -
- chrono::system_clock::from_time_t(0);
- EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
- diff % chrono::seconds(1));
+ auto diff = chrono::system_clock::time_point() -
+ chrono::system_clock::from_time_t(0);
+ EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
+ diff % chrono::seconds(1));
}
TEST(BreakTime, TimePointResolution) {
const time_zone utc = utc_time_zone();
- const auto t0 = chrono::system_clock::from_time_t(0);
+ const auto t0 = chrono::system_clock::from_time_t(0);
- ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<cctz::seconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<cctz::seconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
}
TEST(BreakTime, LocalTimeInUTC) {
const time_zone tz = utc_time_zone();
- const auto tp = chrono::system_clock::from_time_t(0);
+ const auto tp = chrono::system_clock::from_time_t(0);
ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInUTCUnaligned) {
const time_zone tz = utc_time_zone();
- const auto tp =
- chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
+ const auto tp =
+ chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimePosix) {
// See IEEE Std 1003.1-1988 B.2.3 General Terms, Epoch.
const time_zone tz = utc_time_zone();
- const auto tp = chrono::system_clock::from_time_t(536457599);
+ const auto tp = chrono::system_clock::from_time_t(536457599);
ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(TimeZoneImpl, LocalTimeInFixed) {
- const cctz::seconds offset =
- -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47));
+ const cctz::seconds offset =
+ -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47));
const time_zone tz = fixed_time_zone(offset);
- const auto tp = chrono::system_clock::from_time_t(0);
+ const auto tp = chrono::system_clock::from_time_t(0);
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
- "-083347");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ "-083347");
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInNewYork) {
const time_zone tz = LoadZone("America/New_York");
- const auto tp = chrono::system_clock::from_time_t(45);
+ const auto tp = chrono::system_clock::from_time_t(45);
ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInMTV) {
const time_zone tz = LoadZone("America/Los_Angeles");
- const auto tp = chrono::system_clock::from_time_t(1380855729);
+ const auto tp = chrono::system_clock::from_time_t(1380855729);
ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT");
- EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInSydney) {
const time_zone tz = LoadZone("Australia/Sydney");
- const auto tp = chrono::system_clock::from_time_t(90);
+ const auto tp = chrono::system_clock::from_time_t(90);
ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST");
- EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(MakeTime, TimePointResolution) {
const time_zone utc = utc_time_zone();
- const time_point<chrono::nanoseconds> tp_ns =
+ const time_point<chrono::nanoseconds> tp_ns =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_ns, utc));
- const time_point<chrono::microseconds> tp_us =
+ const time_point<chrono::microseconds> tp_us =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_us, utc));
- const time_point<chrono::milliseconds> tp_ms =
+ const time_point<chrono::milliseconds> tp_ms =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_ms, utc));
- const time_point<chrono::seconds> tp_s =
+ const time_point<chrono::seconds> tp_s =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_s, utc));
- const time_point<cctz::seconds> tp_s64 =
+ const time_point<cctz::seconds> tp_s64 =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_s64, utc));
- // These next two require chrono::time_point_cast because the conversion
- // from a resolution of seconds (the return value of convert()) to a
- // coarser resolution requires an explicit cast.
- const time_point<chrono::minutes> tp_m =
- chrono::time_point_cast<chrono::minutes>(
+ // These next two require chrono::time_point_cast because the conversion
+ // from a resolution of seconds (the return value of convert()) to a
+ // coarser resolution requires an explicit cast.
+ const time_point<chrono::minutes> tp_m =
+ chrono::time_point_cast<chrono::minutes>(
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc));
- const time_point<chrono::hours> tp_h =
- chrono::time_point_cast<chrono::hours>(
+ const time_point<chrono::hours> tp_h =
+ chrono::time_point_cast<chrono::hours>(
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc));
}
@@ -917,7 +917,7 @@ TEST(MakeTime, TimePointResolution) {
TEST(MakeTime, Normalization) {
const time_zone tz = LoadZone("America/New_York");
const auto tp = convert(civil_second(2009, 2, 13, 18, 31, 30), tz);
- EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
// Now requests for the same time_point but with out-of-range fields.
EXPECT_EQ(tp, convert(civil_second(2008, 14, 13, 18, 31, 30), tz)); // month
@@ -927,253 +927,253 @@ TEST(MakeTime, Normalization) {
EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz)); // second
}
-// NOTE: Run this with -ftrapv to detect overflow problems.
+// NOTE: Run this with -ftrapv to detect overflow problems.
TEST(MakeTime, SysSecondsLimits) {
- const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
+ const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
const time_zone utc = utc_time_zone();
- const time_zone east = fixed_time_zone(chrono::hours(14));
- const time_zone west = fixed_time_zone(-chrono::hours(14));
- time_point<cctz::seconds> tp;
+ const time_zone east = fixed_time_zone(chrono::hours(14));
+ const time_zone west = fixed_time_zone(-chrono::hours(14));
+ time_point<cctz::seconds> tp;
- // Approach the maximal time_point<cctz::seconds> value from below.
+ // Approach the maximal time_point<cctz::seconds> value from below.
tp = convert(civil_second(292277026596, 12, 4, 15, 30, 6), utc);
EXPECT_EQ("292277026596-12-04T15:30:06+00:00", format(RFC3339, tp, utc));
tp = convert(civil_second(292277026596, 12, 4, 15, 30, 7), utc);
EXPECT_EQ("292277026596-12-04T15:30:07+00:00", format(RFC3339, tp, utc));
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second(292277026596, 12, 4, 15, 30, 8), utc);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second::max(), utc);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
// Checks that we can also get the maximal value for a far-east zone.
tp = convert(civil_second(292277026596, 12, 5, 5, 30, 7), east);
EXPECT_EQ("292277026596-12-05T05:30:07+14:00", format(RFC3339, tp, east));
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second(292277026596, 12, 5, 5, 30, 8), east);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second::max(), east);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
// Checks that we can also get the maximal value for a far-west zone.
tp = convert(civil_second(292277026596, 12, 4, 1, 30, 7), west);
EXPECT_EQ("292277026596-12-04T01:30:07-14:00", format(RFC3339, tp, west));
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second(292277026596, 12, 4, 7, 30, 8), west);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second::max(), west);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
- // Approach the minimal time_point<cctz::seconds> value from above.
+ // Approach the minimal time_point<cctz::seconds> value from above.
tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 53), utc);
EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", format(RFC3339, tp, utc));
tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 52), utc);
EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", format(RFC3339, tp, utc));
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 51), utc);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), utc);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
// Checks that we can also get the minimal value for a far-east zone.
tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 52), east);
EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", format(RFC3339, tp, east));
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 51), east);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), east);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
// Checks that we can also get the minimal value for a far-west zone.
tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 52), west);
EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", format(RFC3339, tp, west));
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 51), west);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), west);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
-
- // Some similar checks for the "libc" time-zone implementation.
- if (sizeof(std::time_t) >= 8) {
- // Checks that "tm_year + 1900", as used by the "libc" implementation,
- // can produce year values beyond the range on an int without overflow.
-#if defined(_WIN32) || defined(_WIN64)
- // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
-#else
- const time_zone cut = LoadZone("libc:UTC");
- const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
- tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
- // The BSD gmtime_r() fails on extreme positive tm_year values.
-#else
- EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
-#endif
- const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
- tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
- EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
-#endif
- }
-}
-
-TEST(MakeTime, LocalTimeLibC) {
- // Checks that cctz and libc agree on transition points in [1970:2037].
- //
- // We limit this test case to environments where:
- // 1) we know how to change the time zone used by localtime()/mktime(),
- // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
- // 3) we have some idea about how mktime() behaves during transitions.
-#if defined(__linux__) && !defined(__ANDROID__) && defined(CCTZ_TEST_LIBC_LOCALTIME)
- const char* const ep = getenv("TZ");
- std::string tz_name = (ep != nullptr) ? ep : "";
- for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
- ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means
- const auto zi = local_time_zone();
- const auto lc = LoadZone("libc:localtime");
- time_zone::civil_transition transition;
- for (auto tp = zi.lookup(civil_second()).trans;
- zi.next_transition(tp, &transition);
- tp = zi.lookup(transition.to).trans) {
- const auto fcl = zi.lookup(transition.from);
- const auto tcl = zi.lookup(transition.to);
- civil_second cs; // compare cs in zi and lc
- if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
- if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
- // Both unique; must be an is_dst or abbr change.
- ASSERT_EQ(transition.from, transition.to);
- const auto trans = fcl.trans;
- const auto tal = zi.lookup(trans);
- const auto tprev = trans - cctz::seconds(1);
- const auto pal = zi.lookup(tprev);
- if (pal.is_dst == tal.is_dst) {
- ASSERT_STRNE(pal.abbr, tal.abbr);
- }
- continue;
- }
- ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
- cs = transition.to;
- } else {
- ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
- ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
- cs = transition.from;
- }
- if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
- const auto cl_zi = zi.lookup(cs);
- if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
- // The "libc" implementation cannot correctly classify transitions
- // that don't change the "tm_isdst" flag. In Europe/Volgograd, for
- // example, there is a SKIPPED transition from +03 to +04 with dst=F
- // on both sides ...
- // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800]
- // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400]
- // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike,
- // say, the similar Europe/Chisinau transition from +02 to +03 ...
- // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200]
- // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800]
- // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and
- // returns 1521936000.
- continue;
- }
- if (cs == civil_second(2037, 10, 4, 2, 0, 0)) {
- const std::string tzname = *np;
- if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") {
- // The "libc" implementation gets this transition wrong (at least
- // until 2018g when it was removed), returning an offset of 3600
- // instead of 0. TODO: Revert this when 2018g is ubiquitous.
- continue;
- }
- }
- const auto cl_lc = lc.lookup(cs);
- SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np);
- EXPECT_EQ(cl_zi.kind, cl_lc.kind);
- EXPECT_EQ(cl_zi.pre, cl_lc.pre);
- EXPECT_EQ(cl_zi.trans, cl_lc.trans);
- EXPECT_EQ(cl_zi.post, cl_lc.post);
- }
- }
- if (ep == nullptr) {
- ASSERT_EQ(0, unsetenv("TZ"));
- } else {
- ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1));
- }
-#endif
-}
-
-TEST(NextTransition, UTC) {
- const auto tz = utc_time_zone();
- time_zone::civil_transition trans;
-
- auto tp = time_point<cctz::seconds>::min();
- EXPECT_FALSE(tz.next_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::max();
- EXPECT_FALSE(tz.next_transition(tp, &trans));
-}
-
-TEST(PrevTransition, UTC) {
- const auto tz = utc_time_zone();
- time_zone::civil_transition trans;
-
- auto tp = time_point<cctz::seconds>::max();
- EXPECT_FALSE(tz.prev_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::min();
- EXPECT_FALSE(tz.prev_transition(tp, &trans));
-}
-
-TEST(NextTransition, AmericaNewYork) {
- const auto tz = LoadZone("America/New_York");
- time_zone::civil_transition trans;
-
- auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
- EXPECT_TRUE(tz.next_transition(tp, &trans));
- EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from);
- EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to);
-
- tp = time_point<cctz::seconds>::max();
- EXPECT_FALSE(tz.next_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::min();
- EXPECT_TRUE(tz.next_transition(tp, &trans));
- if (trans.from == civil_second(1918, 3, 31, 2, 0, 0)) {
- // It looks like the tzdata is only 32 bit (probably macOS),
- // which bottoms out at 1901-12-13T20:45:52+00:00.
- EXPECT_EQ(civil_second(1918, 3, 31, 3, 0, 0), trans.to);
- } else {
- EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from);
- EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to);
- }
-}
-
-TEST(PrevTransition, AmericaNewYork) {
- const auto tz = LoadZone("America/New_York");
- time_zone::civil_transition trans;
-
- auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
- EXPECT_TRUE(tz.prev_transition(tp, &trans));
- EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from);
- EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to);
-
- tp = time_point<cctz::seconds>::min();
- EXPECT_FALSE(tz.prev_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::max();
- EXPECT_TRUE(tz.prev_transition(tp, &trans));
- // We have a transition but we don't know which one.
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+
+ // Some similar checks for the "libc" time-zone implementation.
+ if (sizeof(std::time_t) >= 8) {
+ // Checks that "tm_year + 1900", as used by the "libc" implementation,
+ // can produce year values beyond the range on an int without overflow.
+#if defined(_WIN32) || defined(_WIN64)
+ // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
+#else
+ const time_zone cut = LoadZone("libc:UTC");
+ const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
+ tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // The BSD gmtime_r() fails on extreme positive tm_year values.
+#else
+ EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
+#endif
+ const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
+ tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
+ EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
+#endif
+ }
}
+TEST(MakeTime, LocalTimeLibC) {
+ // Checks that cctz and libc agree on transition points in [1970:2037].
+ //
+ // We limit this test case to environments where:
+ // 1) we know how to change the time zone used by localtime()/mktime(),
+ // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
+ // 3) we have some idea about how mktime() behaves during transitions.
+#if defined(__linux__) && !defined(__ANDROID__) && defined(CCTZ_TEST_LIBC_LOCALTIME)
+ const char* const ep = getenv("TZ");
+ std::string tz_name = (ep != nullptr) ? ep : "";
+ for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
+ ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means
+ const auto zi = local_time_zone();
+ const auto lc = LoadZone("libc:localtime");
+ time_zone::civil_transition transition;
+ for (auto tp = zi.lookup(civil_second()).trans;
+ zi.next_transition(tp, &transition);
+ tp = zi.lookup(transition.to).trans) {
+ const auto fcl = zi.lookup(transition.from);
+ const auto tcl = zi.lookup(transition.to);
+ civil_second cs; // compare cs in zi and lc
+ if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
+ if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
+ // Both unique; must be an is_dst or abbr change.
+ ASSERT_EQ(transition.from, transition.to);
+ const auto trans = fcl.trans;
+ const auto tal = zi.lookup(trans);
+ const auto tprev = trans - cctz::seconds(1);
+ const auto pal = zi.lookup(tprev);
+ if (pal.is_dst == tal.is_dst) {
+ ASSERT_STRNE(pal.abbr, tal.abbr);
+ }
+ continue;
+ }
+ ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
+ cs = transition.to;
+ } else {
+ ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
+ ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
+ cs = transition.from;
+ }
+ if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
+ const auto cl_zi = zi.lookup(cs);
+ if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
+ // The "libc" implementation cannot correctly classify transitions
+ // that don't change the "tm_isdst" flag. In Europe/Volgograd, for
+ // example, there is a SKIPPED transition from +03 to +04 with dst=F
+ // on both sides ...
+ // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800]
+ // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400]
+ // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike,
+ // say, the similar Europe/Chisinau transition from +02 to +03 ...
+ // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200]
+ // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800]
+ // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and
+ // returns 1521936000.
+ continue;
+ }
+ if (cs == civil_second(2037, 10, 4, 2, 0, 0)) {
+ const std::string tzname = *np;
+ if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") {
+ // The "libc" implementation gets this transition wrong (at least
+ // until 2018g when it was removed), returning an offset of 3600
+ // instead of 0. TODO: Revert this when 2018g is ubiquitous.
+ continue;
+ }
+ }
+ const auto cl_lc = lc.lookup(cs);
+ SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np);
+ EXPECT_EQ(cl_zi.kind, cl_lc.kind);
+ EXPECT_EQ(cl_zi.pre, cl_lc.pre);
+ EXPECT_EQ(cl_zi.trans, cl_lc.trans);
+ EXPECT_EQ(cl_zi.post, cl_lc.post);
+ }
+ }
+ if (ep == nullptr) {
+ ASSERT_EQ(0, unsetenv("TZ"));
+ } else {
+ ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1));
+ }
+#endif
+}
+
+TEST(NextTransition, UTC) {
+ const auto tz = utc_time_zone();
+ time_zone::civil_transition trans;
+
+ auto tp = time_point<cctz::seconds>::min();
+ EXPECT_FALSE(tz.next_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::max();
+ EXPECT_FALSE(tz.next_transition(tp, &trans));
+}
+
+TEST(PrevTransition, UTC) {
+ const auto tz = utc_time_zone();
+ time_zone::civil_transition trans;
+
+ auto tp = time_point<cctz::seconds>::max();
+ EXPECT_FALSE(tz.prev_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::min();
+ EXPECT_FALSE(tz.prev_transition(tp, &trans));
+}
+
+TEST(NextTransition, AmericaNewYork) {
+ const auto tz = LoadZone("America/New_York");
+ time_zone::civil_transition trans;
+
+ auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
+ EXPECT_TRUE(tz.next_transition(tp, &trans));
+ EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from);
+ EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to);
+
+ tp = time_point<cctz::seconds>::max();
+ EXPECT_FALSE(tz.next_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::min();
+ EXPECT_TRUE(tz.next_transition(tp, &trans));
+ if (trans.from == civil_second(1918, 3, 31, 2, 0, 0)) {
+ // It looks like the tzdata is only 32 bit (probably macOS),
+ // which bottoms out at 1901-12-13T20:45:52+00:00.
+ EXPECT_EQ(civil_second(1918, 3, 31, 3, 0, 0), trans.to);
+ } else {
+ EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from);
+ EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to);
+ }
+}
+
+TEST(PrevTransition, AmericaNewYork) {
+ const auto tz = LoadZone("America/New_York");
+ time_zone::civil_transition trans;
+
+ auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
+ EXPECT_TRUE(tz.prev_transition(tp, &trans));
+ EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from);
+ EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to);
+
+ tp = time_point<cctz::seconds>::min();
+ EXPECT_FALSE(tz.prev_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::max();
+ EXPECT_TRUE(tz.prev_transition(tp, &trans));
+ // We have a transition but we don't know which one.
+}
+
TEST(TimeZoneEdgeCase, AmericaNewYork) {
const time_zone tz = LoadZone("America/New_York");
// Spring 1:59:59 -> 3:00:00
auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -5 * 3600, false, "EST");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -4 * 3600, true, "EDT");
// Fall 1:59:59 -> 1:00:00
tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -4 * 3600, true, "EDT");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -5 * 3600, false, "EST");
}
@@ -1183,13 +1183,13 @@ TEST(TimeZoneEdgeCase, AmericaLosAngeles) {
// 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 += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -7 * 3600, true, "PDT");
// Fall 1:59:59 -> 1:00:00
tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, true, "PDT");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -8 * 3600, false, "PST");
}
@@ -1199,13 +1199,13 @@ TEST(TimeZoneEdgeCase, ArizonaNoTransition) {
// 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 += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 3, 10, 2, 0, 0, -7 * 3600, false, "MST");
// No transition in Fall.
tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, false, "MST");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 11, 3, 2, 0, 0, -7 * 3600, false, "MST");
}
@@ -1218,7 +1218,7 @@ TEST(TimeZoneEdgeCase, AsiaKathmandu) {
// 504901800 == Wed, 1 Jan 1986 00:15:00 +0545 (+0545)
auto tp = convert(civil_second(1985, 12, 31, 23, 59, 59), tz);
ExpectTime(tp, tz, 1985, 12, 31, 23, 59, 59, 5.5 * 3600, false, "+0530");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 1986, 1, 1, 0, 15, 0, 5.75 * 3600, false, "+0545");
}
@@ -1231,14 +1231,14 @@ TEST(TimeZoneEdgeCase, PacificChatham) {
// 1365256800 == Sun, 7 Apr 2013 02:45:00 +1245 (+1245)
auto tp = convert(civil_second(2013, 4, 7, 3, 44, 59), tz);
ExpectTime(tp, tz, 2013, 4, 7, 3, 44, 59, 13.75 * 3600, true, "+1345");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 4, 7, 2, 45, 0, 12.75 * 3600, false, "+1245");
// 1380376799 == Sun, 29 Sep 2013 02:44:59 +1245 (+1245)
// 1380376800 == Sun, 29 Sep 2013 03:45:00 +1345 (+1345)
tp = convert(civil_second(2013, 9, 29, 2, 44, 59), tz);
ExpectTime(tp, tz, 2013, 9, 29, 2, 44, 59, 12.75 * 3600, false, "+1245");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 9, 29, 3, 45, 0, 13.75 * 3600, true, "+1345");
}
@@ -1251,14 +1251,14 @@ TEST(TimeZoneEdgeCase, AustraliaLordHowe) {
// 1365260400 == Sun, 7 Apr 2013 01:30:00 +1030 (+1030)
auto tp = convert(civil_second(2013, 4, 7, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 4, 7, 1, 59, 59, 11 * 3600, true, "+11");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 4, 7, 1, 30, 0, 10.5 * 3600, false, "+1030");
// 1380986999 == Sun, 6 Oct 2013 01:59:59 +1030 (+1030)
// 1380987000 == Sun, 6 Oct 2013 02:30:00 +1100 (+11)
tp = convert(civil_second(2013, 10, 6, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 10, 6, 1, 59, 59, 10.5 * 3600, false, "+1030");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 10, 6, 2, 30, 0, 11 * 3600, true, "+11");
}
@@ -1275,40 +1275,40 @@ TEST(TimeZoneEdgeCase, PacificApia) {
// 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14)
auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz);
ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10");
- EXPECT_EQ(363, get_yearday(convert(tp, tz)));
- tp += cctz::seconds(1);
+ EXPECT_EQ(363, get_yearday(convert(tp, tz)));
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14");
- EXPECT_EQ(365, get_yearday(convert(tp, tz)));
+ EXPECT_EQ(365, get_yearday(convert(tp, tz)));
}
TEST(TimeZoneEdgeCase, AfricaCairo) {
const time_zone tz = LoadZone("Africa/Cairo");
- if (VersionCmp(tz, "2014c") >= 0) {
- // An interesting case of midnight not existing.
- //
- // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
- // 1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST)
- auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz);
- ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
- tp += cctz::seconds(1);
- ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
- }
+ if (VersionCmp(tz, "2014c") >= 0) {
+ // An interesting case of midnight not existing.
+ //
+ // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
+ // 1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST)
+ auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
+ tp += cctz::seconds(1);
+ ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
+ }
}
TEST(TimeZoneEdgeCase, AfricaMonrovia) {
const time_zone tz = LoadZone("Africa/Monrovia");
- if (VersionCmp(tz, "2017b") >= 0) {
- // Strange offset change -00:44:30 -> +00:00:00 (non-DST)
- //
- // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT)
- // 63593070 == Fri, 7 Jan 1972 00:44:30 +0000 (GMT)
- auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
- ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
- tp += cctz::seconds(1);
- ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
- }
+ if (VersionCmp(tz, "2017b") >= 0) {
+ // Strange offset change -00:44:30 -> +00:00:00 (non-DST)
+ //
+ // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT)
+ // 63593070 == Fri, 7 Jan 1972 00:44:30 +0000 (GMT)
+ auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
+ tp += cctz::seconds(1);
+ ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
+ }
}
TEST(TimeZoneEdgeCase, AmericaJamaica) {
@@ -1320,31 +1320,31 @@ TEST(TimeZoneEdgeCase, AmericaJamaica) {
const time_zone tz = LoadZone("America/Jamaica");
// Before the first transition.
- if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) {
- // We avoid the expectations on the -18430 offset below unless we are
- // certain we have commit 907241e (Fix off-by-1 error for Jamaica and
- // T&C before 1913) from 2018d. TODO: Remove the "version() not empty"
- // part when 2018d is generally available from /usr/share/zoneinfo.
- auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz);
- ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false,
- tz.lookup(tp).abbr);
-
- // Over the first (abbreviation-change only) transition.
- // -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT)
- // -2524503169 == Wed, 1 Jan 1890 00:00:00 -0507 (KMT)
- tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz);
- ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false,
- tz.lookup(tp).abbr);
- tp += cctz::seconds(1);
- ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT");
- }
+ if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) {
+ // We avoid the expectations on the -18430 offset below unless we are
+ // certain we have commit 907241e (Fix off-by-1 error for Jamaica and
+ // T&C before 1913) from 2018d. TODO: Remove the "version() not empty"
+ // part when 2018d is generally available from /usr/share/zoneinfo.
+ auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz);
+ ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false,
+ tz.lookup(tp).abbr);
+
+ // Over the first (abbreviation-change only) transition.
+ // -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT)
+ // -2524503169 == Wed, 1 Jan 1890 00:00:00 -0507 (KMT)
+ tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false,
+ tz.lookup(tp).abbr);
+ tp += cctz::seconds(1);
+ ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT");
+ }
// Over the last (DST) transition.
// 436341599 == Sun, 30 Oct 1983 01:59:59 -0400 (EDT)
// 436341600 == Sun, 30 Oct 1983 01:00:00 -0500 (EST)
- auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz);
+ auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz);
ExpectTime(tp, tz, 1983, 10, 30, 1, 59, 59, -4 * 3600, true, "EDT");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 1983, 10, 30, 1, 0, 0, -5 * 3600, false, "EST");
// After the last transition.
@@ -1365,7 +1365,7 @@ TEST(TimeZoneEdgeCase, 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 += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST");
// A non-existent time within the first transition.
@@ -1387,12 +1387,12 @@ TEST(TimeZoneEdgeCase, FixedOffsets) {
const time_zone gmtm5 = LoadZone("Etc/GMT+5"); // -0500
auto tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtm5);
ExpectTime(tp, gmtm5, 1970, 1, 1, 0, 0, 0, -5 * 3600, false, "-05");
- EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp);
+ EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp);
const time_zone gmtp5 = LoadZone("Etc/GMT-5"); // +0500
tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtp5);
ExpectTime(tp, gmtp5, 1970, 1, 1, 0, 0, 0, 5 * 3600, false, "+05");
- EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp);
+ EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp);
}
TEST(TimeZoneEdgeCase, NegativeYear) {
@@ -1400,10 +1400,10 @@ TEST(TimeZoneEdgeCase, NegativeYear) {
const time_zone tz = utc_time_zone();
auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz);
ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
- EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz)));
- tp -= cctz::seconds(1);
+ EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz)));
+ tp -= cctz::seconds(1);
ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
- EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz)));
}
TEST(TimeZoneEdgeCase, UTC32bitLimit) {
@@ -1415,7 +1415,7 @@ TEST(TimeZoneEdgeCase, UTC32bitLimit) {
// 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 += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 8, 0 * 3600, false, "UTC");
}
@@ -1428,7 +1428,7 @@ TEST(TimeZoneEdgeCase, UTC5DigitYear) {
// 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 += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
}
diff --git a/contrib/libs/cctz/test/ya.make b/contrib/libs/cctz/test/ya.make
index 8815f9769d..57b9be0018 100644
--- a/contrib/libs/cctz/test/ya.make
+++ b/contrib/libs/cctz/test/ya.make
@@ -1,4 +1,4 @@
-GTEST()
+GTEST()
LICENSE(Apache-2.0)
@@ -10,26 +10,26 @@ OWNER(
)
PEERDIR(
- contrib/libs/cctz
+ contrib/libs/cctz
contrib/libs/cctz/tzdata
)
ADDINCL(
contrib/libs/cctz/include
)
-
-IF (NOT AUTOCHECK)
- # We do not set TZDIR to a stable data source, so
- # LoadZone("libc:localtime") is inconsistent and makes
- # LocalTimeLibC test fail on distbuild.
+
+IF (NOT AUTOCHECK)
+ # We do not set TZDIR to a stable data source, so
+ # LoadZone("libc:localtime") is inconsistent and makes
+ # LocalTimeLibC test fail on distbuild.
CFLAGS(
-DCCTZ_TEST_LIBC_LOCALTIME
)
-ENDIF()
-
+ENDIF()
+
SRCS(
civil_time_test.cc
- time_zone_format_test.cc
+ time_zone_format_test.cc
time_zone_lookup_test.cc
)