PR #2109: carry field normalization into parsed year in ParseYearAnd

Imported from GitHub PR https://github.com/abseil/abseil-cpp/pull/2109

**Dropped year carry in ParseCivilTime**

`ParseYearAnd` parses the year on its own and normalizes it into the ~2400 range before handing the rest of the string to `ParseTime`, then rebuilds the result from the original year plus the normalized month..second fields taken from `cs`. When one of those fields carries across the year boundary (a `:60` leap second at `23:59:60` on Dec 31, or an end-of-year rollover), that carry lives in `cs.year()` and was dropped, so `ParseCivilTime("2020-12-31T23:59:60")` produced `2020-01-01T00:00:00` while constructing `CivilSecond(2020, 12, 31, 23, 59, 60)` directly gives `2021-01-01T00:00:00`. This reapplies the same carry to the original year, which is a no-op whenever no rollover happened.
Merge af31d66e1109de628f4e1ffb4f760b27ec7f39ca into 63c77e4060d6b4aefb9d85f9205c2d109d5fd9b8

Merging this change closes #2109

COPYBARA_INTEGRATE_REVIEW=https://github.com/abseil/abseil-cpp/pull/2109 from nabhan06:civil-time-year-carry af31d66e1109de628f4e1ffb4f760b27ec7f39ca
PiperOrigin-RevId: 949723541
Change-Id: I015bcd78575306136677e3dfc1f478066e2dca71
diff --git a/absl/time/civil_time.cc b/absl/time/civil_time.cc
index 1773366..eae7e7f 100644
--- a/absl/time/civil_time.cc
+++ b/absl/time/civil_time.cc
@@ -55,13 +55,20 @@
   const civil_year_t y =
       std::strtoll(np, &endp, 10);  // NOLINT(runtime/deprecated_fn)
   if (endp == np || errno == ERANGE) return false;
-  const std::string norm = StrCat(NormalizeYear(y), endp);
+  const civil_year_t normalized_year = NormalizeYear(y);
+  const std::string norm = StrCat(normalized_year, endp);
 
   const TimeZone utc = UTCTimeZone();
   Time t;
   if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) {
     const auto cs = ToCivilSecond(t, utc);
-    *c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
+    // Field normalization while parsing (e.g. a ":60" leap second or an
+    // end-of-year rollover) can carry into the year. The other fields are taken
+    // from `cs`, so the same carry must be applied to the original year;
+    // otherwise the reconstructed value would use the wrong (un-carried) year.
+    const civil_year_t year = y + (cs.year() - normalized_year);
+    *c =
+        CivilT(year, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
     return true;
   }
 
diff --git a/absl/time/civil_time_test.cc b/absl/time/civil_time_test.cc
index b1e1f39..3ad8e14 100644
--- a/absl/time/civil_time_test.cc
+++ b/absl/time/civil_time_test.cc
@@ -852,6 +852,23 @@
   EXPECT_EQ(absl::CivilMonth(-1, 1), m);
 }
 
+TEST(CivilTime, ParseFieldNormalizationCarriesYear) {
+  // When a field normalizes past the end of the year (e.g. a ":60" leap
+  // second on the last second of December), the carry must be reflected in
+  // the parsed year, so parsing agrees with direct field construction.
+  absl::CivilSecond ss;
+  EXPECT_TRUE(absl::ParseCivilTime("2020-12-31T23:59:60", &ss)) << ss;
+  EXPECT_EQ(absl::CivilSecond(2020, 12, 31, 23, 59, 60), ss);
+  EXPECT_EQ(absl::CivilSecond(2021, 1, 1, 0, 0, 0), ss);
+
+  EXPECT_TRUE(absl::ParseLenientCivilTime("2020-12-31T23:59:60", &ss)) << ss;
+  EXPECT_EQ(absl::CivilSecond(2021, 1, 1, 0, 0, 0), ss);
+
+  // The carry also works for negative years crossing zero.
+  EXPECT_TRUE(absl::ParseCivilTime("-1-12-31T23:59:60", &ss)) << ss;
+  EXPECT_EQ(absl::CivilSecond(0, 1, 1, 0, 0, 0), ss);
+}
+
 TEST(CivilTime, AbslStringify) {
   EXPECT_EQ("2015-01-02T03:04:05",
             absl::StrFormat("%v", absl::CivilSecond(2015, 1, 2, 3, 4, 5)));