You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2018/04/29 19:35:46 UTC

[17/51] [partial] marmotta git commit: * Replace gtest with upstream version, including LICENSE header. * Include absl library for faster and safer string operations. * Update license headers where needed. * Removed custom code replaced by absl.

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/civil_time_test.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/civil_time_test.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/civil_time_test.cc
new file mode 100644
index 0000000..6df0395
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/civil_time_test.cc
@@ -0,0 +1,1049 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+
+#include <iomanip>
+#include <limits>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#include "gtest/gtest.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+template <typename T>
+std::string Format(const T& t) {
+  std::stringstream ss;
+  ss << t;
+  return ss.str();
+}
+
+}  // namespace
+
+#if __clang__ && __cpp_constexpr >= 201304
+// Construction constexpr tests
+
+TEST(CivilTime, Normal) {
+  constexpr civil_second css(2016, 1, 28, 17, 14, 12);
+  static_assert(css.second() == 12, "Normal.second");
+  constexpr civil_minute cmm(2016, 1, 28, 17, 14);
+  static_assert(cmm.minute() == 14, "Normal.minute");
+  constexpr civil_hour chh(2016, 1, 28, 17);
+  static_assert(chh.hour() == 17, "Normal.hour");
+  constexpr civil_day cd(2016, 1, 28);
+  static_assert(cd.day() == 28, "Normal.day");
+  constexpr civil_month cm(2016, 1);
+  static_assert(cm.month() == 1, "Normal.month");
+  constexpr civil_year cy(2016);
+  static_assert(cy.year() == 2016, "Normal.year");
+}
+
+TEST(CivilTime, Conversion) {
+  constexpr civil_year cy(2016);
+  static_assert(cy.year() == 2016, "Conversion.year");
+  constexpr civil_month cm(cy);
+  static_assert(cm.month() == 1, "Conversion.month");
+  constexpr civil_day cd(cm);
+  static_assert(cd.day() == 1, "Conversion.day");
+  constexpr civil_hour chh(cd);
+  static_assert(chh.hour() == 0, "Conversion.hour");
+  constexpr civil_minute cmm(chh);
+  static_assert(cmm.minute() == 0, "Conversion.minute");
+  constexpr civil_second css(cmm);
+  static_assert(css.second() == 0, "Conversion.second");
+}
+
+// Normalization constexpr tests
+
+TEST(CivilTime, Normalized) {
+  constexpr civil_second cs(2016, 1, 28, 17, 14, 12);
+  static_assert(cs.year() == 2016, "Normalized.year");
+  static_assert(cs.month() == 1, "Normalized.month");
+  static_assert(cs.day() == 28, "Normalized.day");
+  static_assert(cs.hour() == 17, "Normalized.hour");
+  static_assert(cs.minute() == 14, "Normalized.minute");
+  static_assert(cs.second() == 12, "Normalized.second");
+}
+
+TEST(CivilTime, SecondOverflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, 14, 121);
+  static_assert(cs.year() == 2016, "SecondOverflow.year");
+  static_assert(cs.month() == 1, "SecondOverflow.month");
+  static_assert(cs.day() == 28, "SecondOverflow.day");
+  static_assert(cs.hour() == 17, "SecondOverflow.hour");
+  static_assert(cs.minute() == 16, "SecondOverflow.minute");
+  static_assert(cs.second() == 1, "SecondOverflow.second");
+}
+
+TEST(CivilTime, SecondUnderflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, 14, -121);
+  static_assert(cs.year() == 2016, "SecondUnderflow.year");
+  static_assert(cs.month() == 1, "SecondUnderflow.month");
+  static_assert(cs.day() == 28, "SecondUnderflow.day");
+  static_assert(cs.hour() == 17, "SecondUnderflow.hour");
+  static_assert(cs.minute() == 11, "SecondUnderflow.minute");
+  static_assert(cs.second() == 59, "SecondUnderflow.second");
+}
+
+TEST(CivilTime, MinuteOverflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, 121, 12);
+  static_assert(cs.year() == 2016, "MinuteOverflow.year");
+  static_assert(cs.month() == 1, "MinuteOverflow.month");
+  static_assert(cs.day() == 28, "MinuteOverflow.day");
+  static_assert(cs.hour() == 19, "MinuteOverflow.hour");
+  static_assert(cs.minute() == 1, "MinuteOverflow.minute");
+  static_assert(cs.second() == 12, "MinuteOverflow.second");
+}
+
+TEST(CivilTime, MinuteUnderflow) {
+  constexpr civil_second cs(2016, 1, 28, 17, -121, 12);
+  static_assert(cs.year() == 2016, "MinuteUnderflow.year");
+  static_assert(cs.month() == 1, "MinuteUnderflow.month");
+  static_assert(cs.day() == 28, "MinuteUnderflow.day");
+  static_assert(cs.hour() == 14, "MinuteUnderflow.hour");
+  static_assert(cs.minute() == 59, "MinuteUnderflow.minute");
+  static_assert(cs.second() == 12, "MinuteUnderflow.second");
+}
+
+TEST(CivilTime, HourOverflow) {
+  constexpr civil_second cs(2016, 1, 28, 49, 14, 12);
+  static_assert(cs.year() == 2016, "HourOverflow.year");
+  static_assert(cs.month() == 1, "HourOverflow.month");
+  static_assert(cs.day() == 30, "HourOverflow.day");
+  static_assert(cs.hour() == 1, "HourOverflow.hour");
+  static_assert(cs.minute() == 14, "HourOverflow.minute");
+  static_assert(cs.second() == 12, "HourOverflow.second");
+}
+
+TEST(CivilTime, HourUnderflow) {
+  constexpr civil_second cs(2016, 1, 28, -49, 14, 12);
+  static_assert(cs.year() == 2016, "HourUnderflow.year");
+  static_assert(cs.month() == 1, "HourUnderflow.month");
+  static_assert(cs.day() == 25, "HourUnderflow.day");
+  static_assert(cs.hour() == 23, "HourUnderflow.hour");
+  static_assert(cs.minute() == 14, "HourUnderflow.minute");
+  static_assert(cs.second() == 12, "HourUnderflow.second");
+}
+
+TEST(CivilTime, MonthOverflow) {
+  constexpr civil_second cs(2016, 25, 28, 17, 14, 12);
+  static_assert(cs.year() == 2018, "MonthOverflow.year");
+  static_assert(cs.month() == 1, "MonthOverflow.month");
+  static_assert(cs.day() == 28, "MonthOverflow.day");
+  static_assert(cs.hour() == 17, "MonthOverflow.hour");
+  static_assert(cs.minute() == 14, "MonthOverflow.minute");
+  static_assert(cs.second() == 12, "MonthOverflow.second");
+}
+
+TEST(CivilTime, MonthUnderflow) {
+  constexpr civil_second cs(2016, -25, 28, 17, 14, 12);
+  static_assert(cs.year() == 2013, "MonthUnderflow.year");
+  static_assert(cs.month() == 11, "MonthUnderflow.month");
+  static_assert(cs.day() == 28, "MonthUnderflow.day");
+  static_assert(cs.hour() == 17, "MonthUnderflow.hour");
+  static_assert(cs.minute() == 14, "MonthUnderflow.minute");
+  static_assert(cs.second() == 12, "MonthUnderflow.second");
+}
+
+TEST(CivilTime, C4Overflow) {
+  constexpr civil_second cs(2016, 1, 292195, 17, 14, 12);
+  static_assert(cs.year() == 2816, "C4Overflow.year");
+  static_assert(cs.month() == 1, "C4Overflow.month");
+  static_assert(cs.day() == 1, "C4Overflow.day");
+  static_assert(cs.hour() == 17, "C4Overflow.hour");
+  static_assert(cs.minute() == 14, "C4Overflow.minute");
+  static_assert(cs.second() == 12, "C4Overflow.second");
+}
+
+TEST(CivilTime, C4Underflow) {
+  constexpr civil_second cs(2016, 1, -292195, 17, 14, 12);
+  static_assert(cs.year() == 1215, "C4Underflow.year");
+  static_assert(cs.month() == 12, "C4Underflow.month");
+  static_assert(cs.day() == 30, "C4Underflow.day");
+  static_assert(cs.hour() == 17, "C4Underflow.hour");
+  static_assert(cs.minute() == 14, "C4Underflow.minute");
+  static_assert(cs.second() == 12, "C4Underflow.second");
+}
+
+TEST(CivilTime, MixedNormalization) {
+  constexpr civil_second cs(2016, -42, 122, 99, -147, 4949);
+  static_assert(cs.year() == 2012, "MixedNormalization.year");
+  static_assert(cs.month() == 10, "MixedNormalization.month");
+  static_assert(cs.day() == 4, "MixedNormalization.day");
+  static_assert(cs.hour() == 1, "MixedNormalization.hour");
+  static_assert(cs.minute() == 55, "MixedNormalization.minute");
+  static_assert(cs.second() == 29, "MixedNormalization.second");
+}
+
+// Relational constexpr tests
+
+TEST(CivilTime, Less) {
+  constexpr civil_second cs1(2016, 1, 28, 17, 14, 12);
+  constexpr civil_second cs2(2016, 1, 28, 17, 14, 13);
+  constexpr bool less = cs1 < cs2;
+  static_assert(less, "Less");
+}
+
+// Arithmetic constexpr tests
+
+TEST(CivilTime, Addition) {
+  constexpr civil_second cs1(2016, 1, 28, 17, 14, 12);
+  constexpr civil_second cs2 = cs1 + 50;
+  static_assert(cs2.year() == 2016, "Addition.year");
+  static_assert(cs2.month() == 1, "Addition.month");
+  static_assert(cs2.day() == 28, "Addition.day");
+  static_assert(cs2.hour() == 17, "Addition.hour");
+  static_assert(cs2.minute() == 15, "Addition.minute");
+  static_assert(cs2.second() == 2, "Addition.second");
+}
+
+TEST(CivilTime, Subtraction) {
+  constexpr civil_second cs1(2016, 1, 28, 17, 14, 12);
+  constexpr civil_second cs2 = cs1 - 50;
+  static_assert(cs2.year() == 2016, "Subtraction.year");
+  static_assert(cs2.month() == 1, "Subtraction.month");
+  static_assert(cs2.day() == 28, "Subtraction.day");
+  static_assert(cs2.hour() == 17, "Subtraction.hour");
+  static_assert(cs2.minute() == 13, "Subtraction.minute");
+  static_assert(cs2.second() == 22, "Subtraction.second");
+}
+
+TEST(CivilTime, Difference) {
+  constexpr civil_day cd1(2016, 1, 28);
+  constexpr civil_day cd2(2015, 1, 28);
+  constexpr int diff = cd1 - cd2;
+  static_assert(diff == 365, "Difference");
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, DifferenceWithHugeYear) {
+  {
+    constexpr civil_day d1(9223372036854775807, 1, 1);
+    constexpr civil_day d2(9223372036854775807, 12, 31);
+    static_assert(d2 - d1 == 364, "DifferenceWithHugeYear");
+  }
+  {
+    constexpr civil_day d1(-9223372036854775807 - 1, 1, 1);
+    constexpr civil_day d2(-9223372036854775807 - 1, 12, 31);
+    static_assert(d2 - d1 == 365, "DifferenceWithHugeYear");
+  }
+  {
+    // Check the limits of the return value at the end of the year range.
+    constexpr civil_day d1(9223372036854775807, 1, 1);
+    constexpr civil_day d2(9198119301927009252, 6, 6);
+    static_assert(d1 - d2 == 9223372036854775807, "DifferenceWithHugeYear");
+    static_assert((d2 - 1) - d1 == -9223372036854775807 - 1,
+                  "DifferenceWithHugeYear");
+  }
+  {
+    // Check the limits of the return value at the start of the year range.
+    constexpr civil_day d1(-9223372036854775807 - 1, 1, 1);
+    constexpr civil_day d2(-9198119301927009254, 7, 28);
+    static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear");
+    static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1,
+                  "DifferenceWithHugeYear");
+  }
+  {
+    // Check the limits of the return value from either side of year 0.
+    constexpr civil_day d1(-12626367463883278, 9, 3);
+    constexpr civil_day d2(12626367463883277, 3, 28);
+    static_assert(d2 - d1 == 9223372036854775807, "DifferenceWithHugeYear");
+    static_assert(d1 - (d2 + 1) == -9223372036854775807 - 1,
+                  "DifferenceWithHugeYear");
+  }
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, DifferenceNoIntermediateOverflow) {
+  {
+    // The difference up to the minute field would be below the minimum
+    // diff_t, but the 52 extra seconds brings us back to the minimum.
+    constexpr civil_second s1(-292277022657, 1, 27, 8, 29 - 1, 52);
+    constexpr civil_second s2(1970, 1, 1, 0, 0 - 1, 0);
+    static_assert(s1 - s2 == -9223372036854775807 - 1,
+                  "DifferenceNoIntermediateOverflow");
+  }
+  {
+    // The difference up to the minute field would be above the maximum
+    // diff_t, but the -53 extra seconds brings us back to the maximum.
+    constexpr civil_second s1(292277026596, 12, 4, 15, 30, 7 - 7);
+    constexpr civil_second s2(1970, 1, 1, 0, 0, 0 - 7);
+    static_assert(s1 - s2 == 9223372036854775807,
+                  "DifferenceNoIntermediateOverflow");
+  }
+}
+
+// Helper constexpr tests
+
+TEST(CivilTime, WeekDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr weekday wd = get_weekday(cd);
+  static_assert(wd == weekday::thursday, "Weekday");
+}
+
+TEST(CivilTime, NextWeekDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr civil_day next = next_weekday(cd, weekday::thursday);
+  static_assert(next.year() == 2016, "NextWeekDay.year");
+  static_assert(next.month() == 2, "NextWeekDay.month");
+  static_assert(next.day() == 4, "NextWeekDay.day");
+}
+
+TEST(CivilTime, PrevWeekDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr civil_day prev = prev_weekday(cd, weekday::thursday);
+  static_assert(prev.year() == 2016, "PrevWeekDay.year");
+  static_assert(prev.month() == 1, "PrevWeekDay.month");
+  static_assert(prev.day() == 21, "PrevWeekDay.day");
+}
+
+TEST(CivilTime, YearDay) {
+  constexpr civil_day cd(2016, 1, 28);
+  constexpr int yd = get_yearday(cd);
+  static_assert(yd == 28, "YearDay");
+}
+#endif  // __clang__ && __cpp_constexpr >= 201304
+
+// The remaining tests do not use constexpr.
+
+TEST(CivilTime, DefaultConstruction) {
+  civil_second ss;
+  EXPECT_EQ("1970-01-01T00:00:00", Format(ss));
+
+  civil_minute mm;
+  EXPECT_EQ("1970-01-01T00:00", Format(mm));
+
+  civil_hour hh;
+  EXPECT_EQ("1970-01-01T00", Format(hh));
+
+  civil_day d;
+  EXPECT_EQ("1970-01-01", Format(d));
+
+  civil_month m;
+  EXPECT_EQ("1970-01", Format(m));
+
+  civil_year y;
+  EXPECT_EQ("1970", Format(y));
+}
+
+TEST(CivilTime, StructMember) {
+  struct S {
+    civil_day day;
+  };
+  S s = {};
+  EXPECT_EQ(civil_day{}, s.day);
+}
+
+TEST(CivilTime, FieldsConstruction) {
+  EXPECT_EQ("2015-01-02T03:04:05", Format(civil_second(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02T03:04:00", Format(civil_second(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02T03:00:00", Format(civil_second(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02T00:00:00", Format(civil_second(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015, 1)));
+  EXPECT_EQ("2015-01-01T00:00:00", Format(civil_second(2015)));
+
+  EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02T03:04", Format(civil_minute(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02T03:00", Format(civil_minute(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02T00:00", Format(civil_minute(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015, 1)));
+  EXPECT_EQ("2015-01-01T00:00", Format(civil_minute(2015)));
+
+  EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02T03", Format(civil_hour(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02T00", Format(civil_hour(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015, 1)));
+  EXPECT_EQ("2015-01-01T00", Format(civil_hour(2015)));
+
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01-02", Format(civil_day(2015, 1, 2)));
+  EXPECT_EQ("2015-01-01", Format(civil_day(2015, 1)));
+  EXPECT_EQ("2015-01-01", Format(civil_day(2015)));
+
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2, 3)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1, 2)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015, 1)));
+  EXPECT_EQ("2015-01", Format(civil_month(2015)));
+
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4, 5)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3, 4)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2, 3)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1, 2)));
+  EXPECT_EQ("2015", Format(civil_year(2015, 1)));
+  EXPECT_EQ("2015", Format(civil_year(2015)));
+}
+
+TEST(CivilTime, FieldsConstructionLimits) {
+  const int kIntMax = std::numeric_limits<int>::max();
+  EXPECT_EQ("2038-01-19T03:14:07",
+            Format(civil_second(1970, 1, 1, 0, 0, kIntMax)));
+  EXPECT_EQ("6121-02-11T05:21:07",
+            Format(civil_second(1970, 1, 1, 0, kIntMax, kIntMax)));
+  EXPECT_EQ("251104-11-20T12:21:07",
+            Format(civil_second(1970, 1, 1, kIntMax, kIntMax, kIntMax)));
+  EXPECT_EQ("6130715-05-30T12:21:07",
+            Format(civil_second(1970, 1, kIntMax, kIntMax, kIntMax, kIntMax)));
+  EXPECT_EQ(
+      "185087685-11-26T12:21:07",
+      Format(civil_second(1970, kIntMax, kIntMax, kIntMax, kIntMax, kIntMax)));
+
+  const int kIntMin = std::numeric_limits<int>::min();
+  EXPECT_EQ("1901-12-13T20:45:52",
+            Format(civil_second(1970, 1, 1, 0, 0, kIntMin)));
+  EXPECT_EQ("-2182-11-20T18:37:52",
+            Format(civil_second(1970, 1, 1, 0, kIntMin, kIntMin)));
+  EXPECT_EQ("-247165-02-11T10:37:52",
+            Format(civil_second(1970, 1, 1, kIntMin, kIntMin, kIntMin)));
+  EXPECT_EQ("-6126776-08-01T10:37:52",
+            Format(civil_second(1970, 1, kIntMin, kIntMin, kIntMin, kIntMin)));
+  EXPECT_EQ(
+      "-185083747-10-31T10:37:52",
+      Format(civil_second(1970, kIntMin, kIntMin, kIntMin, kIntMin, kIntMin)));
+}
+
+TEST(CivilTime, ImplicitCrossAlignment) {
+  civil_year year(2015);
+  civil_month month = year;
+  civil_day day = month;
+  civil_hour hour = day;
+  civil_minute minute = hour;
+  civil_second second = minute;
+
+  second = year;
+  EXPECT_EQ(second, year);
+  second = month;
+  EXPECT_EQ(second, month);
+  second = day;
+  EXPECT_EQ(second, day);
+  second = hour;
+  EXPECT_EQ(second, hour);
+  second = minute;
+  EXPECT_EQ(second, minute);
+
+  minute = year;
+  EXPECT_EQ(minute, year);
+  minute = month;
+  EXPECT_EQ(minute, month);
+  minute = day;
+  EXPECT_EQ(minute, day);
+  minute = hour;
+  EXPECT_EQ(minute, hour);
+
+  hour = year;
+  EXPECT_EQ(hour, year);
+  hour = month;
+  EXPECT_EQ(hour, month);
+  hour = day;
+  EXPECT_EQ(hour, day);
+
+  day = year;
+  EXPECT_EQ(day, year);
+  day = month;
+  EXPECT_EQ(day, month);
+
+  month = year;
+  EXPECT_EQ(month, year);
+
+  // Ensures unsafe conversions are not allowed.
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_minute>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_hour>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_day>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_second, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_hour>::value));
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_day>::value));
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_minute, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_hour, civil_day>::value));
+  EXPECT_FALSE((std::is_convertible<civil_hour, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_hour, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_day, civil_month>::value));
+  EXPECT_FALSE((std::is_convertible<civil_day, civil_year>::value));
+
+  EXPECT_FALSE((std::is_convertible<civil_month, civil_year>::value));
+}
+
+TEST(CivilTime, ExplicitCrossAlignment) {
+  //
+  // Assign from smaller units -> larger units
+  //
+
+  civil_second second(2015, 1, 2, 3, 4, 5);
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second));
+
+  civil_minute minute(second);
+  EXPECT_EQ("2015-01-02T03:04", Format(minute));
+
+  civil_hour hour(minute);
+  EXPECT_EQ("2015-01-02T03", Format(hour));
+
+  civil_day day(hour);
+  EXPECT_EQ("2015-01-02", Format(day));
+
+  civil_month month(day);
+  EXPECT_EQ("2015-01", Format(month));
+
+  civil_year year(month);
+  EXPECT_EQ("2015", Format(year));
+
+  //
+  // Now assign from larger units -> smaller units
+  //
+
+  month = civil_month(year);
+  EXPECT_EQ("2015-01", Format(month));
+
+  day = civil_day(month);
+  EXPECT_EQ("2015-01-01", Format(day));
+
+  hour = civil_hour(day);
+  EXPECT_EQ("2015-01-01T00", Format(hour));
+
+  minute = civil_minute(hour);
+  EXPECT_EQ("2015-01-01T00:00", Format(minute));
+
+  second = civil_second(minute);
+  EXPECT_EQ("2015-01-01T00:00:00", Format(second));
+}
+
+// Metafunction to test whether difference is allowed between two types.
+template <typename T1, typename T2>
+struct HasDifference {
+  template <typename U1, typename U2>
+  static std::false_type test(...);
+  template <typename U1, typename U2>
+  static std::true_type test(decltype(std::declval<U1>() - std::declval<U2>()));
+  static constexpr bool value = decltype(test<T1, T2>(0))::value;
+};
+
+TEST(CivilTime, DisallowCrossAlignedDifference) {
+  // Difference is allowed between types with the same alignment.
+  static_assert(HasDifference<civil_second, civil_second>::value, "");
+  static_assert(HasDifference<civil_minute, civil_minute>::value, "");
+  static_assert(HasDifference<civil_hour, civil_hour>::value, "");
+  static_assert(HasDifference<civil_day, civil_day>::value, "");
+  static_assert(HasDifference<civil_month, civil_month>::value, "");
+  static_assert(HasDifference<civil_year, civil_year>::value, "");
+
+  // Difference is disallowed between types with different alignments.
+  static_assert(!HasDifference<civil_second, civil_minute>::value, "");
+  static_assert(!HasDifference<civil_second, civil_hour>::value, "");
+  static_assert(!HasDifference<civil_second, civil_day>::value, "");
+  static_assert(!HasDifference<civil_second, civil_month>::value, "");
+  static_assert(!HasDifference<civil_second, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_minute, civil_hour>::value, "");
+  static_assert(!HasDifference<civil_minute, civil_day>::value, "");
+  static_assert(!HasDifference<civil_minute, civil_month>::value, "");
+  static_assert(!HasDifference<civil_minute, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_hour, civil_day>::value, "");
+  static_assert(!HasDifference<civil_hour, civil_month>::value, "");
+  static_assert(!HasDifference<civil_hour, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_day, civil_month>::value, "");
+  static_assert(!HasDifference<civil_day, civil_year>::value, "");
+
+  static_assert(!HasDifference<civil_month, civil_year>::value, "");
+}
+
+TEST(CivilTime, ValueSemantics) {
+  const civil_hour a(2015, 1, 2, 3);
+  const civil_hour b = a;
+  const civil_hour c(b);
+  civil_hour d;
+  d = c;
+  EXPECT_EQ("2015-01-02T03", Format(d));
+}
+
+TEST(CivilTime, Relational) {
+  // Tests that the alignment unit is ignored in comparison.
+  const civil_year year(2014);
+  const civil_month month(year);
+  EXPECT_EQ(year, month);
+
+#define TEST_RELATIONAL(OLDER, YOUNGER) \
+  do {                                  \
+    EXPECT_FALSE(OLDER < OLDER);        \
+    EXPECT_FALSE(OLDER > OLDER);        \
+    EXPECT_TRUE(OLDER >= OLDER);        \
+    EXPECT_TRUE(OLDER <= OLDER);        \
+    EXPECT_FALSE(YOUNGER < YOUNGER);    \
+    EXPECT_FALSE(YOUNGER > YOUNGER);    \
+    EXPECT_TRUE(YOUNGER >= YOUNGER);    \
+    EXPECT_TRUE(YOUNGER <= YOUNGER);    \
+    EXPECT_EQ(OLDER, OLDER);            \
+    EXPECT_NE(OLDER, YOUNGER);          \
+    EXPECT_LT(OLDER, YOUNGER);          \
+    EXPECT_LE(OLDER, YOUNGER);          \
+    EXPECT_GT(YOUNGER, OLDER);          \
+    EXPECT_GE(YOUNGER, OLDER);          \
+  } while (0)
+
+  // Alignment is ignored in comparison (verified above), so kSecond is used
+  // to test comparison in all field positions.
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2015, 1, 1, 0, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2014, 2, 1, 0, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2014, 1, 2, 0, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 0, 0, 0),
+                  civil_second(2014, 1, 1, 1, 0, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 0, 0),
+                  civil_second(2014, 1, 1, 1, 1, 0));
+  TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 1, 0),
+                  civil_second(2014, 1, 1, 1, 1, 1));
+
+  // Tests the relational operators of two different CivilTime types.
+  TEST_RELATIONAL(civil_day(2014, 1, 1), civil_minute(2014, 1, 1, 1, 1));
+  TEST_RELATIONAL(civil_day(2014, 1, 1), civil_month(2014, 2));
+
+#undef TEST_RELATIONAL
+}
+
+TEST(CivilTime, Arithmetic) {
+  civil_second second(2015, 1, 2, 3, 4, 5);
+  EXPECT_EQ("2015-01-02T03:04:06", Format(second += 1));
+  EXPECT_EQ("2015-01-02T03:04:07", Format(second + 1));
+  EXPECT_EQ("2015-01-02T03:04:08", Format(2 + second));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second - 1));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second -= 1));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(second++));
+  EXPECT_EQ("2015-01-02T03:04:07", Format(++second));
+  EXPECT_EQ("2015-01-02T03:04:07", Format(second--));
+  EXPECT_EQ("2015-01-02T03:04:05", Format(--second));
+
+  civil_minute minute(2015, 1, 2, 3, 4);
+  EXPECT_EQ("2015-01-02T03:05", Format(minute += 1));
+  EXPECT_EQ("2015-01-02T03:06", Format(minute + 1));
+  EXPECT_EQ("2015-01-02T03:07", Format(2 + minute));
+  EXPECT_EQ("2015-01-02T03:04", Format(minute - 1));
+  EXPECT_EQ("2015-01-02T03:04", Format(minute -= 1));
+  EXPECT_EQ("2015-01-02T03:04", Format(minute++));
+  EXPECT_EQ("2015-01-02T03:06", Format(++minute));
+  EXPECT_EQ("2015-01-02T03:06", Format(minute--));
+  EXPECT_EQ("2015-01-02T03:04", Format(--minute));
+
+  civil_hour hour(2015, 1, 2, 3);
+  EXPECT_EQ("2015-01-02T04", Format(hour += 1));
+  EXPECT_EQ("2015-01-02T05", Format(hour + 1));
+  EXPECT_EQ("2015-01-02T06", Format(2 + hour));
+  EXPECT_EQ("2015-01-02T03", Format(hour - 1));
+  EXPECT_EQ("2015-01-02T03", Format(hour -= 1));
+  EXPECT_EQ("2015-01-02T03", Format(hour++));
+  EXPECT_EQ("2015-01-02T05", Format(++hour));
+  EXPECT_EQ("2015-01-02T05", Format(hour--));
+  EXPECT_EQ("2015-01-02T03", Format(--hour));
+
+  civil_day day(2015, 1, 2);
+  EXPECT_EQ("2015-01-03", Format(day += 1));
+  EXPECT_EQ("2015-01-04", Format(day + 1));
+  EXPECT_EQ("2015-01-05", Format(2 + day));
+  EXPECT_EQ("2015-01-02", Format(day - 1));
+  EXPECT_EQ("2015-01-02", Format(day -= 1));
+  EXPECT_EQ("2015-01-02", Format(day++));
+  EXPECT_EQ("2015-01-04", Format(++day));
+  EXPECT_EQ("2015-01-04", Format(day--));
+  EXPECT_EQ("2015-01-02", Format(--day));
+
+  civil_month month(2015, 1);
+  EXPECT_EQ("2015-02", Format(month += 1));
+  EXPECT_EQ("2015-03", Format(month + 1));
+  EXPECT_EQ("2015-04", Format(2 + month));
+  EXPECT_EQ("2015-01", Format(month - 1));
+  EXPECT_EQ("2015-01", Format(month -= 1));
+  EXPECT_EQ("2015-01", Format(month++));
+  EXPECT_EQ("2015-03", Format(++month));
+  EXPECT_EQ("2015-03", Format(month--));
+  EXPECT_EQ("2015-01", Format(--month));
+
+  civil_year year(2015);
+  EXPECT_EQ("2016", Format(year += 1));
+  EXPECT_EQ("2017", Format(year + 1));
+  EXPECT_EQ("2018", Format(2 + year));
+  EXPECT_EQ("2015", Format(year - 1));
+  EXPECT_EQ("2015", Format(year -= 1));
+  EXPECT_EQ("2015", Format(year++));
+  EXPECT_EQ("2017", Format(++year));
+  EXPECT_EQ("2017", Format(year--));
+  EXPECT_EQ("2015", Format(--year));
+}
+
+TEST(CivilTime, ArithmeticLimits) {
+  const int kIntMax = std::numeric_limits<int>::max();
+  const int kIntMin = std::numeric_limits<int>::min();
+
+  civil_second second(1970, 1, 1, 0, 0, 0);
+  second += kIntMax;
+  EXPECT_EQ("2038-01-19T03:14:07", Format(second));
+  second -= kIntMax;
+  EXPECT_EQ("1970-01-01T00:00:00", Format(second));
+  second += kIntMin;
+  EXPECT_EQ("1901-12-13T20:45:52", Format(second));
+  second -= kIntMin;
+  EXPECT_EQ("1970-01-01T00:00:00", Format(second));
+
+  civil_minute minute(1970, 1, 1, 0, 0);
+  minute += kIntMax;
+  EXPECT_EQ("6053-01-23T02:07", Format(minute));
+  minute -= kIntMax;
+  EXPECT_EQ("1970-01-01T00:00", Format(minute));
+  minute += kIntMin;
+  EXPECT_EQ("-2114-12-08T21:52", Format(minute));
+  minute -= kIntMin;
+  EXPECT_EQ("1970-01-01T00:00", Format(minute));
+
+  civil_hour hour(1970, 1, 1, 0);
+  hour += kIntMax;
+  EXPECT_EQ("246953-10-09T07", Format(hour));
+  hour -= kIntMax;
+  EXPECT_EQ("1970-01-01T00", Format(hour));
+  hour += kIntMin;
+  EXPECT_EQ("-243014-03-24T16", Format(hour));
+  hour -= kIntMin;
+  EXPECT_EQ("1970-01-01T00", Format(hour));
+
+  civil_day day(1970, 1, 1);
+  day += kIntMax;
+  EXPECT_EQ("5881580-07-11", Format(day));
+  day -= kIntMax;
+  EXPECT_EQ("1970-01-01", Format(day));
+  day += kIntMin;
+  EXPECT_EQ("-5877641-06-23", Format(day));
+  day -= kIntMin;
+  EXPECT_EQ("1970-01-01", Format(day));
+
+  civil_month month(1970, 1);
+  month += kIntMax;
+  EXPECT_EQ("178958940-08", Format(month));
+  month -= kIntMax;
+  EXPECT_EQ("1970-01", Format(month));
+  month += kIntMin;
+  EXPECT_EQ("-178955001-05", Format(month));
+  month -= kIntMin;
+  EXPECT_EQ("1970-01", Format(month));
+
+  civil_year year(0);
+  year += kIntMax;
+  EXPECT_EQ("2147483647", Format(year));
+  year -= kIntMax;
+  EXPECT_EQ("0", Format(year));
+  year += kIntMin;
+  EXPECT_EQ("-2147483648", Format(year));
+  year -= kIntMin;
+  EXPECT_EQ("0", Format(year));
+}
+
+TEST(CivilTime, ArithmeticDifference) {
+  civil_second second(2015, 1, 2, 3, 4, 5);
+  EXPECT_EQ(0, second - second);
+  EXPECT_EQ(10, (second + 10) - second);
+  EXPECT_EQ(-10, (second - 10) - second);
+
+  civil_minute minute(2015, 1, 2, 3, 4);
+  EXPECT_EQ(0, minute - minute);
+  EXPECT_EQ(10, (minute + 10) - minute);
+  EXPECT_EQ(-10, (minute - 10) - minute);
+
+  civil_hour hour(2015, 1, 2, 3);
+  EXPECT_EQ(0, hour - hour);
+  EXPECT_EQ(10, (hour + 10) - hour);
+  EXPECT_EQ(-10, (hour - 10) - hour);
+
+  civil_day day(2015, 1, 2);
+  EXPECT_EQ(0, day - day);
+  EXPECT_EQ(10, (day + 10) - day);
+  EXPECT_EQ(-10, (day - 10) - day);
+
+  civil_month month(2015, 1);
+  EXPECT_EQ(0, month - month);
+  EXPECT_EQ(10, (month + 10) - month);
+  EXPECT_EQ(-10, (month - 10) - month);
+
+  civil_year year(2015);
+  EXPECT_EQ(0, year - year);
+  EXPECT_EQ(10, (year + 10) - year);
+  EXPECT_EQ(-10, (year - 10) - year);
+}
+
+TEST(CivilTime, DifferenceLimits) {
+  const int kIntMax = std::numeric_limits<int>::max();
+  const int kIntMin = std::numeric_limits<int>::min();
+
+  // Check day arithmetic at the end of the year range.
+  const civil_day max_day(kIntMax, 12, 31);
+  EXPECT_EQ(1, max_day - (max_day - 1));
+  EXPECT_EQ(-1, (max_day - 1) - max_day);
+
+  // Check day arithmetic at the end of the year range.
+  const civil_day min_day(kIntMin, 1, 1);
+  EXPECT_EQ(1, (min_day + 1) - min_day);
+  EXPECT_EQ(-1, min_day - (min_day + 1));
+
+  // Check the limits of the return value.
+  const civil_day d1(1970, 1, 1);
+  const civil_day d2(5881580, 7, 11);
+  EXPECT_EQ(kIntMax, d2 - d1);
+  EXPECT_EQ(kIntMin, d1 - (d2 + 1));
+}
+
+TEST(CivilTime, Properties) {
+  civil_second ss(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, ss.year());
+  EXPECT_EQ(2, ss.month());
+  EXPECT_EQ(3, ss.day());
+  EXPECT_EQ(4, ss.hour());
+  EXPECT_EQ(5, ss.minute());
+  EXPECT_EQ(6, ss.second());
+
+  civil_minute mm(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, mm.year());
+  EXPECT_EQ(2, mm.month());
+  EXPECT_EQ(3, mm.day());
+  EXPECT_EQ(4, mm.hour());
+  EXPECT_EQ(5, mm.minute());
+  EXPECT_EQ(0, mm.second());
+
+  civil_hour hh(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, hh.year());
+  EXPECT_EQ(2, hh.month());
+  EXPECT_EQ(3, hh.day());
+  EXPECT_EQ(4, hh.hour());
+  EXPECT_EQ(0, hh.minute());
+  EXPECT_EQ(0, hh.second());
+
+  civil_day d(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, d.year());
+  EXPECT_EQ(2, d.month());
+  EXPECT_EQ(3, d.day());
+  EXPECT_EQ(0, d.hour());
+  EXPECT_EQ(0, d.minute());
+  EXPECT_EQ(0, d.second());
+  EXPECT_EQ(weekday::tuesday, get_weekday(d));
+  EXPECT_EQ(34, get_yearday(d));
+
+  civil_month m(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, m.year());
+  EXPECT_EQ(2, m.month());
+  EXPECT_EQ(1, m.day());
+  EXPECT_EQ(0, m.hour());
+  EXPECT_EQ(0, m.minute());
+  EXPECT_EQ(0, m.second());
+
+  civil_year y(2015, 2, 3, 4, 5, 6);
+  EXPECT_EQ(2015, y.year());
+  EXPECT_EQ(1, y.month());
+  EXPECT_EQ(1, y.day());
+  EXPECT_EQ(0, y.hour());
+  EXPECT_EQ(0, y.minute());
+  EXPECT_EQ(0, y.second());
+}
+
+TEST(CivilTime, OutputStream) {
+  // Tests formatting of civil_year, which does not pad.
+  EXPECT_EQ("2016", Format(civil_year(2016)));
+  EXPECT_EQ("123", Format(civil_year(123)));
+  EXPECT_EQ("0", Format(civil_year(0)));
+  EXPECT_EQ("-1", Format(civil_year(-1)));
+
+  // Tests formatting of sub-year types, which pad to 2 digits
+  EXPECT_EQ("2016-02", Format(civil_month(2016, 2)));
+  EXPECT_EQ("2016-02-03", Format(civil_day(2016, 2, 3)));
+  EXPECT_EQ("2016-02-03T04", Format(civil_hour(2016, 2, 3, 4)));
+  EXPECT_EQ("2016-02-03T04:05", Format(civil_minute(2016, 2, 3, 4, 5)));
+  EXPECT_EQ("2016-02-03T04:05:06", Format(civil_second(2016, 2, 3, 4, 5, 6)));
+
+  // Tests formatting of weekday.
+  EXPECT_EQ("Monday", Format(weekday::monday));
+  EXPECT_EQ("Tuesday", Format(weekday::tuesday));
+  EXPECT_EQ("Wednesday", Format(weekday::wednesday));
+  EXPECT_EQ("Thursday", Format(weekday::thursday));
+  EXPECT_EQ("Friday", Format(weekday::friday));
+  EXPECT_EQ("Saturday", Format(weekday::saturday));
+  EXPECT_EQ("Sunday", Format(weekday::sunday));
+}
+
+TEST(CivilTime, OutputStreamLeftFillWidth) {
+  civil_second cs(2016, 2, 3, 4, 5, 6);
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_year(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016.................X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_month(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02..............X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_day(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03...........X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_hour(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03T04........X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_minute(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03T04:05.....X..", ss.str());
+  }
+  {
+    std::stringstream ss;
+    ss << std::left << std::setfill('.');
+    ss << std::setw(3) << 'X';
+    ss << std::setw(21) << civil_second(cs);
+    ss << std::setw(3) << 'X';
+    EXPECT_EQ("X..2016-02-03T04:05:06..X..", ss.str());
+  }
+}
+
+TEST(CivilTime, NextPrevWeekday) {
+  // Jan 1, 1970 was a Thursday.
+  const civil_day thursday(1970, 1, 1);
+  EXPECT_EQ(weekday::thursday, get_weekday(thursday));
+
+  // Thursday -> Thursday
+  civil_day d = next_weekday(thursday, weekday::thursday);
+  EXPECT_EQ(7, d - thursday) << Format(d);
+  EXPECT_EQ(d - 14, prev_weekday(thursday, weekday::thursday));
+
+  // Thursday -> Friday
+  d = next_weekday(thursday, weekday::friday);
+  EXPECT_EQ(1, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::friday));
+
+  // Thursday -> Saturday
+  d = next_weekday(thursday, weekday::saturday);
+  EXPECT_EQ(2, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::saturday));
+
+  // Thursday -> Sunday
+  d = next_weekday(thursday, weekday::sunday);
+  EXPECT_EQ(3, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::sunday));
+
+  // Thursday -> Monday
+  d = next_weekday(thursday, weekday::monday);
+  EXPECT_EQ(4, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::monday));
+
+  // Thursday -> Tuesday
+  d = next_weekday(thursday, weekday::tuesday);
+  EXPECT_EQ(5, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::tuesday));
+
+  // Thursday -> Wednesday
+  d = next_weekday(thursday, weekday::wednesday);
+  EXPECT_EQ(6, d - thursday) << Format(d);
+  EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::wednesday));
+}
+
+TEST(CivilTime, NormalizeWithHugeYear) {
+  civil_month c(9223372036854775807, 1);
+  EXPECT_EQ("9223372036854775807-01", Format(c));
+  c = c - 1;  // Causes normalization
+  EXPECT_EQ("9223372036854775806-12", Format(c));
+
+  c = civil_month(-9223372036854775807 - 1, 1);
+  EXPECT_EQ("-9223372036854775808-01", Format(c));
+  c = c + 12;  // Causes normalization
+  EXPECT_EQ("-9223372036854775807-01", Format(c));
+}
+
+TEST(CivilTime, LeapYears) {
+  // Test data for leap years.
+  const struct {
+    int year;
+    int days;
+    struct {
+      int month;
+      int day;
+    } leap_day;  // The date of the day after Feb 28.
+  } kLeapYearTable[]{
+      {1900, 365, {3, 1}},
+      {1999, 365, {3, 1}},
+      {2000, 366, {2, 29}},  // leap year
+      {2001, 365, {3, 1}},
+      {2002, 365, {3, 1}},
+      {2003, 365, {3, 1}},
+      {2004, 366, {2, 29}},  // leap year
+      {2005, 365, {3, 1}},
+      {2006, 365, {3, 1}},
+      {2007, 365, {3, 1}},
+      {2008, 366, {2, 29}},  // leap year
+      {2009, 365, {3, 1}},
+      {2100, 365, {3, 1}},
+  };
+
+  for (const auto& e : kLeapYearTable) {
+    // Tests incrementing through the leap day.
+    const civil_day feb28(e.year, 2, 28);
+    const civil_day next_day = feb28 + 1;
+    EXPECT_EQ(e.leap_day.month, next_day.month());
+    EXPECT_EQ(e.leap_day.day, next_day.day());
+
+    // Tests difference in days of leap years.
+    const civil_year year(feb28);
+    const civil_year next_year = year + 1;
+    EXPECT_EQ(e.days, civil_day(next_year) - civil_day(year));
+  }
+}
+
+TEST(CivilTime, FirstThursdayInMonth) {
+  const civil_day nov1(2014, 11, 1);
+  const civil_day thursday = prev_weekday(nov1, weekday::thursday) + 7;
+  EXPECT_EQ("2014-11-06", Format(thursday));
+
+  // Bonus: Date of Thanksgiving in the United States
+  // Rule: Fourth Thursday of November
+  const civil_day thanksgiving = thursday + 7 * 3;
+  EXPECT_EQ("2014-11-27", Format(thanksgiving));
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
new file mode 100644
index 0000000..8d3b144
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -0,0 +1,133 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#include "time_zone_fixed.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+namespace {
+
+// The prefix used for the internal names of fixed-offset zones.
+const char kFixedOffsetPrefix[] = "Fixed/";
+
+int Parse02d(const char* p) {
+  static const char kDigits[] = "0123456789";
+  if (const char* ap = std::strchr(kDigits, *p)) {
+    int v = static_cast<int>(ap - kDigits);
+    if (const char* bp = std::strchr(kDigits, *++p)) {
+      return (v * 10) + static_cast<int>(bp - kDigits);
+    }
+  }
+  return -1;
+}
+
+}  // namespace
+
+bool FixedOffsetFromName(const std::string& name, sys_seconds* offset) {
+  if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
+    *offset = sys_seconds::zero();
+    return true;
+  }
+
+  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+  const char* const ep = kFixedOffsetPrefix + prefix_len;
+  if (name.size() != prefix_len + 12)  // "<prefix>UTC+99:99:99"
+    return false;
+  if (!std::equal(kFixedOffsetPrefix, ep, name.begin()))
+    return false;
+  const char* np = name.data() + prefix_len;
+  if (*np++ != 'U' || *np++ != 'T' || *np++ != 'C')
+    return false;
+  if (np[0] != '+' && np[0] != '-')
+    return false;
+  if (np[3] != ':' || np[6] != ':')  // see note below about large offsets
+    return false;
+
+  int hours = Parse02d(np + 1);
+  if (hours == -1) return false;
+  int mins = Parse02d(np + 4);
+  if (mins == -1) return false;
+  int secs = Parse02d(np + 7);
+  if (secs == -1) return false;
+
+  secs += ((hours * 60) + mins) * 60;
+  if (secs > 24 * 60 * 60) return false;  // outside supported offset range
+  *offset = sys_seconds(secs * (np[0] == '-' ? -1 : 1));  // "-" means west
+  return true;
+}
+
+std::string FixedOffsetToName(const sys_seconds& offset) {
+  if (offset == sys_seconds::zero()) return "UTC";
+  if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) {
+    // We don't support fixed-offset zones more than 24 hours
+    // away from UTC to avoid complications in rendering such
+    // offsets and to (somewhat) limit the total number of zones.
+    return "UTC";
+  }
+  int seconds = static_cast<int>(offset.count());
+  const char sign = (seconds < 0 ? '-' : '+');
+  int minutes = seconds / 60;
+  seconds %= 60;
+  if (sign == '-') {
+    if (seconds > 0) {
+      seconds -= 60;
+      minutes += 1;
+    }
+    seconds = -seconds;
+    minutes = -minutes;
+  }
+  int hours = minutes / 60;
+  minutes %= 60;
+  char buf[sizeof(kFixedOffsetPrefix) + sizeof("UTC-24:00:00")];
+  snprintf(buf, sizeof(buf), "%sUTC%c%02d:%02d:%02d",
+           kFixedOffsetPrefix, sign, hours, minutes, seconds);
+  return buf;
+}
+
+std::string FixedOffsetToAbbr(const sys_seconds& offset) {
+  std::string abbr = FixedOffsetToName(offset);
+  const std::size_t prefix_len = sizeof(kFixedOffsetPrefix) - 1;
+  const char* const ep = kFixedOffsetPrefix + prefix_len;
+  if (abbr.size() >= prefix_len) {
+    if (std::equal(kFixedOffsetPrefix, ep, abbr.begin())) {
+      abbr.erase(0, prefix_len);
+      if (abbr.size() == 12) {                     // UTC+99:99:99
+        abbr.erase(9, 1);                          // UTC+99:9999
+        abbr.erase(6, 1);                          // UTC+999999
+        if (abbr[8] == '0' && abbr[9] == '0') {    // UTC+999900
+          abbr.erase(8, 2);                        // UTC+9999
+          if (abbr[6] == '0' && abbr[7] == '0') {  // UTC+9900
+            abbr.erase(6, 2);                      // UTC+99
+            if (abbr[4] == '0') {                  // UTC+09
+              abbr.erase(4, 1);                    // UTC+9
+            }
+          }
+        }
+      }
+    }
+  }
+  return abbr;
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.h b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
new file mode 100644
index 0000000..7c9d11d
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
@@ -0,0 +1,49 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
+
+#include <string>
+
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+
+// Helper functions for dealing with the names and abbreviations
+// of time zones that are a fixed offset (seconds east) from UTC.
+// FixedOffsetFromName() extracts the offset from a valid fixed-offset
+// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate
+// the canonical zone name and abbreviation respectively for the given
+// offset.
+//
+// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>".
+// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the
+// optional pieces are omitted when their values are zero.  (Note that
+// the sign is the opposite of that used in a POSIX TZ specification.)
+//
+// Note: FixedOffsetFromName() fails on syntax errors or when the parsed
+// offset exceeds 24 hours.  FixedOffsetToName() and FixedOffsetToAbbr()
+// both produce "UTC" when the argument offset exceeds 24 hours.
+bool FixedOffsetFromName(const std::string& name, sys_seconds* offset);
+std::string FixedOffsetToName(const sys_seconds& offset);
+std::string FixedOffsetToAbbr(const sys_seconds& offset);
+
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_

http://git-wip-us.apache.org/repos/asf/marmotta/blob/0eb556da/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_format.cc
----------------------------------------------------------------------
diff --git a/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_format.cc b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_format.cc
new file mode 100644
index 0000000..6d5ccba
--- /dev/null
+++ b/libraries/ostrich/backend/3rdparty/abseil/absl/time/internal/cctz/src/time_zone_format.cc
@@ -0,0 +1,848 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+#if !defined(HAS_STRPTIME)
+# if !defined(_MSC_VER)
+#  define HAS_STRPTIME 1  // assume everyone has strptime() except windows
+# endif
+#endif
+
+#include "absl/time/internal/cctz/include/cctz/time_zone.h"
+
+#include <cctype>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <vector>
+#if !HAS_STRPTIME
+#include <iomanip>
+#include <sstream>
+#endif
+
+#include "absl/time/internal/cctz/include/cctz/civil_time.h"
+#include "time_zone_if.h"
+
+namespace absl {
+namespace time_internal {
+namespace cctz {
+namespace detail {
+
+namespace {
+
+#if !HAS_STRPTIME
+// Build a strptime() using C++11's std::get_time().
+char* strptime(const char* s, const char* fmt, std::tm* tm) {
+  std::istringstream input(s);
+  input >> std::get_time(tm, fmt);
+  if (input.fail()) return nullptr;
+  return const_cast<char*>(s) +
+         (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
+}
+#endif
+
+std::tm ToTM(const time_zone::absolute_lookup& al) {
+  std::tm tm{};
+  tm.tm_sec = al.cs.second();
+  tm.tm_min = al.cs.minute();
+  tm.tm_hour = al.cs.hour();
+  tm.tm_mday = al.cs.day();
+  tm.tm_mon = al.cs.month() - 1;
+
+  // Saturate tm.tm_year is cases of over/underflow.
+  if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
+    tm.tm_year = std::numeric_limits<int>::min();
+  } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
+    tm.tm_year = std::numeric_limits<int>::max();
+  } else {
+    tm.tm_year = static_cast<int>(al.cs.year() - 1900);
+  }
+
+  switch (get_weekday(civil_day(al.cs))) {
+    case weekday::sunday:
+      tm.tm_wday = 0;
+      break;
+    case weekday::monday:
+      tm.tm_wday = 1;
+      break;
+    case weekday::tuesday:
+      tm.tm_wday = 2;
+      break;
+    case weekday::wednesday:
+      tm.tm_wday = 3;
+      break;
+    case weekday::thursday:
+      tm.tm_wday = 4;
+      break;
+    case weekday::friday:
+      tm.tm_wday = 5;
+      break;
+    case weekday::saturday:
+      tm.tm_wday = 6;
+      break;
+  }
+  tm.tm_yday = get_yearday(civil_day(al.cs)) - 1;
+  tm.tm_isdst = al.is_dst ? 1 : 0;
+  return tm;
+}
+
+const char kDigits[] = "0123456789";
+
+// Formats a 64-bit integer in the given field width.  Note that it is up
+// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure
+// that there is sufficient space before ep to hold the conversion.
+char* Format64(char* ep, int width, std::int_fast64_t v) {
+  bool neg = false;
+  if (v < 0) {
+    --width;
+    neg = true;
+    if (v == std::numeric_limits<std::int_fast64_t>::min()) {
+      // Avoid negating minimum value.
+      std::int_fast64_t last_digit = -(v % 10);
+      v /= 10;
+      if (last_digit < 0) {
+        ++v;
+        last_digit += 10;
+      }
+      --width;
+      *--ep = kDigits[last_digit];
+    }
+    v = -v;
+  }
+  do {
+    --width;
+    *--ep = kDigits[v % 10];
+  } while (v /= 10);
+  while (--width >= 0) *--ep = '0';  // zero pad
+  if (neg) *--ep = '-';
+  return ep;
+}
+
+// Formats [0 .. 99] as %02d.
+char* Format02d(char* ep, int v) {
+  *--ep = kDigits[v % 10];
+  *--ep = kDigits[(v / 10) % 10];
+  return ep;
+}
+
+// Formats a UTC offset, like +00:00.
+char* FormatOffset(char* ep, int offset, const char* mode) {
+  char sign = '+';
+  if (offset < 0) {
+    offset = -offset;  // bounded by 24h so no overflow
+    sign = '-';
+  }
+  char sep = mode[0];
+  if (sep != '\0' && mode[1] == '*') {
+    ep = Format02d(ep, offset % 60);
+    *--ep = sep;
+  }
+  int minutes = offset / 60;
+  ep = Format02d(ep, minutes % 60);
+  if (sep != '\0') *--ep = sep;
+  ep = Format02d(ep, minutes / 60);
+  *--ep = sign;
+  return ep;
+}
+
+// Formats a std::tm using strftime(3).
+void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
+  // strftime(3) returns the number of characters placed in the output
+  // array (which may be 0 characters).  It also returns 0 to indicate
+  // an error, like the array wasn't large enough.  To accommodate this,
+  // the following code grows the buffer size from 2x the format std::string
+  // length up to 32x.
+  for (std::size_t i = 2; i != 32; i *= 2) {
+    std::size_t buf_size = fmt.size() * i;
+    std::vector<char> buf(buf_size);
+    if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
+      out->append(&buf[0], len);
+      return;
+    }
+  }
+}
+
+// Used for %E#S/%E#f specifiers and for data values in parse().
+template <typename T>
+const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
+  if (dp != nullptr) {
+    const T kmin = std::numeric_limits<T>::min();
+    bool erange = false;
+    bool neg = false;
+    T value = 0;
+    if (*dp == '-') {
+      neg = true;
+      if (width <= 0 || --width != 0) {
+        ++dp;
+      } else {
+        dp = nullptr;  // width was 1
+      }
+    }
+    if (const char* const bp = dp) {
+      while (const char* cp = strchr(kDigits, *dp)) {
+        int d = static_cast<int>(cp - kDigits);
+        if (d >= 10) break;
+        if (value < kmin / 10) {
+          erange = true;
+          break;
+        }
+        value *= 10;
+        if (value < kmin + d) {
+          erange = true;
+          break;
+        }
+        value -= d;
+        dp += 1;
+        if (width > 0 && --width == 0) break;
+      }
+      if (dp != bp && !erange && (neg || value != kmin)) {
+        if (!neg || value != 0) {
+          if (!neg) value = -value;  // make positive
+          if (min <= value && value <= max) {
+            *vp = value;
+          } else {
+            dp = nullptr;
+          }
+        } else {
+          dp = nullptr;
+        }
+      } else {
+        dp = nullptr;
+      }
+    }
+  }
+  return dp;
+}
+
+// The number of base-10 digits that can be represented by a signed 64-bit
+// integer.  That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1).
+const int kDigits10_64 = 18;
+
+// 10^n for everything that can be represented by a signed 64-bit integer.
+const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
+    1,
+    10,
+    100,
+    1000,
+    10000,
+    100000,
+    1000000,
+    10000000,
+    100000000,
+    1000000000,
+    10000000000,
+    100000000000,
+    1000000000000,
+    10000000000000,
+    100000000000000,
+    1000000000000000,
+    10000000000000000,
+    100000000000000000,
+    1000000000000000000,
+};
+
+}  // namespace
+
+// Uses strftime(3) to format the given Time.  The following extended format
+// specifiers are also supported:
+//
+//   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+//   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+//   - %E#S - Seconds with # digits of fractional precision
+//   - %E*S - Seconds with full fractional precision (a literal '*')
+//   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally for performance reasons.  strftime(3) is slow due to
+// a POSIX requirement to respect changes to ${TZ}.
+//
+// The TZ/GNU %s extension is handled internally because strftime() has
+// to use mktime() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z and %Z specifiers to accommodate platforms that do
+// not support the tm_gmtoff and tm_zone extensions to std::tm.
+//
+// Requires that zero() <= fs < seconds(1).
+std::string format(const std::string& format, const time_point<sys_seconds>& tp,
+                   const detail::femtoseconds& fs, const time_zone& tz) {
+  std::string result;
+  result.reserve(format.size());  // A reasonable guess for the result size.
+  const time_zone::absolute_lookup al = tz.lookup(tp);
+  const std::tm tm = ToTM(al);
+
+  // Scratch buffer for internal conversions.
+  char buf[3 + kDigits10_64];  // enough for longest conversion
+  char* const ep = buf + sizeof(buf);
+  char* bp;  // works back from ep
+
+  // Maintain three, disjoint subsequences that span format.
+  //   [format.begin() ... pending) : already formatted into result
+  //   [pending ... cur) : formatting pending, but no special cases
+  //   [cur ... format.end()) : unexamined
+  // Initially, everything is in the unexamined part.
+  const char* pending = format.c_str();  // NUL terminated
+  const char* cur = pending;
+  const char* end = pending + format.length();
+
+  while (cur != end) {  // while something is unexamined
+    // Moves cur to the next percent sign.
+    const char* start = cur;
+    while (cur != end && *cur != '%') ++cur;
+
+    // If the new pending text is all ordinary, copy it out.
+    if (cur != start && pending == start) {
+      result.append(pending, static_cast<std::size_t>(cur - pending));
+      pending = start = cur;
+    }
+
+    // Span the sequential percent signs.
+    const char* percent = cur;
+    while (cur != end && *cur == '%') ++cur;
+
+    // If the new pending text is all percents, copy out one
+    // percent for every matched pair, then skip those pairs.
+    if (cur != start && pending == start) {
+      std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
+      result.append(pending, escaped);
+      pending += escaped * 2;
+      // Also copy out a single trailing percent.
+      if (pending != cur && cur == end) {
+        result.push_back(*pending++);
+      }
+    }
+
+    // Loop unless we have an unescaped percent.
+    if (cur == end || (cur - percent) % 2 == 0) continue;
+
+    // Simple specifiers that we handle ourselves.
+    if (strchr("YmdeHMSzZs%", *cur)) {
+      if (cur - 1 != pending) {
+        FormatTM(&result, std::string(pending, cur - 1), tm);
+      }
+      switch (*cur) {
+        case 'Y':
+          // This avoids the tm.tm_year overflow problem for %Y, however
+          // tm.tm_year will still be used by other specifiers like %D.
+          bp = Format64(ep, 0, al.cs.year());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'm':
+          bp = Format02d(ep, al.cs.month());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'd':
+        case 'e':
+          bp = Format02d(ep, al.cs.day());
+          if (*cur == 'e' && *bp == '0') *bp = ' ';  // for Windows
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'H':
+          bp = Format02d(ep, al.cs.hour());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'M':
+          bp = Format02d(ep, al.cs.minute());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'S':
+          bp = Format02d(ep, al.cs.second());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'z':
+          bp = FormatOffset(ep, al.offset, "");
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case 'Z':
+          result.append(al.abbr);
+          break;
+        case 's':
+          bp = Format64(ep, 0, ToUnixSeconds(tp));
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          break;
+        case '%':
+          result.push_back('%');
+          break;
+      }
+      pending = ++cur;
+      continue;
+    }
+
+    // Loop if there is no E modifier.
+    if (*cur != 'E' || ++cur == end) continue;
+
+    // Format our extensions.
+    if (*cur == 'z') {
+      // Formats %Ez.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = FormatOffset(ep, al.offset, ":");
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = ++cur;
+    } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
+      // Formats %E*z.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = FormatOffset(ep, al.offset, ":*");
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = cur += 2;
+    } else if (*cur == '*' && cur + 1 != end &&
+               (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
+      // Formats %E*S or %E*F.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      char* cp = ep;
+      bp = Format64(cp, 15, fs.count());
+      while (cp != bp && cp[-1] == '0') --cp;
+      switch (*(cur + 1)) {
+        case 'S':
+          if (cp != bp) *--bp = '.';
+          bp = Format02d(bp, al.cs.second());
+          break;
+        case 'f':
+          if (cp == bp) *--bp = '0';
+          break;
+      }
+      result.append(bp, static_cast<std::size_t>(cp - bp));
+      pending = cur += 2;
+    } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
+      // Formats %E4Y.
+      if (cur - 2 != pending) {
+        FormatTM(&result, std::string(pending, cur - 2), tm);
+      }
+      bp = Format64(ep, 4, al.cs.year());
+      result.append(bp, static_cast<std::size_t>(ep - bp));
+      pending = cur += 2;
+    } else if (std::isdigit(*cur)) {
+      // Possibly found %E#S or %E#f.
+      int n = 0;
+      if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
+        if (*np == 'S' || *np == 'f') {
+          // Formats %E#S or %E#f.
+          if (cur - 2 != pending) {
+            FormatTM(&result, std::string(pending, cur - 2), tm);
+          }
+          bp = ep;
+          if (n > 0) {
+            if (n > kDigits10_64) n = kDigits10_64;
+            bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
+                                          : fs.count() / kExp10[15 - n]);
+            if (*np == 'S') *--bp = '.';
+          }
+          if (*np == 'S') bp = Format02d(bp, al.cs.second());
+          result.append(bp, static_cast<std::size_t>(ep - bp));
+          pending = cur = ++np;
+        }
+      }
+    }
+  }
+
+  // Formats any remaining data.
+  if (end != pending) {
+    FormatTM(&result, std::string(pending, end), tm);
+  }
+
+  return result;
+}
+
+namespace {
+
+const char* ParseOffset(const char* dp, const char* mode, int* offset) {
+  if (dp != nullptr) {
+    const char first = *dp++;
+    if (first == '+' || first == '-') {
+      char sep = mode[0];
+      int hours = 0;
+      int minutes = 0;
+      int seconds = 0;
+      const char* ap = ParseInt(dp, 2, 0, 23, &hours);
+      if (ap != nullptr && ap - dp == 2) {
+        dp = ap;
+        if (sep != '\0' && *ap == sep) ++ap;
+        const char* bp = ParseInt(ap, 2, 0, 59, &minutes);
+        if (bp != nullptr && bp - ap == 2) {
+          dp = bp;
+          if (sep != '\0' && *bp == sep) ++bp;
+          const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
+          if (cp != nullptr && cp - bp == 2) dp = cp;
+        }
+        *offset = ((hours * 60 + minutes) * 60) + seconds;
+        if (first == '-') *offset = -*offset;
+      } else {
+        dp = nullptr;
+      }
+    } else if (first == 'Z') {  // Zulu
+      *offset = 0;
+    } else {
+      dp = nullptr;
+    }
+  }
+  return dp;
+}
+
+const char* ParseZone(const char* dp, std::string* zone) {
+  zone->clear();
+  if (dp != nullptr) {
+    while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
+    if (zone->empty()) dp = nullptr;
+  }
+  return dp;
+}
+
+const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
+  if (dp != nullptr) {
+    std::int_fast64_t v = 0;
+    std::int_fast64_t exp = 0;
+    const char* const bp = dp;
+    while (const char* cp = strchr(kDigits, *dp)) {
+      int d = static_cast<int>(cp - kDigits);
+      if (d >= 10) break;
+      if (exp < 15) {
+        exp += 1;
+        v *= 10;
+        v += d;
+      }
+      ++dp;
+    }
+    if (dp != bp) {
+      v *= kExp10[15 - exp];
+      *subseconds = detail::femtoseconds(v);
+    } else {
+      dp = nullptr;
+    }
+  }
+  return dp;
+}
+
+// Parses a std::string into a std::tm using strptime(3).
+const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
+  if (dp != nullptr) {
+    dp = strptime(dp, fmt, tm);
+  }
+  return dp;
+}
+
+}  // namespace
+
+// Uses strptime(3) to parse the given input.  Supports the same extended
+// format specifiers as format(), although %E#S and %E*S are treated
+// identically (and similarly for %E#f and %E*f).  %Ez and %E*z also accept
+// the same inputs.
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally so that we can normally avoid strptime() altogether
+// (which is particularly helpful when the native implementation is broken).
+//
+// The TZ/GNU %s extension is handled internally because strptime() has to
+// use localtime_r() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z specifier to accommodate platforms that do not
+// support the tm_gmtoff extension to std::tm.  %Z is parsed but ignored.
+bool parse(const std::string& format, const std::string& input,
+           const time_zone& tz, time_point<sys_seconds>* sec,
+           detail::femtoseconds* fs, std::string* err) {
+  // The unparsed input.
+  const char* data = input.c_str();  // NUL terminated
+
+  // Skips leading whitespace.
+  while (std::isspace(*data)) ++data;
+
+  const year_t kyearmax = std::numeric_limits<year_t>::max();
+  const year_t kyearmin = std::numeric_limits<year_t>::min();
+
+  // Sets default values for unspecified fields.
+  bool saw_year = false;
+  year_t year = 1970;
+  std::tm tm{};
+  tm.tm_year = 1970 - 1900;
+  tm.tm_mon = 1 - 1;  // Jan
+  tm.tm_mday = 1;
+  tm.tm_hour = 0;
+  tm.tm_min = 0;
+  tm.tm_sec = 0;
+  tm.tm_wday = 4;  // Thu
+  tm.tm_yday = 0;
+  tm.tm_isdst = 0;
+  auto subseconds = detail::femtoseconds::zero();
+  bool saw_offset = false;
+  int offset = 0;  // No offset from passed tz.
+  std::string zone = "UTC";
+
+  const char* fmt = format.c_str();  // NUL terminated
+  bool twelve_hour = false;
+  bool afternoon = false;
+
+  bool saw_percent_s = false;
+  std::int_fast64_t percent_s = 0;
+
+  // Steps through format, one specifier at a time.
+  while (data != nullptr && *fmt != '\0') {
+    if (std::isspace(*fmt)) {
+      while (std::isspace(*data)) ++data;
+      while (std::isspace(*++fmt)) continue;
+      continue;
+    }
+
+    if (*fmt != '%') {
+      if (*data == *fmt) {
+        ++data;
+        ++fmt;
+      } else {
+        data = nullptr;
+      }
+      continue;
+    }
+
+    const char* percent = fmt;
+    if (*++fmt == '\0') {
+      data = nullptr;
+      continue;
+    }
+    switch (*fmt++) {
+      case 'Y':
+        // Symmetrically with FormatTime(), directly handing %Y avoids the
+        // tm.tm_year overflow problem.  However, tm.tm_year will still be
+        // used by other specifiers like %D.
+        data = ParseInt(data, 0, kyearmin, kyearmax, &year);
+        if (data != nullptr) saw_year = true;
+        continue;
+      case 'm':
+        data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
+        if (data != nullptr) tm.tm_mon -= 1;
+        continue;
+      case 'd':
+      case 'e':
+        data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+        continue;
+      case 'H':
+        data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
+        twelve_hour = false;
+        continue;
+      case 'M':
+        data = ParseInt(data, 2, 0, 59, &tm.tm_min);
+        continue;
+      case 'S':
+        data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+        continue;
+      case 'I':
+      case 'l':
+      case 'r':  // probably uses %I
+        twelve_hour = true;
+        break;
+      case 'R':  // uses %H
+      case 'T':  // uses %H
+      case 'c':  // probably uses %H
+      case 'X':  // probably uses %H
+        twelve_hour = false;
+        break;
+      case 'z':
+        data = ParseOffset(data, "", &offset);
+        if (data != nullptr) saw_offset = true;
+        continue;
+      case 'Z':  // ignored; zone abbreviations are ambiguous
+        data = ParseZone(data, &zone);
+        continue;
+      case 's':
+        data = ParseInt(data, 0,
+                        std::numeric_limits<std::int_fast64_t>::min(),
+                        std::numeric_limits<std::int_fast64_t>::max(),
+                        &percent_s);
+        if (data != nullptr) saw_percent_s = true;
+        continue;
+      case '%':
+        data = (*data == '%' ? data + 1 : nullptr);
+        continue;
+      case 'E':
+        if (*fmt == 'z' || (*fmt == '*' && *(fmt + 1) == 'z')) {
+          data = ParseOffset(data, ":", &offset);
+          if (data != nullptr) saw_offset = true;
+          fmt += (*fmt == 'z') ? 1 : 2;
+          continue;
+        }
+        if (*fmt == '*' && *(fmt + 1) == 'S') {
+          data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+          if (data != nullptr && *data == '.') {
+            data = ParseSubSeconds(data + 1, &subseconds);
+          }
+          fmt += 2;
+          continue;
+        }
+        if (*fmt == '*' && *(fmt + 1) == 'f') {
+          if (data != nullptr && std::isdigit(*data)) {
+            data = ParseSubSeconds(data, &subseconds);
+          }
+          fmt += 2;
+          continue;
+        }
+        if (*fmt == '4' && *(fmt + 1) == 'Y') {
+          const char* bp = data;
+          data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
+          if (data != nullptr) {
+            if (data - bp == 4) {
+              saw_year = true;
+            } else {
+              data = nullptr;  // stopped too soon
+            }
+          }
+          fmt += 2;
+          continue;
+        }
+        if (std::isdigit(*fmt)) {
+          int n = 0;  // value ignored
+          if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
+            if (*np == 'S') {
+              data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+              if (data != nullptr && *data == '.') {
+                data = ParseSubSeconds(data + 1, &subseconds);
+              }
+              fmt = ++np;
+              continue;
+            }
+            if (*np == 'f') {
+              if (data != nullptr && std::isdigit(*data)) {
+                data = ParseSubSeconds(data, &subseconds);
+              }
+              fmt = ++np;
+              continue;
+            }
+          }
+        }
+        if (*fmt == 'c') twelve_hour = false;  // probably uses %H
+        if (*fmt == 'X') twelve_hour = false;  // probably uses %H
+        if (*fmt != '\0') ++fmt;
+        break;
+      case 'O':
+        if (*fmt == 'H') twelve_hour = false;
+        if (*fmt == 'I') twelve_hour = true;
+        if (*fmt != '\0') ++fmt;
+        break;
+    }
+
+    // Parses the current specifier.
+    const char* orig_data = data;
+    std::string spec(percent, static_cast<std::size_t>(fmt - percent));
+    data = ParseTM(data, spec.c_str(), &tm);
+
+    // If we successfully parsed %p we need to remember whether the result
+    // was AM or PM so that we can adjust tm_hour before ConvertDateTime().
+    // So reparse the input with a known AM hour, and check if it is shifted
+    // to a PM hour.
+    if (spec == "%p" && data != nullptr) {
+      std::string test_input = "1";
+      test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
+      const char* test_data = test_input.c_str();
+      std::tm tmp{};
+      ParseTM(test_data, "%I%p", &tmp);
+      afternoon = (tmp.tm_hour == 13);
+    }
+  }
+
+  // Adjust a 12-hour tm_hour value if it should be in the afternoon.
+  if (twelve_hour && afternoon && tm.tm_hour < 12) {
+    tm.tm_hour += 12;
+  }
+
+  if (data == nullptr) {
+    if (err != nullptr) *err = "Failed to parse input";
+    return false;
+  }
+
+  // Skip any remaining whitespace.
+  while (std::isspace(*data)) ++data;
+
+  // parse() must consume the entire input std::string.
+  if (*data != '\0') {
+    if (err != nullptr) *err = "Illegal trailing data in input string";
+    return false;
+  }
+
+  // If we saw %s then we ignore anything else and return that time.
+  if (saw_percent_s) {
+    *sec = FromUnixSeconds(percent_s);
+    *fs = detail::femtoseconds::zero();
+    return true;
+  }
+
+  // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields
+  // in UTC and then shift by that offset.  Otherwise we want to interpret
+  // the fields directly in the passed time_zone.
+  time_zone ptz = saw_offset ? utc_time_zone() : tz;
+
+  // Allows a leap second of 60 to normalize forward to the following ":00".
+  if (tm.tm_sec == 60) {
+    tm.tm_sec -= 1;
+    offset -= 1;
+    subseconds = detail::femtoseconds::zero();
+  }
+
+  if (!saw_year) {
+    year = year_t{tm.tm_year};
+    if (year > kyearmax - 1900) {
+      // Platform-dependent, maybe unreachable.
+      if (err != nullptr) *err = "Out-of-range year";
+      return false;
+    }
+    year += 1900;
+  }
+
+  const int month = tm.tm_mon + 1;
+  civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+  // parse() should not allow normalization. Due to the restricted field
+  // ranges above (see ParseInt()), the only possibility is for days to roll
+  // into months. That is, parsing "Sep 31" should not produce "Oct 1".
+  if (cs.month() != month || cs.day() != tm.tm_mday) {
+    if (err != nullptr) *err = "Out-of-range field";
+    return false;
+  }
+
+  // Accounts for the offset adjustment before converting to absolute time.
+  if ((offset < 0 && cs > civil_second::max() + offset) ||
+      (offset > 0 && cs < civil_second::min() + offset)) {
+    if (err != nullptr) *err = "Out-of-range field";
+    return false;
+  }
+  cs -= offset;
+
+  const auto tp = ptz.lookup(cs).pre;
+  // Checks for overflow/underflow and returns an error as necessary.
+  if (tp == time_point<sys_seconds>::max()) {
+    const auto al = ptz.lookup(time_point<sys_seconds>::max());
+    if (cs > al.cs) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+  if (tp == time_point<sys_seconds>::min()) {
+    const auto al = ptz.lookup(time_point<sys_seconds>::min());
+    if (cs < al.cs) {
+      if (err != nullptr) *err = "Out-of-range field";
+      return false;
+    }
+  }
+
+  *sec = tp;
+  *fs = subseconds;
+  return true;
+}
+
+}  // namespace detail
+}  // namespace cctz
+}  // namespace time_internal
+}  // namespace absl