Rollback import of CCTZ from GitHub.

PiperOrigin-RevId: 958551023
Change-Id: I19160c0858b4f4ade49e6287908cc2a69183bd88
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index edec282..3b47877 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -140,10 +140,7 @@
     name = "time_zone_lookup_test",
     size = "small",
     timeout = "moderate",
-    srcs = [
-        "src/time_zone_lookup_test.cc",
-        "src/tzfile.h",
-    ],
+    srcs = ["src/time_zone_lookup_test.cc"],
     copts = ABSL_TEST_COPTS,
     data = [":zoneinfo"],
     linkopts = ABSL_DEFAULT_LINKOPTS,
@@ -180,24 +177,6 @@
     ],
 )
 
-cc_test(
-    name = "time_zone_posix_test",
-    size = "small",
-    srcs = [
-        "src/time_zone_posix.h",
-        "src/time_zone_posix_test.cc",
-    ],
-    copts = ABSL_TEST_COPTS,
-    linkopts = ABSL_DEFAULT_LINKOPTS,
-    deps = [
-        ":civil_time",
-        ":time_zone",
-        "//absl/base:config",
-        "@googletest//:gtest",
-        "@googletest//:gtest_main",
-    ],
-)
-
 ### benchmarks
 
 cc_test(
diff --git a/absl/time/internal/cctz/src/cctz_benchmark.cc b/absl/time/internal/cctz/src/cctz_benchmark.cc
index 17ff576..ce27818 100644
--- a/absl/time/internal/cctz/src/cctz_benchmark.cc
+++ b/absl/time/internal/cctz/src/cctz_benchmark.cc
@@ -28,7 +28,6 @@
 
 namespace {
 
-// SKIP_ABSL_INLINE_NAMESPACE_CHECK
 namespace cctz = absl::time_internal::cctz;
 
 void BM_Difference_Days(benchmark::State& state) {
diff --git a/absl/time/internal/cctz/src/time_zone_fixed.cc b/absl/time/internal/cctz/src/time_zone_fixed.cc
index b33410d..ed7f9cb 100644
--- a/absl/time/internal/cctz/src/time_zone_fixed.cc
+++ b/absl/time/internal/cctz/src/time_zone_fixed.cc
@@ -40,19 +40,12 @@
   return p;
 }
 
-// Returns the value of the decimal digit ch, or -1 if ch is not a digit.
-// Note that std::strchr() also matches kDigits' terminating '\0', which
-// would otherwise be taken for a tenth digit.
-int ParseDigit(char ch) {
-  const char* const dp = std::strchr(kDigits, ch);
-  return (dp == nullptr || *dp == '\0') ? -1 : static_cast<int>(dp - kDigits);
-}
-
 int Parse02d(const char* p) {
-  const int hi = ParseDigit(p[0]);
-  if (hi >= 0) {
-    const int lo = ParseDigit(p[1]);
-    if (lo >= 0) return (hi * 10) + lo;
+  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;
 }
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index f97de2f..91b4621 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -58,16 +58,6 @@
 
 namespace {
 
-// The ctype functions have undefined behavior for negative char values,
-// so these helpers ensure the argument is always in the unsigned-char domain.
-bool isdigit(char ch) {
-  return std::isdigit(static_cast<unsigned char>(ch)) != 0;
-}
-
-bool isspace(char ch) {
-  return std::isspace(static_cast<unsigned char>(ch)) != 0;
-}
-
 #if !HAS_STRPTIME
 // Build a strptime() using C++11's std::get_time().
 char* strptime(const char* s, const char* fmt, std::tm* tm) {
@@ -563,7 +553,7 @@
       bp = Format64(ep, 4, al.cs.year());
       result.append(bp, ep);
       pending = cur += 2;
-    } else if (isdigit(*cur)) {
+    } 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)) {
@@ -630,7 +620,7 @@
 const char* ParseZone(const char* dp, std::string* zone) {
   zone->clear();
   if (dp != nullptr) {
-    while (*dp != '\0' && !isspace(*dp)) zone->push_back(*dp++);
+    while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
     if (zone->empty()) dp = nullptr;
   }
   return dp;
@@ -716,7 +706,7 @@
   const char* const edata = data + input.size();
 
   // Skips leading whitespace.
-  while (isspace(*data)) ++data;
+  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();
@@ -754,9 +744,9 @@
 
   // Steps through format, one specifier at a time.
   while (data != nullptr && fmt != efmt) {
-    if (isspace(*fmt)) {
-      while (isspace(*data)) ++data;
-      while (isspace(*++fmt)) continue;
+    if (std::isspace(*fmt)) {
+      while (std::isspace(*data)) ++data;
+      while (std::isspace(*++fmt)) continue;
       continue;
     }
 
@@ -908,7 +898,7 @@
           continue;
         }
         if (fmt[0] == '*' && fmt[1] == 'f') {
-          if (data != nullptr && isdigit(*data)) {
+          if (data != nullptr && std::isdigit(*data)) {
             data = ParseSubSeconds(data, &subseconds);
           }
           fmt += 2;
@@ -927,7 +917,7 @@
           fmt += 2;
           continue;
         }
-        if (isdigit(*fmt)) {
+        if (std::isdigit(*fmt)) {
           int n = 0;  // value ignored
           if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
             if (*np == 'S') {
@@ -939,7 +929,7 @@
               continue;
             }
             if (*np == 'f') {
-              if (data != nullptr && isdigit(*data)) {
+              if (data != nullptr && std::isdigit(*data)) {
                 data = ParseSubSeconds(data, &subseconds);
               }
               fmt = ++np;
@@ -987,7 +977,7 @@
   }
 
   // Skip any remaining whitespace.
-  while (isspace(*data)) ++data;
+  while (std::isspace(*data)) ++data;
 
   // parse() must consume the entire input string.
   if (data != edata) {
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 8793a80..f047d93 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -1002,27 +1002,6 @@
   EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
 }
 
-TEST(Parse, NonAsciiInput) {
-  const time_zone tz = utc_time_zone();
-  auto tp = chrono::system_clock::from_time_t(0);
-
-  // High-bit-set bytes reach the ctype functions during parsing. 0xA0 is not
-  // ASCII whitespace, so the leading-whitespace skip must not consume it and
-  // the parse must fail rather than pass a negative char to std::isspace().
-  EXPECT_FALSE(parse("%Y-%m-%d",
-                     "\xA0"
-                     "2016-01-02",
-                     tz, &tp));
-  EXPECT_FALSE(parse("%Y",
-                     "\xA0"
-                     "2016",
-                     tz, &tp));
-
-  // A leading ASCII space is still skipped as before.
-  EXPECT_TRUE(parse("%Y-%m-%d", " 2016-01-02", tz, &tp));
-  EXPECT_EQ(2016, convert(tp, utc_time_zone()).year());
-}
-
 TEST(Parse, PosixConversions) {
   time_zone tz = utc_time_zone();
   auto tp = chrono::system_clock::from_time_t(0);
diff --git a/absl/time/internal/cctz/src/time_zone_impl.cc b/absl/time/internal/cctz/src/time_zone_impl.cc
index 5cf38e7..5f2f49e 100644
--- a/absl/time/internal/cctz/src/time_zone_impl.cc
+++ b/absl/time/internal/cctz/src/time_zone_impl.cc
@@ -76,18 +76,9 @@
   // Add the new time zone to the map.
   std::lock_guard<std::mutex> lock(TimeZoneMutex());
   if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
-  if (!new_impl->zone_) {
-    // Load failed, but a successful insertion may have happened concurrently.
-    // Check it now that we have the lock. Otherwise, avoid caching negative
-    // entries to avoid unbounded growth and DoS attacks.
-    auto itr = time_zone_map->find(name);
-    const Impl* impl = (itr != time_zone_map->end()) ? itr->second : utc_impl;
-    *tz = time_zone(impl);
-    return impl != utc_impl;
-  }
   const Impl*& impl = (*time_zone_map)[name];
   if (impl == nullptr) {  // this thread won any load race
-    impl = new_impl.release();
+    impl = new_impl->zone_ ? new_impl.release() : utc_impl;
   }
   *tz = time_zone(impl);
   return impl != utc_impl;
diff --git a/absl/time/internal/cctz/src/time_zone_info.cc b/absl/time/internal/cctz/src/time_zone_info.cc
index 1e707c8..f8484c9 100644
--- a/absl/time/internal/cctz/src/time_zone_info.cc
+++ b/absl/time/internal/cctz/src/time_zone_info.cc
@@ -32,14 +32,6 @@
 
 #include "absl/time/internal/cctz/src/time_zone_info.h"
 
-#include "absl/base/config.h"
-
-#if !defined(_MSC_VER)
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
 #include <algorithm>
 #include <cassert>
 #include <chrono>
@@ -49,17 +41,16 @@
 #include <cstring>
 #include <fstream>
 #include <functional>
-#include <limits>
 #include <memory>
 #include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
 
+#include "absl/base/config.h"
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
 #include "absl/time/internal/cctz/src/time_zone_fixed.h"
 #include "absl/time/internal/cctz/src/time_zone_posix.h"
-#include "absl/time/internal/cctz/src/tzfile.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -347,14 +338,6 @@
     return EquivTransitions(transitions_.back().type_index, dst_ti);
   }
 
-  // We require that zoneinfo data with a rule for future transitions
-  // ends with a non-negative transition.  This removes the need to add
-  // any "second-half" transition to ensure differences between adjacent
-  // transitions are always representable, while also guaranteeing that
-  // the arithmetic used to shift between 400-year cycles never overflows.
-  // All valid zones easily meet this requirement.
-  if (transitions_.back().unix_time < 0) return false;
-
   // Extend the transitions for an additional 401 years using the future
   // specification. Years beyond those can be handled by mapping back to
   // a cycle-equivalent year within that range. Note that we need 401
@@ -399,45 +382,18 @@
 
 using FilePtr = std::unique_ptr<FILE, int (*)(FILE*)>;
 
-// fopen(3) adaptor for reading zoneinfo files (read-only binary mode).
-inline FilePtr FOpen(const char* path) {
+// fopen(3) adaptor.
+inline FilePtr FOpen(const char* path, const char* mode) {
 #if defined(_MSC_VER)
   FILE* fp;
-  if (fopen_s(&fp, path, "rb") != 0) fp = nullptr;
+  if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
   return FilePtr(fp, fclose);
 #else
-  // Open non-blocking and verify the target is a regular file before handing it
-  // to stdio. Zone names are potentially attacker-controlled, and a plain
-  // fopen() on a FIFO or device node (reachable via the "file:" prefix or an
-  // absolute path) would block indefinitely or read unbounded data.
-  const int fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
-  if (fd >= 0) {
-    struct stat st;
-    if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
-      FILE* fp = fdopen(fd, "rb");
-      if (fp != nullptr) return FilePtr(fp, fclose);
-    }
-    close(fd);
-  }
-  return FilePtr(nullptr, fclose);
+  // TODO: Enable the close-on-exec flag.
+  return FilePtr(fopen(path, mode), fclose);
 #endif
 }
 
-// Returns true if the zone name starting at pos contains an unsafe path.
-inline bool UnsafePath(const std::string& name, std::size_t pos) {
-  // Path traversal: exact match ".."
-  if (name.compare(pos, std::string::npos, "..") == 0) return true;
-  // Path traversal: leading component "../"
-  if (name.compare(pos, 3, "../") == 0) return true;
-  // Path traversal: interior component "/../"
-  if (name.find("/../", pos) != std::string::npos) return true;
-  // Path traversal: trailing component "/.."
-  if (name.size() - pos >= 3 && name.compare(name.size() - 3, 3, "/..") == 0) {
-    return true;
-  }
-  return false;
-}
-
 // A stdio(3)-backed implementation of ZoneInfoSource.
 class FileZoneInfoSource : public ZoneInfoSource {
  public:
@@ -475,11 +431,6 @@
   // Use of the "file:" prefix is intended for testing purposes only.
   const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
 
-  // Reject unsafe paths (e.g., "../../etc/passwd").
-  if (UnsafePath(name, pos)) {
-    return nullptr;
-  }
-
   // Map the time-zone name to a path name.
   std::string path;
   if (pos == name.size() || name[pos] != '/') {
@@ -500,7 +451,7 @@
   path.append(name, pos, std::string::npos);
 
   // Open the zoneinfo file.
-  auto fp = FOpen(path.c_str());
+  auto fp = FOpen(path.c_str(), "rb");
   if (fp == nullptr) return nullptr;
   return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(std::move(fp)));
 }
@@ -526,7 +477,7 @@
   for (const char* tzdata : {"/apex/com.android.tzdata/etc/tz/tzdata",
                              "/data/misc/zoneinfo/current/tzdata",
                              "/system/usr/share/zoneinfo/tzdata"}) {
-    auto fp = FOpen(tzdata);
+    auto fp = FOpen(tzdata, "rb");
     if (fp == nullptr) continue;
 
     char hbuf[24];  // covers header.zonetab_offset too
@@ -546,12 +497,9 @@
     if (zonecnt * sizeof(ebuf) != index_size) continue;
     for (std::size_t i = 0; i != zonecnt; ++i) {
       if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
-      const std::int_fast64_t start =
-          std::int_fast64_t{data_offset} + Decode32(ebuf + 40);
+      const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
       const std::int_fast32_t length = Decode32(ebuf + 44);
       if (start < 0 || length < 0) break;
-      // fseek() takes a long
-      if (start > std::numeric_limits<long>::max()) break;
       ebuf[40] = '\0';  // ensure zone name is NUL terminated
       if (strcmp(name.c_str() + pos, ebuf) == 0) {
         if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
@@ -589,11 +537,6 @@
   // Use of the "file:" prefix is intended for testing purposes only.
   const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
 
-  // Reject unsafe paths (e.g., "../../etc/passwd").
-  if (UnsafePath(name, pos)) {
-    return nullptr;
-  }
-
   // Prefixes where a Fuchsia component might find zoneinfo files,
   // in descending order of preference.
   const auto kTzdataPrefixes = {
@@ -618,7 +561,7 @@
     if (!prefix.empty()) path += "zoneinfo/tzif2/";  // format
     path.append(name, pos, std::string::npos);
 
-    auto fp = FOpen(path.c_str());
+    auto fp = FOpen(path.c_str(), "rb");
     if (fp == nullptr) continue;
 
     std::string version;
@@ -719,12 +662,6 @@
   if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false;
   if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false;
 
-  // Bound the header counts before sizing tbuf so that a hostile TZif blob
-  // cannot force a very large zero-filled allocation from a tiny input.
-  if (hdr.timecnt > TZ_MAX_TIMES) return false;
-  if (hdr.typecnt > TZ_MAX_TYPES) return false;
-  if (hdr.charcnt > TZ_MAX_CHARS) return false;
-
   // Read the data into a local buffer.
   std::size_t len = hdr.DataLength(time_len);
   std::vector<char> tbuf(len);
@@ -737,14 +674,6 @@
   for (std::size_t i = 0; i != hdr.timecnt; ++i) {
     transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
     bp += time_len;
-    // A valid zoneinfo file keeps transition times far from the int64 limits.
-    // A hostile one can place them at the extremes, where the
-    // reverse-conversion arithmetic in MakeTime() (tr.unix_time +/- a sub-day
-    // civil delta, see MakeSkipped()/MakeRepeated()) overflows. Bound them to
-    // +/-(1<<59), the times used by the no-op transitions added below.
-    if (transitions_[i].unix_time < -(1LL << 59) ||
-        transitions_[i].unix_time > (1LL << 59))
-      return false;  // out of range
     if (i != 0) {
       // Check that the transitions are ordered by time (as zic guarantees).
       if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
@@ -776,22 +705,16 @@
   // Determine the before-first-transition type.
   default_transition_type_ = 0;
   if (seen_type_0 && hdr.timecnt != 0) {
-    std::size_t index = 0;
+    std::uint_fast8_t index = 0;
     if (transition_types_[0].is_dst) {
       index = transitions_[0].type_index;
       while (index != 0 && transition_types_[index].is_dst) --index;
     }
     while (index != hdr.typecnt && transition_types_[index].is_dst) ++index;
-    if (index != hdr.typecnt)
-      default_transition_type_ = static_cast<std::uint_fast8_t>(index);
+    if (index != hdr.typecnt) default_transition_type_ = index;
   }
 
-  // Copy all the abbreviations. The area holds NUL-terminated strings, and
-  // LocalTime() hands out a pointer into it, so the final abbreviation has
-  // to be terminated within the area itself. Otherwise an abbreviation runs
-  // on into whatever ExtendTransitions() later appends. (hdr.charcnt != 0
-  // because every abbr_index was validated to be less than it.)
-  if (bp[hdr.charcnt - 1] != '\0') return false;
+  // Copy all the abbreviations.
   abbreviations_.reserve(hdr.charcnt + 10);
   abbreviations_.assign(bp, hdr.charcnt);
   bp += hdr.charcnt;
@@ -848,7 +771,6 @@
   // previous transition is always representable, without overflow.
   const Transition& last(transitions_.back());
   if (last.unix_time < 0) {
-    assert(!extended_);
     const std::uint_fast8_t type_index = last.type_index;
     Transition& tr(*transitions_.emplace(transitions_.end()));
     tr.unix_time = 2147483647;  // 2038-01-19T03:14:07+00:00
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 1147e93..cd08a35 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -15,27 +15,21 @@
 #include <chrono>
 #include <cstddef>
 #include <cstdlib>
-#include <cstring>
 #include <future>
 #include <limits>
-#include <memory>
 #include <string>
 #include <thread>
-#include <utility>
 #include <vector>
 
 #include "absl/base/config.h"
 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
-
 #if defined(__linux__)
 #include <features.h>
 #endif
 
 #include "gtest/gtest.h"
 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
-#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
 #include "absl/time/internal/cctz/src/test_time_zone_names.h"
-#include "absl/time/internal/cctz/src/tzfile.h"
 
 namespace chrono = std::chrono;
 
@@ -186,24 +180,6 @@
   EXPECT_FALSE(load_time_zone("", &tz));
   EXPECT_EQ(chrono::system_clock::from_time_t(0),
             convert(civil_second(1970, 1, 1, 0, 0, 0), tz));  // UTC
-
-  // Reject path-traversal components.
-  EXPECT_FALSE(load_time_zone("file:../etc/passwd", &tz));
-  EXPECT_FALSE(load_time_zone("file:../../etc/passwd", &tz));
-  EXPECT_FALSE(load_time_zone("file:/../etc/passwd", &tz));
-  EXPECT_FALSE(load_time_zone("file:America/../America/Los_Angeles", &tz));
-
-  // Reject a fixed-offset name with a NUL where a digit belongs.
-  for (const int i : {10, 11, 13, 14, 16, 17}) {
-    std::string name = "Fixed/UTC+00:00:00";
-    name[static_cast<std::size_t>(i)] = '\0';
-    EXPECT_FALSE(load_time_zone(name, &tz)) << "NUL at offset " << i;
-  }
-
-  // Reject non-regular files and directories.
-  EXPECT_FALSE(load_time_zone("file:/dev/null", &tz));
-  EXPECT_FALSE(load_time_zone("file:/dev/stdin", &tz));
-  EXPECT_FALSE(load_time_zone("file:/tmp", &tz));
 }
 
 TEST(TimeZone, Equality) {
@@ -936,181 +912,6 @@
   ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
 }
 
-// A ZoneInfoSource implementation backed by an in-memory string buffer.
-class StringZoneInfoSource : public ZoneInfoSource {
- public:
-  explicit StringZoneInfoSource(std::string data)
-      : data_(std::move(data)), offset_(0) {}
-
-  std::size_t Read(void* ptr, std::size_t size) override {
-    std::size_t n = (std::min)(size, data_.size() - offset_);
-    std::memcpy(ptr, data_.data() + offset_, n);
-    offset_ += n;
-    return n;
-  }
-
-  int Skip(std::size_t offset) override {
-    if (offset > data_.size() - offset_) return -1;
-    offset_ += offset;
-    return 0;
-  }
-
- private:
-  std::string data_;
-  std::size_t offset_;
-};
-
-// Constructs a minimal TZif2 string with a single 64-bit transition
-// at the given transition time and a future POSIX rule. The abbreviation
-// area holds abbr verbatim, so a valid file's abbr must include the
-// trailing '\0' (e.g., std::string{"EST", 4}).
-std::string MakeExtendedTzif(std::int_fast64_t unix_time,
-                             std::int_fast32_t utc_offset,
-                             const std::string& abbr,
-                             const std::string& future_spec) {
-  std::string s;
-  auto append32 = [&s](std::int_fast32_t v) {
-    const std::int_fast32_t s32max = 0x7fffffff;
-    const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
-    std::uint_fast32_t uv;
-    if (v >= 0) {
-      uv = static_cast<std::uint_fast32_t>(v);
-    } else {
-      uv = static_cast<std::uint_fast32_t>(v + s32max + 1) + s32maxU + 1;
-    }
-    for (int i = 3; i >= 0; --i) {
-      s.push_back(static_cast<char>((uv >> (i * 8)) & 0xff));
-    }
-  };
-  auto append64 = [&s](std::int_fast64_t v) {
-    const std::int_fast64_t s64max = 0x7fffffffffffffff;
-    const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
-    std::uint_fast64_t uv;
-    if (v >= 0) {
-      uv = static_cast<std::uint_fast64_t>(v);
-    } else {
-      uv = static_cast<std::uint_fast64_t>(v + s64max + 1) + s64maxU + 1;
-    }
-    for (int i = 7; i >= 0; --i) {
-      s.push_back(static_cast<char>((uv >> (i * 8)) & 0xff));
-    }
-  };
-
-  const std::size_t charcnt = abbr.size();
-
-  // 32-bit header
-  s.append(TZ_MAGIC, 4);
-  s.push_back('2');    // tzh_version
-  s.append(15, '\0');  // tzh_reserved
-  append32(0);         // tzh_ttisutcnt
-  append32(0);         // tzh_ttisstdcnt
-  append32(0);         // tzh_leapcnt
-  append32(0);         // tzh_timecnt (0 32-bit transitions)
-  append32(1);         // tzh_typecnt (1 ttinfo record)
-  append32(static_cast<std::int_fast32_t>(charcnt));  // tzh_charcnt
-
-  // 32-bit data block
-  append32(utc_offset);  // tt_utoff
-  s.push_back(0);        // tt_isdst (standard time)
-  s.push_back(0);        // tt_desigidx
-  s.append(abbr);        // abbreviation table
-
-  // 64-bit header
-  s.append(TZ_MAGIC, 4);
-  s.push_back('2');    // tzh_version
-  s.append(15, '\0');  // tzh_reserved
-  append32(0);         // tzh_ttisutcnt
-  append32(0);         // tzh_ttisstdcnt
-  append32(0);         // tzh_leapcnt
-  append32(1);         // tzh_timecnt (1 64-bit transition)
-  append32(1);         // tzh_typecnt (1 ttinfo record)
-  append32(static_cast<std::int_fast32_t>(charcnt));  // tzh_charcnt
-
-  // 64-bit data block
-  append64(unix_time);   // transition time
-  s.push_back(0);        // type index for transition
-  append32(utc_offset);  // tt_utoff
-  s.push_back(0);        // tt_isdst (standard time)
-  s.push_back(0);        // tt_desigidx
-  s.append(abbr);        // abbreviation table
-
-  // POSIX footer
-  s.push_back('\n');
-  s.append(future_spec);
-  s.push_back('\n');
-  return s;
-}
-
-std::unique_ptr<ZoneInfoSource> ExtendedTestFactory(
-    const std::string& name,
-    const std::function<std::unique_ptr<ZoneInfoSource>(const std::string&)>&
-        fallback) {
-  if (name == "test:ExtendedBeforeEpoch") {
-    // -1 (1969-12-31T23:59:59Z) is the latest final transition before the
-    // epoch, so the zone is rejected despite the future specification.
-    return std::unique_ptr<ZoneInfoSource>(
-        new StringZoneInfoSource(MakeExtendedTzif(
-            -1, -5 * 3600, std::string{"EST", 4}, "EST5EDT,M3.2.0,M11.1.0")));
-  }
-  if (name == "test:ExtendedFarFuture") {
-    // 0 (1970-01-01T00:00:00Z) is the earliest final transition an extended
-    // zone may have, which maximizes the 400-year shift that BreakTime()
-    // needs for a lookup at the maximum time.
-    return std::unique_ptr<ZoneInfoSource>(
-        new StringZoneInfoSource(MakeExtendedTzif(
-            0, -5 * 3600, std::string{"EST", 4}, "EST5EDT,M3.2.0,M11.1.0")));
-  }
-  if (name == "test:UnterminatedAbbreviation") {
-    // The abbreviation area is missing its final NUL, so the abbreviation
-    // would run into whatever ExtendTransitions() appends behind it.
-    return std::unique_ptr<ZoneInfoSource>(new StringZoneInfoSource(
-        MakeExtendedTzif(0, -5 * 3600, "EST", "EST5EDT,M3.2.0,M11.1.0")));
-  }
-  return fallback(name);
-}
-
-// Tests that a TZif file whose abbreviation area is not NUL-terminated
-// is rejected.
-TEST(TimeZoneEdgeCase, UnterminatedAbbreviation) {
-  auto prev_factory = cctz_extension::zone_info_source_factory;
-  cctz_extension::zone_info_source_factory = ExtendedTestFactory;
-
-  time_zone tz;
-  EXPECT_FALSE(load_time_zone("test:UnterminatedAbbreviation", &tz));
-
-  cctz_extension::zone_info_source_factory = prev_factory;
-}
-
-// Tests that a TZif file whose explicit transitions end before epoch
-// is rejected when it has a POSIX DST footer string.
-TEST(TimeZoneEdgeCase, ExtendedBeforeEpoch) {
-  auto prev_factory = cctz_extension::zone_info_source_factory;
-  cctz_extension::zone_info_source_factory = ExtendedTestFactory;
-
-  // Extended zones must end with a non-negative explicit transition.
-  time_zone tz;
-  EXPECT_FALSE(load_time_zone("test:ExtendedBeforeEpoch", &tz));
-
-  cctz_extension::zone_info_source_factory = prev_factory;
-}
-
-// Looking up the maximum time in an extended zone must fold back through the
-// 400-year cycle without overflowing when BreakTime() computes the shift.
-TEST(TimeZoneEdgeCase, ExtendedFarFuture) {
-  auto prev_factory = cctz_extension::zone_info_source_factory;
-  cctz_extension::zone_info_source_factory = ExtendedTestFactory;
-
-  time_zone tz;
-  ASSERT_TRUE(load_time_zone("test:ExtendedFarFuture", &tz));
-
-  auto tp_max = time_point<absl::time_internal::cctz::seconds>::max();
-  ExpectTime(tp_max, tz, 292277026596, 12, 4, 10, 30, 7, -5 * 3600, false,
-             "EST");
-  EXPECT_STREQ("EST", tz.lookup(tp_max).abbr);
-
-  cctz_extension::zone_info_source_factory = prev_factory;
-}
-
 }  // namespace cctz
 }  // namespace time_internal
 ABSL_NAMESPACE_END
diff --git a/absl/time/internal/cctz/src/time_zone_posix.cc b/absl/time/internal/cctz/src/time_zone_posix.cc
index c60f98b..efea080 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.cc
+++ b/absl/time/internal/cctz/src/time_zone_posix.cc
@@ -92,17 +92,14 @@
   return p;
 }
 
-// datetime = , ( Jn | n | Mm.w.d ) [ / offset ]
+// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
 const char* ParseDateTime(const char* p, PosixTransition* res) {
-  if (p != nullptr) {
-    if (*p != ',') return nullptr;
+  if (p != nullptr && *p == ',') {
     if (*++p == 'M') {
       int month = 0;
-      if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr) {
-        if (*p != '.') return nullptr;
+      if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
         int week = 0;
-        if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr) {
-          if (*p != '.') return nullptr;
+        if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
           int weekday = 0;
           if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
             res->date.fmt = PosixTransition::M;
@@ -125,17 +122,17 @@
         res->date.n.day = static_cast<std::int_fast16_t>(day);
       }
     }
-    if (p != nullptr) {
-      res->time.offset = 2 * 60 * 60;  // default offset is 02:00:00
-      if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
-    }
+  }
+  if (p != nullptr) {
+    res->time.offset = 2 * 60 * 60;  // default offset is 02:00:00
+    if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
   }
   return p;
 }
 
 }  // namespace
 
-// spec = std offset [ dst [ offset ] datetime datetime ]
+// spec = std offset [ dst [ offset ] , datetime , datetime ]
 bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
   const char* p = spec.c_str();
   if (*p == ':') return false;
diff --git a/absl/time/internal/cctz/src/time_zone_posix.h b/absl/time/internal/cctz/src/time_zone_posix.h
index 23f5699..7fd2b9e 100644
--- a/absl/time/internal/cctz/src/time_zone_posix.h
+++ b/absl/time/internal/cctz/src/time_zone_posix.h
@@ -13,7 +13,7 @@
 //   limitations under the License.
 
 // Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in
-// https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html.
+// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html.
 //
 // The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0",
 // which would be broken down as ...
diff --git a/absl/time/internal/cctz/src/time_zone_posix_test.cc b/absl/time/internal/cctz/src/time_zone_posix_test.cc
deleted file mode 100644
index 8e429f7..0000000
--- a/absl/time/internal/cctz/src/time_zone_posix_test.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2026 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//   https://www.apache.org/licenses/LICENSE-2.0
-//
-//   Unless required by applicable law or agreed to in writing, software
-//   distributed under the License is distributed on an "AS IS" BASIS,
-//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-//   See the License for the specific language governing permissions and
-//   limitations under the License.
-
-#include "absl/time/internal/cctz/src/time_zone_posix.h"
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-#include "absl/base/config.h"
-
-namespace absl {
-ABSL_NAMESPACE_BEGIN
-namespace time_internal {
-namespace cctz {
-
-using ::testing::Eq;
-using ::testing::IsEmpty;
-
-// We only support the second POSIX format (that is, neither the
-// "first character is a <colon>" format, nor the "geographical
-// or a special timezone" format).  We also require DST start/end
-// rules whenever a DST abbreviation is given (zic always provides
-// them).  So, ...
-//
-//   spec = abbr offset [ abbr [ offset ] datetime datetime ]
-//   abbr = <.*?> | [^-+,\d]{3,}
-//   offset = [+|-]hh[:mm[:ss]]
-//   datetime = , ( Jn | n | Mm.w.d ) [ / offset ]
-
-TEST(ParsePosixSpec, UnsupportedFormats) {
-  PosixTimeZone zone;
-  EXPECT_FALSE(ParsePosixSpec(":characters", &zone));
-  EXPECT_FALSE(ParsePosixSpec("Area/Location", &zone));
-}
-
-TEST(ParsePosixSpec, StdOnly) {
-  PosixTimeZone zone;
-
-  // America/Cancun
-  EXPECT_TRUE(ParsePosixSpec("EST5", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("EST"));
-  EXPECT_THAT(zone.std_offset, Eq(-5 * 60 * 60));
-  EXPECT_THAT(zone.dst_abbr, IsEmpty());
-
-  // Australia/Darwin
-  EXPECT_TRUE(ParsePosixSpec("ACST-9:30", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("ACST"));
-  EXPECT_THAT(zone.std_offset, Eq((9 * 60 + 30) * 60));
-  EXPECT_THAT(zone.dst_abbr, IsEmpty());
-
-  // Australia/Eucla
-  EXPECT_TRUE(ParsePosixSpec("<+0845>-8:45", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("+0845"));
-  EXPECT_THAT(zone.std_offset, Eq((8 * 60 + 45) * 60));
-  EXPECT_THAT(zone.dst_abbr, IsEmpty());
-}
-
-TEST(ParsePosixSpec, WithDst) {
-  PosixTimeZone zone;
-
-  // America/New_York
-  EXPECT_TRUE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.0", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("EST"));
-  EXPECT_THAT(zone.std_offset, Eq(-5 * 60 * 60));
-  EXPECT_THAT(zone.dst_abbr, Eq("EDT"));
-  EXPECT_THAT(zone.dst_offset, Eq(-4 * 60 * 60));
-  EXPECT_THAT(zone.dst_start.date.fmt, Eq(PosixTransition::M));
-  EXPECT_THAT(zone.dst_start.date.m.month, Eq(3));
-  EXPECT_THAT(zone.dst_start.date.m.week, Eq(2));
-  EXPECT_THAT(zone.dst_start.date.m.weekday, Eq(0));
-  EXPECT_THAT(zone.dst_start.time.offset, Eq(2 * 60 * 60));
-  EXPECT_THAT(zone.dst_end.date.fmt, Eq(PosixTransition::M));
-  EXPECT_THAT(zone.dst_end.date.m.month, Eq(11));
-  EXPECT_THAT(zone.dst_end.date.m.week, Eq(1));
-  EXPECT_THAT(zone.dst_end.date.m.weekday, Eq(0));
-  EXPECT_THAT(zone.dst_end.time.offset, Eq(2 * 60 * 60));
-
-  // Australia/Adelaide
-  EXPECT_TRUE(ParsePosixSpec("ACST-9:30ACDT,M10.1.0,M4.1.0/3", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("ACST"));
-  EXPECT_THAT(zone.std_offset, Eq((9 * 60 + 30) * 60));
-  EXPECT_THAT(zone.dst_abbr, Eq("ACDT"));
-  EXPECT_THAT(zone.dst_offset, Eq((10 * 60 + 30) * 60));
-  EXPECT_THAT(zone.dst_start.date.fmt, Eq(PosixTransition::M));
-  EXPECT_THAT(zone.dst_start.date.m.month, Eq(10));
-  EXPECT_THAT(zone.dst_start.date.m.week, Eq(1));
-  EXPECT_THAT(zone.dst_start.date.m.weekday, Eq(0));
-  EXPECT_THAT(zone.dst_start.time.offset, Eq(2 * 60 * 60));
-  EXPECT_THAT(zone.dst_end.date.fmt, Eq(PosixTransition::M));
-  EXPECT_THAT(zone.dst_end.date.m.month, Eq(4));
-  EXPECT_THAT(zone.dst_end.date.m.week, Eq(1));
-  EXPECT_THAT(zone.dst_end.date.m.weekday, Eq(0));
-  EXPECT_THAT(zone.dst_end.time.offset, Eq(3 * 60 * 60));
-
-  // Australia/Lord_Howe
-  EXPECT_TRUE(ParsePosixSpec("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("+1030"));
-  EXPECT_THAT(zone.std_offset, Eq((10 * 60 + 30) * 60));
-  EXPECT_THAT(zone.dst_abbr, Eq("+11"));
-  EXPECT_THAT(zone.dst_offset, Eq(11 * 60 * 60));
-  EXPECT_THAT(zone.dst_start.date.fmt, Eq(PosixTransition::M));
-  EXPECT_THAT(zone.dst_start.date.m.month, Eq(10));
-  EXPECT_THAT(zone.dst_start.date.m.week, Eq(1));
-  EXPECT_THAT(zone.dst_start.date.m.weekday, Eq(0));
-  EXPECT_THAT(zone.dst_start.time.offset, Eq(2 * 60 * 60));
-  EXPECT_THAT(zone.dst_end.date.fmt, Eq(PosixTransition::M));
-  EXPECT_THAT(zone.dst_end.date.m.month, Eq(4));
-  EXPECT_THAT(zone.dst_end.date.m.week, Eq(1));
-  EXPECT_THAT(zone.dst_end.date.m.weekday, Eq(0));
-  EXPECT_THAT(zone.dst_end.time.offset, Eq(2 * 60 * 60));
-
-  // Africa/Casablanca (year-round DST)
-  EXPECT_TRUE(ParsePosixSpec("<+00>0<+01>,0/0,J365/25", &zone));
-  EXPECT_THAT(zone.std_abbr, Eq("+00"));
-  EXPECT_THAT(zone.std_offset, Eq(0));
-  EXPECT_THAT(zone.dst_abbr, Eq("+01"));
-  EXPECT_THAT(zone.dst_offset, Eq(1 * 60 * 60));
-  EXPECT_THAT(zone.dst_start.date.fmt, Eq(PosixTransition::N));
-  EXPECT_THAT(zone.dst_start.date.n.day, Eq(0));
-  EXPECT_THAT(zone.dst_start.time.offset, Eq(0));
-  EXPECT_THAT(zone.dst_end.date.fmt, Eq(PosixTransition::J));
-  EXPECT_THAT(zone.dst_end.date.n.day, Eq(365));
-  EXPECT_THAT(zone.dst_end.time.offset, Eq(25 * 60 * 60));
-}
-
-TEST(TimeZonePosix, ParseErrors) {
-  PosixTimeZone zone;
-
-  // STD abbreviation errors.
-  EXPECT_FALSE(ParsePosixSpec("ET5", &zone));
-  EXPECT_FALSE(ParsePosixSpec("ET+", &zone));
-  EXPECT_FALSE(ParsePosixSpec("ET-", &zone));
-  EXPECT_FALSE(ParsePosixSpec("ET,", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<00", &zone));
-
-  // STD offset errors.
-  EXPECT_FALSE(ParsePosixSpec("<00>", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<00>+", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<00>-", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<00>?", &zone));
-
-  // DST abbreviation errors.
-  EXPECT_FALSE(ParsePosixSpec("EST5DT,M3.2.0,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT+,M3.2.0,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT-,M3.2.0,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<00>0<-01", &zone));
-
-  // DST offset errors.
-  EXPECT_FALSE(ParsePosixSpec("<01>1<00>?,0,0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<01>1<00>+?,0,0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("<01>1<00>-?,0,0", &zone));
-
-  // Malformed DST start date/time.
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M13.2.0,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.6.0,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.7,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,J0,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,366,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0/,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0/?,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0/1:?,M11.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0/1:2:?,M11.1.0", &zone));
-
-  // Malformed DST end date/time.
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M?.1.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.?.0", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.?", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,J?", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,?", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.0/", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.0/168", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.0/167:60", &zone));
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.0/167:59:60", &zone));
-
-  // Trailing data.
-  EXPECT_FALSE(ParsePosixSpec("EST5EDT,M3.2.0,M11.1.0junk", &zone));
-}
-
-}  // namespace cctz
-}  // namespace time_internal
-ABSL_NAMESPACE_END
-}  // namespace absl
diff --git a/absl/time/internal/cctz/testdata/version b/absl/time/internal/cctz/testdata/version
index 9217a2d..75d34ee 100644
--- a/absl/time/internal/cctz/testdata/version
+++ b/absl/time/internal/cctz/testdata/version
@@ -1 +1 @@
-2026c
+2026b
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
index fb2f5cc..240ebb2 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/Casablanca
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
index 46286b9..909c5f9 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Africa/El_Aaiun
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
index 379e365..645ee94 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Edmonton
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
index 379e365..645ee94 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
+++ b/absl/time/internal/cctz/testdata/zoneinfo/America/Yellowknife
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
index 379e365..645ee94 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
+++ b/absl/time/internal/cctz/testdata/zoneinfo/Canada/Mountain
Binary files differ
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
index 635eabc..a9b47bc 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zone1970.tab
@@ -112,7 +112,7 @@
 CA	+624900-0920459	America/Rankin_Inlet	Central - NU (central)
 CA	+5024-10439	America/Regina	CST - SK (most areas)
 CA	+5017-10750	America/Swift_Current	CST - SK (midwest)
-CA	+5333-11328	America/Edmonton	CST - AB, BC(E), NT(E), SK(W)
+CA	+5333-11328	America/Edmonton	Mountain - AB, BC(E), NT(E), SK(W)
 CA	+690650-1050310	America/Cambridge_Bay	Mountain - NU (west)
 CA	+682059-1334300	America/Inuvik	Mountain - NT (west)
 CA	+4916-12307	America/Vancouver	MST - BC (most areas)
diff --git a/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab b/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
index 9c3a8cf..54e4485 100644
--- a/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
+++ b/absl/time/internal/cctz/testdata/zoneinfo/zonenow.tab
@@ -56,19 +56,16 @@
 XX	-2504-13005	Pacific/Pitcairn	Pitcairn
 #
 # -08/-07 - PST/PDT (North America DST)
-XX	+340308-1181434	America/Los_Angeles	Pacific (PST/PDT) - US; Mexico near US border
+XX	+340308-1181434	America/Los_Angeles	Pacific (PST/PDT) - US & Canada; Mexico near US border
 #
 # -08/-07 - PST/PDT (North America DST) until 2026-11-01 02:00; then MST
-XX	+4916-12307	America/Vancouver	Mountain Standard (MST) - British Columbia (most areas)
+XX	+4916-12307	America/Vancouver	MST - BC (most areas)
 #
 # -07 - MST
 XX	+332654-1120424	America/Phoenix	Mountain Standard (MST) - Arizona; western Mexico; Yukon
 #
 # -07/-06 - MST/MDT (North America DST)
-XX	+394421-1045903	America/Denver	Mountain (MST/MDT) - US; Mexico near US border; northern Canada
-#
-# -07/-06 - MST/MDT (North America DST) until 2026-11-01 02:00; then CST
-XX	+5333-11328	America/Edmonton	Central Standard (CST) - Alberta and some neighbors
+XX	+394421-1045903	America/Denver	Mountain (MST/MDT) - US & Canada; Mexico near US border
 #
 # -06
 XX	-0054-08936	Pacific/Galapagos	Galápagos