Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++][chrono] Adds the sys_info class. #85619

Merged
merged 1 commit into from
Apr 10, 2024
Merged

Conversation

mordante
Copy link
Member

Adds the sys_info class and time_zone::get_info(). The code still has a few quirks and has not been optimized for performance yet.

The returned sys_info is compared against the output of the zdump tool in the test giving confidence the implementation is correct.

Implements parts of:

  • P0355 Extending to Calendars and Time Zones

Implements:

  • LWGXXXX The sys_info range should be affected by save

@mordante mordante requested a review from a team as a code owner March 18, 2024 09:44
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Mar 18, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Mar 18, 2024

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

Adds the sys_info class and time_zone::get_info(). The code still has a few quirks and has not been optimized for performance yet.

The returned sys_info is compared against the output of the zdump tool in the test giving confidence the implementation is correct.

Implements parts of:

  • P0355 Extending <chrono> to Calendars and Time Zones

Implements:

  • LWGXXXX The sys_info range should be affected by save

Patch is 119.62 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/85619.diff

17 Files Affected:

  • (modified) libcxx/docs/Status/Cxx2cIssues.csv (+1)
  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (added) libcxx/include/__chrono/sys_info.h (+53)
  • (modified) libcxx/include/__chrono/time_zone.h (+9)
  • (modified) libcxx/include/chrono (+13)
  • (modified) libcxx/include/libcxx.imp (+1)
  • (modified) libcxx/modules/std/chrono.inc (+2)
  • (modified) libcxx/src/include/tzdb/types_private.h (+13-2)
  • (modified) libcxx/src/include/tzdb/tzdb_list_private.h (+7)
  • (modified) libcxx/src/time_zone.cpp (+855)
  • (modified) libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp (+1)
  • (modified) libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp (+2)
  • (added) libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp (+140)
  • (added) libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/sys_info.members.compile.pass.cpp (+33)
  • (added) libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp (+1374)
  • (added) libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/sys_info.zdump.pass.cpp (+124)
  • (modified) libcxx/utils/libcxx/test/features.py (+6)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 58e995809777c1..a6aa70ecc866e0 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -41,4 +41,5 @@
 "`4001 <https://wg21.link/LWG4001>`__","``iota_view`` should provide ``empty``","Kona November 2023","","","|ranges|"
 "","","","","",""
 "`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
+"XXXX","","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0"
 "","","","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 5d9a693d152e4a..24cef9cd877c62 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -289,6 +289,7 @@ set(files
   __chrono/ostream.h
   __chrono/parser_std_format_spec.h
   __chrono/statically_widen.h
+  __chrono/sys_info.h
   __chrono/steady_clock.h
   __chrono/system_clock.h
   __chrono/time_point.h
diff --git a/libcxx/include/__chrono/sys_info.h b/libcxx/include/__chrono/sys_info.h
new file mode 100644
index 00000000000000..16ec5dd254d59a
--- /dev/null
+++ b/libcxx/include/__chrono/sys_info.h
@@ -0,0 +1,53 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
+
+#ifndef _LIBCPP___CHRONO_SYS_INFO_H
+#define _LIBCPP___CHRONO_SYS_INFO_H
+
+#include <version>
+// Enable the contents of the header only when libc++ was built with experimental features enabled.
+#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+#  include <__chrono/duration.h>
+#  include <__chrono/system_clock.h>
+#  include <__chrono/time_point.h>
+#  include <__config>
+#  include <string>
+
+#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#    pragma GCC system_header
+#  endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#  if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) &&   \
+      !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+
+namespace chrono {
+
+struct sys_info {
+  sys_seconds begin;
+  sys_seconds end;
+  seconds offset;
+  minutes save;
+  string abbrev;
+};
+
+} // namespace chrono
+
+#  endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
+         // && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+#endif // _LIBCPP___CHRONO_SYS_INFO_H
diff --git a/libcxx/include/__chrono/time_zone.h b/libcxx/include/__chrono/time_zone.h
index 7d97327a6c8e99..a5af6297a4cf92 100644
--- a/libcxx/include/__chrono/time_zone.h
+++ b/libcxx/include/__chrono/time_zone.h
@@ -16,6 +16,7 @@
 // Enable the contents of the header only when libc++ was built with experimental features enabled.
 #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
 
+#  include <__chrono/sys_info.h>
 #  include <__compare/strong_order.h>
 #  include <__config>
 #  include <__memory/unique_ptr.h>
@@ -55,10 +56,18 @@ class _LIBCPP_AVAILABILITY_TZDB time_zone {
 
   _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name(); }
 
+  template <class _Duration>
+  _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI sys_info get_info(const sys_time<_Duration>& __time) const {
+    return __get_info(chrono::time_point_cast<seconds>(__time));
+  }
+
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; }
 
 private:
   [[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept;
+
+  [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info __get_info(sys_seconds __time) const;
+
   unique_ptr<__impl> __impl_;
 };
 
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index 8fdc30a3624dfc..00b940a6610a3a 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -724,6 +724,15 @@ const time_zone* current_zone()
 const tzdb& reload_tzdb();                                                       // C++20
 string remote_version();                                                         // C++20
 
+// [time.zone.info], information classes
+struct sys_info {                                                                // C++20
+  sys_seconds   begin;
+  sys_seconds   end;
+  seconds       offset;
+  minutes       save;
+  string        abbrev;
+};
+
 // 25.10.5, class time_zone                                                      // C++20
 enum class choose {earliest, latest};
 class time_zone {
@@ -733,6 +742,9 @@ class time_zone {
   // unspecified additional constructors
 
   string_view name() const noexcept;
+
+  template<class Duration>
+  sys_info get_info(const sys_time<Duration>& st) const;
 };
 bool operator==(const time_zone& x, const time_zone& y) noexcept;                // C++20
 strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept;    // C++20
@@ -906,6 +918,7 @@ constexpr chrono::year                                  operator ""y(unsigned lo
 #if !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) &&                              \
     !defined(_LIBCPP_HAS_NO_LOCALIZATION)
 #  include <__chrono/leap_second.h>
+#  include <__chrono/sys_info.h>
 #  include <__chrono/time_zone.h>
 #  include <__chrono/time_zone_link.h>
 #  include <__chrono/tzdb.h>
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index 2d6ac5f9e982aa..e3a08860c0b059 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -287,6 +287,7 @@
   { include: [ "<__chrono/parser_std_format_spec.h>", "private", "<chrono>", "public" ] },
   { include: [ "<__chrono/statically_widen.h>", "private", "<chrono>", "public" ] },
   { include: [ "<__chrono/steady_clock.h>", "private", "<chrono>", "public" ] },
+  { include: [ "<__chrono/sys_info.h>", "private", "<chrono>", "public" ] },
   { include: [ "<__chrono/system_clock.h>", "private", "<chrono>", "public" ] },
   { include: [ "<__chrono/time_point.h>", "private", "<chrono>", "public" ] },
   { include: [ "<__chrono/time_zone.h>", "private", "<chrono>", "public" ] },
diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc
index e14228043d3b84..575e6347aecce1 100644
--- a/libcxx/modules/std/chrono.inc
+++ b/libcxx/modules/std/chrono.inc
@@ -212,10 +212,12 @@ export namespace std {
     // [time.zone.exception], exception classes
     using std::chrono::ambiguous_local_time;
     using std::chrono::nonexistent_local_time;
+#    endif // if 0
 
     // [time.zone.info], information classes
     using std::chrono::sys_info;
 
+#    if 0
     // [time.zone.timezone], class time_zone
     using std::chrono::choose;
 #    endif // if 0
diff --git a/libcxx/src/include/tzdb/types_private.h b/libcxx/src/include/tzdb/types_private.h
index 4604b9fc88114d..bdc9418a8866be 100644
--- a/libcxx/src/include/tzdb/types_private.h
+++ b/libcxx/src/include/tzdb/types_private.h
@@ -33,7 +33,17 @@ namespace chrono::__tz {
 // Sun>=8   first Sunday on or after the eighth
 // Sun<=25  last Sunday on or before the 25th
 struct __constrained_weekday {
-  /*  year_month_day operator()(year __year, month __month);*/ // needed but not implemented
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI year_month_day operator()(year __year, month __month) const {
+    auto __result = static_cast<sys_days>(year_month_day{__year, __month, __day});
+    weekday __wd{static_cast<sys_days>(__result)};
+
+    if (__comparison == __le)
+      __result -= __wd - __weekday;
+    else
+      __result += __weekday - __wd;
+
+    return __result;
+  }
 
   weekday __weekday;
   enum __comparison_t { __le, __ge } __comparison;
@@ -85,7 +95,8 @@ struct __continuation {
   // used.
   // If this field contains - then standard time always
   // applies. This is indicated by the monostate.
-  using __rules_t = variant<monostate, __tz::__save, string, size_t>;
+  // TODO TZDB Investigate implemention the size_t based caching.
+  using __rules_t = variant<monostate, __tz::__save, string /*, size_t*/>;
 
   __rules_t __rules;
 
diff --git a/libcxx/src/include/tzdb/tzdb_list_private.h b/libcxx/src/include/tzdb/tzdb_list_private.h
index f43d7d8ea772be..a3f56e79a51791 100644
--- a/libcxx/src/include/tzdb/tzdb_list_private.h
+++ b/libcxx/src/include/tzdb/tzdb_list_private.h
@@ -84,6 +84,13 @@ class tzdb_list::__impl {
   const_iterator cbegin() const noexcept { return begin(); }
   const_iterator cend() const noexcept { return end(); }
 
+  const __tz::__rules_storage_type& __rules() const noexcept {
+#ifndef _LIBCPP_HAS_NO_THREADS
+    shared_lock __lock{__mutex_};
+#endif
+    return __rules_.front();
+  }
+
 private:
   // Loads the tzdbs
   // pre: The caller ensures the locking, if needed, is done.
diff --git a/libcxx/src/time_zone.cpp b/libcxx/src/time_zone.cpp
index b6bf06a116f68b..84ff0e1ae49268 100644
--- a/libcxx/src/time_zone.cpp
+++ b/libcxx/src/time_zone.cpp
@@ -8,14 +8,706 @@
 
 // For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
 
+// TODO TZDB look at optimizations
+//
+// The current algorithm is correct but not efficient. For example, in a named
+// rule based continuation finding the next rule does quite a bit of work,
+// returns the next rule and "forgets" its state. This could be better.
+//
+// It would be possible to cache lookups. If a time for a zone is calculated its
+// sys_info could be kept and the next lookup could test whether the time is in
+// a "known" sys_info. The wording in the Standard hints at this slowness by
+// "suggesting" this could be implemented at the user's side.
+
+// TODO TZDB look at removing quirks
+//
+// The code has some special rules to adjust the timing at the continuation
+// switches. This works correctly, but some of the places feel odd. It would be
+// good to investigate this further and see whether all quirks are needed or
+// that there are better fixes.
+//
+// These quirks often use a 12h interval; this is the scan interval of zdump,
+// which implies there are no sys_info objects with a duration of less than 12h.
+
+#include <algorithm>
 #include <chrono>
+#include <expected>
+#include <map>
+#include <ranges>
 
 #include "include/tzdb/time_zone_private.h"
+#include "include/tzdb/tzdb_list_private.h"
+
+// TODO TZDB remove debug printing
+#ifdef PRINT
+#  include <print>
+#endif
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#ifdef PRINT
+template <>
+struct formatter<chrono::sys_info, char> {
+  template <class ParseContext>
+  constexpr typename ParseContext::iterator parse(ParseContext& ctx) {
+    return ctx.begin();
+  }
+
+  template <class FormatContext>
+  typename FormatContext::iterator format(const chrono::sys_info& info, FormatContext& ctx) const {
+    return std::format_to(
+        ctx.out(), "[{}, {}) {:%Q%q} {:%Q%q} {}", info.begin, info.end, info.offset, info.save, info.abbrev);
+  }
+};
+#endif
+
 namespace chrono {
 
+//===----------------------------------------------------------------------===//
+//                           Details
+//===----------------------------------------------------------------------===//
+
+struct __sys_info {
+  sys_info __info;
+  bool __can_merge; // Can the returned sys_info object be merged with
+};
+
+// Return type for helper function to get a sys_info.
+// - The expected result returns the "best" sys_info object. This object can be
+//   before the requested time. Sometimes sys_info objects from different
+//   continuations share their offset, save, and abbrev and these objects are
+//   merged to one sys_info object. The __can_merge flag determines whether the
+//   current result can be merged with the next result.
+// - The unexpected result means no sys_info object was found and the time is
+//   the time to be used for the next search iteration.
+using __sys_info_result = expected<__sys_info, sys_seconds>;
+
+template <ranges::forward_range _Range,
+          class _Type,
+          class _Proj                                                                                  = identity,
+          indirect_strict_weak_order<const _Type*, projected<ranges::iterator_t<_Range>, _Proj>> _Comp = ranges::less>
+[[nodiscard]] static ranges::borrowed_iterator_t<_Range>
+__binary_find(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) {
+  auto __end = ranges::end(__r);
+  auto __ret = ranges::lower_bound(ranges::begin(__r), __end, __value, __comp, __proj);
+  if (__ret == __end)
+    return __end;
+
+  // When the value does not match the predicate it's equal and a valid result
+  // was found.
+  return !std::invoke(__comp, __value, std::invoke(__proj, *__ret)) ? __ret : __end;
+}
+
+// Format based on https://data.iana.org/time-zones/tz-how-to.html
+//
+// 1  a time zone abbreviation that is a string of three or more characters that
+//    are either ASCII alphanumerics, “+”, or “-”
+// 2  the string “%z”, in which case the “%z” will be replaced by a numeric time
+//    zone abbreviation
+// 3  a pair of time zone abbreviations separated by a slash (‘/’), in which
+//    case the first string is the abbreviation for the standard time name and
+//    the second string is the abbreviation for the daylight saving time name
+// 4  a string containing “%s”, in which case the “%s” will be replaced by the
+//    text in the appropriate Rule’s LETTER column, and the resulting string should
+//    be a time zone abbreviation
+//
+// Accepting invalid formats that can be processed in a sensible way would better
+// serve the user than throwing an exception. So some of these rules are not
+// strictly validated.
+// 1  This is not validated. Some examples that will be accepted are, "+04:30",
+//    "Q", "42".
+// 2  How this format is formatted is not specified. In the current tzdata.zi
+//    this value is not used. This value is accepted in a part of the format. So
+//    "a%s%zb" will be considered valid.
+// 3  This is not validated, the output might be incorrect.
+//    Proper validation would make the algorithm more complex. Then the first
+//    element of the pair is used the parsing of FORMAT can stop. To do proper
+//    validation the tail should be validated.
+// 4  This value is accepted in a part of the format. So "a%s%zb" will be
+//    considered valid.
+[[nodiscard]] static string
+__format(const __tz::__continuation& __continuation, const string& __letters, seconds __save) {
+  bool __shift = false;
+  string __result;
+  for (char __c : __continuation.__format) {
+    if (__shift) {
+      switch (__c) {
+      case 's':
+        std::ranges::copy(__letters, std::back_inserter(__result));
+        break;
+
+      case 'z': {
+        chrono::hh_mm_ss __offset{__continuation.__stdoff + __save};
+        if (__offset.is_negative()) {
+          __result += '-';
+          __offset = chrono::hh_mm_ss{-(__continuation.__stdoff + __save)};
+        } else
+          __result += '+';
+
+        if (__offset.minutes() != 0min)
+          std::format_to(std::back_inserter(__result), "{:%H%M}", __offset);
+        else
+          std::format_to(std::back_inserter(__result), "{:%H}", __offset);
+      } break;
+
+      default:
+        std::__throw_runtime_error(
+            std::format("corrupt tzdb FORMAT field: invalid sequence '%{}' found, expected %s or %z", __c).c_str());
+      }
+      __shift = false;
+
+    } else if (__c == '/') {
+      if (__save != 0s)
+        __result.clear();
+      else
+        break;
+
+    } else if (__c == '%') {
+      __shift = true;
+    } else {
+      __result.push_back(__c);
+    }
+  }
+
+  if (__shift)
+    std::__throw_runtime_error("corrupt tzdb FORMAT field: input ended with the start of the escape sequence '%'");
+
+  return __result;
+}
+
+[[nodiscard]] static sys_seconds __to_sys_seconds(year_month_day __ymd, seconds __seconds) {
+  seconds __result = static_cast<sys_days>(__ymd).time_since_epoch() + __seconds;
+  return sys_seconds{__result};
+}
+
+[[nodiscard]] static seconds __at_to_sys_seconds(const __tz::__continuation& __continuation) {
+  switch (__continuation.__at.__clock) {
+  case __tz::__clock::__local:
+    return __continuation.__at.__time - __continuation.__stdoff -
+           std::visit(
+               [](const auto& __value) {
+                 using _Tp = decay_t<decltype(__value)>;
+                 if constexpr (same_as<_Tp, monostate>)
+                   return chrono::seconds{0};
+                 else if constexpr (same_as<_Tp, __tz::__save>)
+                   return chrono::duration_cast<seconds>(__value.__time);
+                 else if constexpr (same_as<_Tp, std::string>)
+                   // For a named rule based continuation the SAVE depends on the RULE
+                   // active at the end. This should be determined separately.
+                   return chrono::seconds{0};
+                 else
+                   static_assert(false);
+
+                 std::__libcpp_unreachable();
+               },
+               __continuation.__rules);
+
+  case __tz::__clock::__universal:
+    return __continuation.__at.__time;
+
+  case __tz::__clock::__standard:
+    return __continuation.__at.__time - __continuation.__stdoff;
+  }
+}
+
+[[nodiscard]] static year_month_day __to_year_month_day(year __year, month __month, __tz::__on __on) {
+  return std::visit(
+      [&](const auto& __value) {
+        using T = decay_t<decltype(__value)>;
+        if constexpr (same_as<T, chrono::day>)
+          return year_month_day{__year, __month, __value};
+        else if constexpr (same_as<T, weekday_last>)
+          return year_month_day{static_cast<sys_days>(year_month_weekday_last{__year, __month, __value})};
+        else if constexpr (same_as<T, __tz::__constrained_weekday>)
+          return __value(__year, __month);
+        else
+          static_assert(false);
+
+        std::__libcpp_unreachable();
+      },
+      __on);
+}
+
+[[nodiscard]] static sys_seconds __until_to_sys_seconds(const __tz::__continuation& __continuation) {
+  // Does UNTIL contain the magic value for the last continuation?
+  if (__continuation.__year == chrono::year::min())
+    return sys_seconds::max();
+
+  year_month_day __ymd = chrono::__to_year_month_day(__continuation.__year, __continuation.__in, __continuation.__on);
+  return chrono::__to_sys_seconds(__ymd, chrono::__at_to_sys_seconds(__continuation));
+}
+
+// Holds the UNTIL time for a continuation with a named rule.
+//
+// Unlike continuations with an fixed SAVE named rules have a variable SAVE.
+// This means when the UNTIL uses the local wall time the actual UNTIL value can
+// only be determined when the SAVE is known. This class holds that abstraction.
+class __named_rule_until {
+public:
+  explicit __named_rule_until(const __tz::__continuation& __continuation)
+      : __until_{chrono::__until_to_sys_seconds(__continuation)},
+        __needs_adjustment_{
+            // The last continuation of a ZONE has no UNTIL which basically is
+            // until the end of _local_ time. This value is expressed by
+            // sys_seconds::max(). Subtracting the SAVE leaves large value.
+            // However SAVE can be negative, which would add a value to maximum
+            // leading to undefined behaviour. In practice this often results in
+            // an overflow to a very small value.
+            __until_ != sys_seconds::max() && __continuation.__at.__clock == __tz::__clock::__local} {}
+
+  // Gives the unadjusted until value, this is useful when the SAVE is not known
+  // at all.
+  sys_seconds __until() const noexcept { return __until_; }
+
+  bool __needs_adjustment() const noexcept { return __needs_adjustment_; }
+
+  // Returns the UNTIL adjusted for SAVE.
+  sys_seconds operator()(seconds __save) const noexcept { return __until_ - __needs_adjustment_ * __save; }
+
+private:
+  sys_seconds __until_;
+  bool __needs_adjustment_;
+};
+
+[[nodiscard]] static seconds __at_to_seconds(seconds __stdoff, const __tz::__rule...
[truncated]

@@ -41,4 +41,5 @@
"`4001 <https://wg21.link/LWG4001>`__","``iota_view`` should provide ``empty``","Kona November 2023","","","|ranges|"
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
"XXXX","","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been discussed with Howard and I'll file an LWG issue.

@mordante mordante force-pushed the users/mordante/adds_sys_info branch 6 times, most recently from 96c6e86 to 7f89e68 Compare March 19, 2024 09:42
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can dive into the implementation during the next round of review!

libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
@mordante mordante force-pushed the users/mordante/completes_tzdb_class branch from 7a742c0 to 2e21062 Compare April 3, 2024 16:45
Base automatically changed from users/mordante/completes_tzdb_class to main April 4, 2024 17:03
@mordante mordante force-pushed the users/mordante/adds_sys_info branch 5 times, most recently from 30e7076 to 4be4a60 Compare April 7, 2024 09:53
Copy link

github-actions bot commented Apr 7, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

}

static void write(std::string_view input) {
static int version = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might need a flush.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should automatically happen in the destructor. Or am I overlooking something?

Copy link
Member

@EricWF EricWF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM once adding the tests Louis requested.

libcxx/include/__chrono/sys_info.h Show resolved Hide resolved
libcxx/include/__chrono/time_zone.h Show resolved Hide resolved
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this in some amount of detail, but obviously the code here is really complex so without actually reimplementing it myself, I can't understand everything. However, this looks right to me and I am relying on your test coverage a lot. I think it would be very valuable to add fuzzing tests here, I am certain it would shake out a lot of issues.

This LGTM once all pending comments have been applied. Thanks a lot for the patch!

libcxx/src/time_zone.cpp Outdated Show resolved Hide resolved
libcxx/src/include/tzdb/types_private.h Outdated Show resolved Hide resolved
Adds the sys_info class and time_zone::get_info(). The code still
has a few quirks and has not been optimized for performance yet.

The returned sys_info is compared against the output of the zdump tool in
the test giving confidence the implementation is correct.

Implements parts of:
- P0355 Extending <chrono> to Calendars and Time Zones

Implements:
- LWGXXXX The sys_info range should be affected by save
@mordante mordante force-pushed the users/mordante/adds_sys_info branch from 4be4a60 to 7fce932 Compare April 9, 2024 18:06
@mordante mordante merged commit 1fda177 into main Apr 10, 2024
52 checks passed
@mordante mordante deleted the users/mordante/adds_sys_info branch April 10, 2024 05:50
@vvereschaka
Copy link
Contributor

Hi @mordante ,

JFI, usage of assert_equal&others in that way does not help actually. The error message always shows a line within these functions instead of actual problematic part of the test.
https://lab.llvm.org/buildbot/#/builders/60/builds/16760/steps/14/logs/FAIL__llvm-libc__-static_cfg_in__get_info_sys_time

# .---command stderr------------
# | Assertion failure: lhs.end == rhs.end C:\buildbot\as-builder-1\x-armv7l\llvm-project\libcxx\test\std\time\time.zone\time.zone.timezone\time.zone.members\get_info.sys_time.pass.cpp 65
# | 
# | End:
# | Expected output 1950-01-01 00:00:00
# | Actual output   1879-12-31 19:06:00
# `-----------------------------

@mordante
Copy link
Member Author

Thanks! It seems I overlooked the CI failure. I think the error can be improved, but I disagree that this is not useful. If I'd gotten a "typical" assert message I would not have been able to figure out what the error was; it wouldn't have shown 1950-01-01 00:00:00. This value helped me to discover that the test_indian_kerguelen test failed. I fully agree that this error does not help those not intimately familiar with this test.

I'll think about a way to improve the error to be more useful.

@mgorny
Copy link
Member

mgorny commented Apr 16, 2024

The new tests are failing for me on Gentoo amd64:

FAIL: llvm-libc++-shared.cfg.in :: std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp (8267 of 9593)
******************** TEST 'llvm-libc++-shared.cfg.in :: std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.
cpp' FAILED ********************
Exit Code: 250

Command Output (stdout):
--
# COMPILED WITH
/usr/lib/ccache/bin/x86_64-pc-linux-gnu-clang++ /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/libcxx/test/std/time/time.zone
/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp -pthread --target=x86_64-pc-linux-gnu -nostdinc++ -I /var/tmp/portage/
sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/include/c++/v1 -I /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20
240416/work/runtimes_build-abi_x86_64.amd64/include/c++/v1 -I /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/libcxx/test/supp
ort -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-command-line-argument -Wno
-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprecated-copy -Wdeprecat
ed-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-parameter -Wunreachable-cod
e -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-failed -Wno-mismatched-n
ew-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D_LIBCPP_HARDENING_MO
DE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings  -lc++experimental -nostdlib++ -L /var/tmp/portage/sys-lib
s/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/lib -Wl,-rpath,/var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/wor
k/runtimes_build-abi_x86_64.amd64/lib -lc++ -latomic -o /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86
_64.amd64/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.sys_time.pass.cpp.dir/t.tmp.exe
# executed command: /usr/lib/ccache/bin/x86_64-pc-linux-gnu-clang++ /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/libcxx/tes
t/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp -pthread --target=x86_64-pc-linux-gnu -nostdinc++ 
-I /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/include/c++/v1 -I /var/tmp/portage/sys-libs
/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/include/c++/v1 -I /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/w
ork/libcxx/test/support -std=c++26 -Werror -Wall -Wctad-maybe-unsupported -Wextra -Wshadow -Wundef -Wunused-template -Wno-unused-comman
d-line-argument -Wno-attributes -Wno-pessimizing-move -Wno-noexcept-type -Wno-atomic-alignment -Wno-reserved-module-identifier -Wdeprec
ated-copy -Wdeprecated-copy-dtor -Wno-user-defined-literals -Wno-tautological-compare -Wsign-compare -Wunused-variable -Wunused-paramet
er -Wunreachable-code -Wno-unused-local-typedef -Wno-local-type-template-args -Wno-c++11-extensions -Wno-unknown-pragmas -Wno-pass-fail
ed -Wno-mismatched-new-delete -Wno-redundant-move -Wno-self-move -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_ENABLE_EXPERIMENTAL -D
_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE -Werror=thread-safety -Wuser-defined-warnings -lc++experimental -nostdlib++ -L /var/
tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/lib -Wl,-rpath,/var/tmp/portage/sys-libs/libcxx-19.
0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/lib -lc++ -latomic -o /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.sys_time.pass.cpp.dir/t.tmp.exe
# EXECUTED AS
/usr/bin/python3.12 /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/libcxx/utils/run.py --execdir /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.sys_time.pass.cpp.dir --  /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.sys_time.pass.cpp.dir/t.tmp.exe
# executed command: /usr/bin/python3.12 /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/libcxx/utils/run.py --execdir /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.sys_time.pass.cpp.dir -- /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/runtimes_build-abi_x86_64.amd64/test/std/time/time.zone/time.zone.timezone/time.zone.members/Output/get_info.sys_time.pass.cpp.dir/t.tmp.exe
# .---command stderr------------
# | Assertion failure: lhs.end == rhs.end /var/tmp/portage/sys-libs/libcxx-19.0.0_pre20240416/work/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp 65
# | 
# | End:
# | Expected output 1957-01-29 00:00:00
# | Actual output   1947-03-13 20:53:08
# `-----------------------------
# error: command failed with exit status: 250

--

********************

@mordante
Copy link
Member Author

Thanks for the comment. For now I disabled the test entirely. I'll investigate the later.

@vvereschaka
Copy link
Contributor

Hi @mordante ,

I think the error can be improved, but I disagree that this is not useful.

No, my point was that it is difficult to get the exact problem, especially without accessing to the target equpment. Sorry for unclear explanation.

Anyway, I tried to find which part of the test is failed and I found that it gets failed on Antarctica/Syowa zone.
Also, this test has passed on the Aarch64/Ubuntu Linux targets.

There is a zdump for Antarctica/Syowa on few arm boards, two of them are aarch64 (passed test) and another is armv7 (failed test):

aarch64 / Ubuntu Linux 22.04 (passed test)

ubuntu@jetson-agx-2197:/usr/share/zoneinfo/Antarctica$ zdump -v Antarctica/Syowa
Antarctica/Syowa  -9223372036854775808 = NULL
Antarctica/Syowa  -9223372036854689408 = NULL
Antarctica/Syowa  Mon Jan 28 23:59:59 1957 UT = Mon Jan 28 23:59:59 1957 -00 isdst=0 gmtoff=0
Antarctica/Syowa  Tue Jan 29 00:00:00 1957 UT = Tue Jan 29 03:00:00 1957 +03 isdst=0 gmtoff=10800
Antarctica/Syowa  9223372036854689407 = NULL
Antarctica/Syowa  9223372036854775807 = NULL

aarch64 / Ubuntu Linux 18.04

ubuntu@jetson10:/usr/share/zoneinfo/Antarctica$ zdump -v Antarctica/Syowa
Antarctica/Syowa  -9223372036854775808 = NULL
Antarctica/Syowa  -9223372036854689408 = NULL
Antarctica/Syowa  Thu Mar 13 20:53:07 1947 UT = Thu Mar 13 23:59:59 1947 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Thu Mar 13 20:53:08 1947 UT = Thu Mar 13 23:53:08 1947 +03 isdst=0 gmtoff=10800
Antarctica/Syowa  9223372036854689407 = NULL
Antarctica/Syowa  9223372036854775807 = NULL

armv7 / Ubuntu Linux 18.04 (FAILED test)

ubuntu@jetson6:/usr/share/zoneinfo/Antarctica$ zdump -v Antarctica/Syowa
Antarctica/Syowa  Fri Dec 13 20:45:52 1901 UT = Fri Dec 13 23:52:44 1901 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Sat Dec 14 20:45:52 1901 UT = Sat Dec 14 23:52:44 1901 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Thu Mar 13 20:53:07 1947 UT = Thu Mar 13 23:59:59 1947 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Thu Mar 13 20:53:08 1947 UT = Thu Mar 13 23:53:08 1947 +03 isdst=0 gmtoff=10800
Antarctica/Syowa  Mon Jan 18 03:14:07 2038 UT = Mon Jan 18 06:14:07 2038 +03 isdst=0 gmtoff=10800
Antarctica/Syowa  Tue Jan 19 03:14:07 2038 UT = Tue Jan 19 06:14:07 2038 +03 isdst=0 gmtoff=10800

Hope it will help in your investigation of the problem.

@mgorny
Copy link
Member

mgorny commented Apr 18, 2024

Hm, even more interesting. On my Gentoo system, amd64, glibc 2.39, tzdata 2024a:

$ zdump -v Antarctica/Syowa
Antarctica/Syowa  -9223372036854775808 (gmtime failed) = -9223372036854775808 (localtime failed)
Antarctica/Syowa  -67768040609752013 (gmtime failed) = -67768040609752013 (localtime failed)
Antarctica/Syowa  -67768040609752012 (gmtime failed) = Thu Jan  1 00:00:00 -2147481748 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  -67768040609740801 (gmtime failed) = Thu Jan  1 03:06:51 -2147481748 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Thu Jan  1 00:00:00 -2147481748 UT = Thu Jan  1 03:06:52 -2147481748 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Thu Mar 13 20:53:07 1947 UT = Thu Mar 13 23:59:59 1947 LMT isdst=0 gmtoff=11212
Antarctica/Syowa  Thu Mar 13 20:53:08 1947 UT = Thu Mar 13 23:53:08 1947 +03 isdst=0 gmtoff=10800
Antarctica/Syowa  Wed Dec 31 20:59:59 2147485547 UT = Wed Dec 31 23:59:59 2147485547 +03 isdst=0 gmtoff=10800
Antarctica/Syowa  Wed Dec 31 21:00:00 2147485547 UT = 67768036191666000 (localtime failed)
Antarctica/Syowa  Wed Dec 31 23:59:59 2147485547 UT = 67768036191676799 (localtime failed)
Antarctica/Syowa  67768036191676800 (gmtime failed) = 67768036191676800 (localtime failed)
Antarctica/Syowa  9223372036854775807 (gmtime failed) = 9223372036854775807 (localtime failed)

@mordante
Copy link
Member Author

Hi @mordante ,

I think the error can be improved, but I disagree that this is not useful.

Ah thanks. I'm working on a patch to show the source location of the caller, which would make it a lot easier to spot the issue.

Anyway, I tried to find which part of the test is failed and I found that it gets failed on Antarctica/Syowa zone. Also, this test has passed on the Aarch64/Ubuntu Linux targets.

> Hope it will help in your investigation of the problem.

Thanks I think it will. I'll check whether these rules have changes, in which case it might depend on the version of the time zone database used. But not only the version seems to matter; there seem to be configuration options too. 2024a on Debian Stable works, but Debian sid is not compatible. (That is a different story which I'm working on.)

For the short term I keep this test disabled and will investigate this further; I first want to improve the output of the error messages.

@yingcong-wu
Copy link
Contributor

Hi @mordante , I encounter some test failure with sys_info.zdump.pass.cpp in different OS.

Here are some os, tzdata version and zdump version first:

  • Red Hat Enterprise Linux 9.0, tzdata 2022a-rearguard, zdump (GNU libc) 2.34
  • Red Hat Enterprise Linux 8.8, 2023c-rearguard, zdump (GNU libc) 2.28
  • Ubuntu 22.04.4 LTS, 2024a, zdump (Ubuntu GLIBC 2.35-0ubuntu3.6) 2.35
  • Ubuntu 24.04 LTS, 2024a, zdump (Ubuntu GLIBC 2.39-0ubuntu8.1) 2.39

First:
With RedHat9, libc++ and zdump have different results of Asia/Dushanbe, but that could be just outdated tzdata. I don't know if we are looking to support older version of tzdata or not.

# +05/+06 is from libcxx
bash> diff libcxx zdump
46,47c46,47
< Asia/Dushanbe  Sat Mar 30 20:00:00 1991 UT = Sun Mar 31 02:00:00 1991 +05/+06 isdst=1 gmtoff=21600
< Asia/Dushanbe  Sun Sep  8 20:59:59 1991 UT = Mon Sep  9 02:59:59 1991 +05/+06 isdst=1 gmtoff=21600
---
> Asia/Dushanbe  Sat Mar 30 20:00:00 1991 UT = Sun Mar 31 02:00:00 1991 +06 isdst=1 gmtoff=21600
> Asia/Dushanbe  Sun Sep  8 20:59:59 1991 UT = Mon Sep  9 02:59:59 1991 +06 isdst=1 gmtoff=21600

Second:
With zone Etc/UTC, only zdump with RedHat9 returns empty, just like libc++'s result. While

  • ReaHat8: returns 620 lines
  • Ubuntu22: returns 58 lines
  • Ubuntu24: returns 58 lines

I don't know much about chrono, hope above information is useful. If you need more information, please let me know.

@mordante
Copy link
Member Author

mordante commented May 8, 2024

Thanks for the info @yingcong-wu. This looks odd, both zdump and libc++ should use the same tzdata.zi and thus produce identical results. I'm really curious about the output of Etc/UTC can you post these for Ubuntu 22.04?

@yingcong-wu
Copy link
Contributor

Sure, it is

Etc/UTC  Mon Dec 31 15:54:16 1900 UT = Mon Dec 31 23:59:59 1900 LMT isdst=0 gmtoff=29143
Etc/UTC  Mon Dec 31 15:54:17 1900 UT = Mon Dec 31 23:54:17 1900 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 12 15:59:59 1919 UT = Sat Apr 12 23:59:59 1919 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 12 16:00:00 1919 UT = Sun Apr 13 01:00:00 1919 CDT isdst=1 gmtoff=32400
Etc/UTC  Tue Sep 30 14:59:59 1919 UT = Tue Sep 30 23:59:59 1919 CDT isdst=1 gmtoff=32400
Etc/UTC  Tue Sep 30 15:00:00 1919 UT = Tue Sep 30 23:00:00 1919 CST isdst=0 gmtoff=28800
Etc/UTC  Fri May 31 15:59:59 1940 UT = Fri May 31 23:59:59 1940 CST isdst=0 gmtoff=28800
Etc/UTC  Fri May 31 16:00:00 1940 UT = Sat Jun  1 01:00:00 1940 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Oct 12 14:59:59 1940 UT = Sat Oct 12 23:59:59 1940 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Oct 12 15:00:00 1940 UT = Sat Oct 12 23:00:00 1940 CST isdst=0 gmtoff=28800
Etc/UTC  Fri Mar 14 15:59:59 1941 UT = Fri Mar 14 23:59:59 1941 CST isdst=0 gmtoff=28800
Etc/UTC  Fri Mar 14 16:00:00 1941 UT = Sat Mar 15 01:00:00 1941 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Nov  1 14:59:59 1941 UT = Sat Nov  1 23:59:59 1941 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Nov  1 15:00:00 1941 UT = Sat Nov  1 23:00:00 1941 CST isdst=0 gmtoff=28800
Etc/UTC  Fri Jan 30 15:59:59 1942 UT = Fri Jan 30 23:59:59 1942 CST isdst=0 gmtoff=28800
Etc/UTC  Fri Jan 30 16:00:00 1942 UT = Sat Jan 31 01:00:00 1942 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep  1 14:59:59 1945 UT = Sat Sep  1 23:59:59 1945 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep  1 15:00:00 1945 UT = Sat Sep  1 23:00:00 1945 CST isdst=0 gmtoff=28800
Etc/UTC  Tue May 14 15:59:59 1946 UT = Tue May 14 23:59:59 1946 CST isdst=0 gmtoff=28800
Etc/UTC  Tue May 14 16:00:00 1946 UT = Wed May 15 01:00:00 1946 CDT isdst=1 gmtoff=32400
Etc/UTC  Mon Sep 30 14:59:59 1946 UT = Mon Sep 30 23:59:59 1946 CDT isdst=1 gmtoff=32400
Etc/UTC  Mon Sep 30 15:00:00 1946 UT = Mon Sep 30 23:00:00 1946 CST isdst=0 gmtoff=28800
Etc/UTC  Mon Apr 14 15:59:59 1947 UT = Mon Apr 14 23:59:59 1947 CST isdst=0 gmtoff=28800
Etc/UTC  Mon Apr 14 16:00:00 1947 UT = Tue Apr 15 01:00:00 1947 CDT isdst=1 gmtoff=32400
Etc/UTC  Fri Oct 31 14:59:59 1947 UT = Fri Oct 31 23:59:59 1947 CDT isdst=1 gmtoff=32400
Etc/UTC  Fri Oct 31 15:00:00 1947 UT = Fri Oct 31 23:00:00 1947 CST isdst=0 gmtoff=28800
Etc/UTC  Fri Apr 30 15:59:59 1948 UT = Fri Apr 30 23:59:59 1948 CST isdst=0 gmtoff=28800
Etc/UTC  Fri Apr 30 16:00:00 1948 UT = Sat May  1 01:00:00 1948 CDT isdst=1 gmtoff=32400
Etc/UTC  Thu Sep 30 14:59:59 1948 UT = Thu Sep 30 23:59:59 1948 CDT isdst=1 gmtoff=32400
Etc/UTC  Thu Sep 30 15:00:00 1948 UT = Thu Sep 30 23:00:00 1948 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 30 15:59:59 1949 UT = Sat Apr 30 23:59:59 1949 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 30 16:00:00 1949 UT = Sun May  1 01:00:00 1949 CDT isdst=1 gmtoff=32400
Etc/UTC  Fri May 27 14:59:59 1949 UT = Fri May 27 23:59:59 1949 CDT isdst=1 gmtoff=32400
Etc/UTC  Fri May 27 15:00:00 1949 UT = Fri May 27 23:00:00 1949 CST isdst=0 gmtoff=28800
Etc/UTC  Sat May  3 17:59:59 1986 UT = Sun May  4 01:59:59 1986 CST isdst=0 gmtoff=28800
Etc/UTC  Sat May  3 18:00:00 1986 UT = Sun May  4 03:00:00 1986 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 13 16:59:59 1986 UT = Sun Sep 14 01:59:59 1986 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 13 17:00:00 1986 UT = Sun Sep 14 01:00:00 1986 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 11 17:59:59 1987 UT = Sun Apr 12 01:59:59 1987 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 11 18:00:00 1987 UT = Sun Apr 12 03:00:00 1987 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 12 16:59:59 1987 UT = Sun Sep 13 01:59:59 1987 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 12 17:00:00 1987 UT = Sun Sep 13 01:00:00 1987 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 16 17:59:59 1988 UT = Sun Apr 17 01:59:59 1988 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 16 18:00:00 1988 UT = Sun Apr 17 03:00:00 1988 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 10 16:59:59 1988 UT = Sun Sep 11 01:59:59 1988 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 10 17:00:00 1988 UT = Sun Sep 11 01:00:00 1988 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 15 17:59:59 1989 UT = Sun Apr 16 01:59:59 1989 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 15 18:00:00 1989 UT = Sun Apr 16 03:00:00 1989 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 16 16:59:59 1989 UT = Sun Sep 17 01:59:59 1989 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 16 17:00:00 1989 UT = Sun Sep 17 01:00:00 1989 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 14 17:59:59 1990 UT = Sun Apr 15 01:59:59 1990 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 14 18:00:00 1990 UT = Sun Apr 15 03:00:00 1990 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 15 16:59:59 1990 UT = Sun Sep 16 01:59:59 1990 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 15 17:00:00 1990 UT = Sun Sep 16 01:00:00 1990 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 13 17:59:59 1991 UT = Sun Apr 14 01:59:59 1991 CST isdst=0 gmtoff=28800
Etc/UTC  Sat Apr 13 18:00:00 1991 UT = Sun Apr 14 03:00:00 1991 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 14 16:59:59 1991 UT = Sun Sep 15 01:59:59 1991 CDT isdst=1 gmtoff=32400
Etc/UTC  Sat Sep 14 17:00:00 1991 UT = Sun Sep 15 01:00:00 1991 CST isdst=0 gmtoff=28800

The Ubuntu 24.04 is the same.

@mordante
Copy link
Member Author

mordante commented May 9, 2024

Thanks. This looks really odd. UTC should not have any changes. This looks like UTC has daylight-saving time. This is especially odd since the libc++ CI also uses Ubuntu 22.04.

Just to be clear, this is the output of zdump. Is that correct?

@yingcong-wu
Copy link
Contributor

yingcong-wu commented May 10, 2024

Just to be clear, this is the output of zdump. Is that correct?

Yes, those are the output of zdump -V -c1800,2100 Etc/UTC.

But it is weird that I use another Ubuntu 22.04 that has the same tzdata.zi with zdump (Ubuntu GLIBC 2.35-0ubuntu3.7) 2.35, but zdump -V -c1800,2100 Etc/UTC returns empty in that environment.

Could that be related to kernel? This one with non-empty output is running on a container with 5.14.0-70.13.1.el9_0.x86_64; while the one with empty output is running with native Ubuntu with 5.15.0-106-generic.

@mordante
Copy link
Member Author

I don't see how this can be related to the kernel. There might be a different software package that affects the result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants