[libcxx-commits] [libcxx] [libc++][chrono] implements GPS clock. (PR #125921)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Feb 9 06:17:48 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

<details>
<summary>Changes</summary>

Completes:
- LWG3359 <chrono> leap second support should allow for negative leap seconds
- P1361 Integration of chrono with text formatting

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


---

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


18 Files Affected:

- (modified) libcxx/docs/Status/FormatPaper.csv (+1-1) 
- (modified) libcxx/include/CMakeLists.txt (+1) 
- (modified) libcxx/include/__chrono/convert_to_tm.h (+6) 
- (modified) libcxx/include/__chrono/formatter.h (+14) 
- (added) libcxx/include/__chrono/gps_clock.h (+90) 
- (modified) libcxx/include/__chrono/ostream.h (+7) 
- (modified) libcxx/include/chrono (+29) 
- (modified) libcxx/include/module.modulemap (+4) 
- (modified) libcxx/modules/std/chrono.inc (-2) 
- (modified) libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp (+11) 
- (added) libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp (+73) 
- (added) libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp (+73) 
- (added) libcxx/test/std/time/time.clock/time.clock.gps/gps_time.ostream.pass.cpp (+164) 
- (added) libcxx/test/std/time/time.clock/time.clock.gps/time.clock.gps.members/from_utc.pass.cpp (+158) 
- (added) libcxx/test/std/time/time.clock/time.clock.gps/time.clock.gps.members/now.pass.cpp (+33) 
- (added) libcxx/test/std/time/time.clock/time.clock.gps/time.clock.gps.members/to_utc.pass.cpp (+153) 
- (added) libcxx/test/std/time/time.clock/time.clock.gps/types.compile.pass.cpp (+60) 
- (added) libcxx/test/std/time/time.syn/formatter.gps_time.pass.cpp (+990) 


``````````diff
diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv
index beec97b8c01790c..6387b5ac20a3d9a 100644
--- a/libcxx/docs/Status/FormatPaper.csv
+++ b/libcxx/docs/Status/FormatPaper.csv
@@ -4,7 +4,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
 `[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::sys_time<Duration>``",,Mark de Wever,|Complete|,17
 `[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::utc_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,|Complete|,20
 `[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::tai_time<Duration>``",,Mark de Wever,|Complete|,21
-`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",A ``<chrono>`` implementation,Mark de Wever,,,
+`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::gps_time<Duration>``",,Mark de Wever,|Complete|,21
 `[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::file_time<Duration>``",,Mark de Wever,|Complete|,17
 `[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_time<Duration>``",,Mark de Wever,|Complete|,17
 `[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local-time-format-t<Duration>``",,,|Nothing To Do|,
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index ce805b4eb7b8b4f..4aab32a7850db6e 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -256,6 +256,7 @@ set(files
   __chrono/exception.h
   __chrono/file_clock.h
   __chrono/formatter.h
+  __chrono/gps_clock.h
   __chrono/hh_mm_ss.h
   __chrono/high_resolution_clock.h
   __chrono/leap_second.h
diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h
index d9ccf693160d292..0a6b62772609162 100644
--- a/libcxx/include/__chrono/convert_to_tm.h
+++ b/libcxx/include/__chrono/convert_to_tm.h
@@ -15,6 +15,7 @@
 #include <__chrono/day.h>
 #include <__chrono/duration.h>
 #include <__chrono/file_clock.h>
+#include <__chrono/gps_clock.h>
 #include <__chrono/hh_mm_ss.h>
 #include <__chrono/local_info.h>
 #include <__chrono/month.h>
@@ -124,6 +125,11 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::tai_time<_Duration> __tp) {
   return std::__convert_to_tm<_Tm>(chrono::sys_time<_Rp>{__tp.time_since_epoch() - __offset});
 }
 
+template <class _Tm, class _Duration>
+_LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(chrono::gps_time<_Duration> __tp) {
+  return std::__convert_to_tm<_Tm>(chrono::utc_clock::to_sys(chrono::gps_clock::to_utc(__tp)));
+}
+
 #    endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
 #  endif   // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
 
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index 13bcb717291f699..a5caecce8a4f6ce 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -21,6 +21,7 @@
 #  include <__chrono/day.h>
 #  include <__chrono/duration.h>
 #  include <__chrono/file_clock.h>
+#  include <__chrono/gps_clock.h>
 #  include <__chrono/hh_mm_ss.h>
 #  include <__chrono/local_info.h>
 #  include <__chrono/month.h>
@@ -235,6 +236,8 @@ _LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const
 #      if _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
   else if constexpr (__is_time_point<_Tp> && requires { requires same_as<typename _Tp::clock, chrono::tai_clock>; })
     return {"TAI", chrono::seconds{0}};
+  else if constexpr (__is_time_point<_Tp> && requires { requires same_as<typename _Tp::clock, chrono::gps_clock>; })
+    return {"GPS", chrono::seconds{0}};
   else if constexpr (__is_specialization_v<_Tp, chrono::zoned_time>)
     return __formatter::__convert_to_time_zone(__value.get_info());
 #      endif // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
@@ -748,6 +751,17 @@ struct _LIBCPP_TEMPLATE_VIS formatter<chrono::tai_time<_Duration>, _CharT> : pub
   }
 };
 
+template <class _Duration, __fmt_char_type _CharT>
+struct _LIBCPP_TEMPLATE_VIS formatter<chrono::gps_time<_Duration>, _CharT> : public __formatter_chrono<_CharT> {
+public:
+  using _Base _LIBCPP_NODEBUG = __formatter_chrono<_CharT>;
+
+  template <class _ParseContext>
+  _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
+    return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__clock);
+  }
+};
+
 #      endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
 #    endif   // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
 
diff --git a/libcxx/include/__chrono/gps_clock.h b/libcxx/include/__chrono/gps_clock.h
new file mode 100644
index 000000000000000..2e220cab946e368
--- /dev/null
+++ b/libcxx/include/__chrono/gps_clock.h
@@ -0,0 +1,90 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___CHRONO_GPS_CLOCK_H
+#define _LIBCPP___CHRONO_GPS_CLOCK_H
+
+#include <version>
+// Enable the contents of the header only when libc++ was built with experimental features enabled.
+#if _LIBCPP_HAS_EXPERIMENTAL_TZDB
+
+#  include <__assert>
+#  include <__chrono/duration.h>
+#  include <__chrono/time_point.h>
+#  include <__chrono/utc_clock.h>
+#  include <__config>
+#  include <__type_traits/common_type.h>
+
+#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#    pragma GCC system_header
+#  endif
+
+_LIBCPP_PUSH_MACROS
+#  include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#  if _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
+
+namespace chrono {
+
+class gps_clock;
+
+template <class _Duration>
+using gps_time    = time_point<gps_clock, _Duration>;
+using gps_seconds = gps_time<seconds>;
+
+class gps_clock {
+public:
+  using rep                       = utc_clock::rep;
+  using period                    = utc_clock::period;
+  using duration                  = chrono::duration<rep, period>;
+  using time_point                = chrono::time_point<gps_clock>;
+  static constexpr bool is_steady = false; // The utc_clock is not steady.
+
+  // The static difference between UTC and GPS time as specified in the Standard.
+  static constexpr chrono::seconds __offset{315964809};
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static time_point now() { return from_utc(utc_clock::now()); }
+
+  template <class _Duration>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static utc_time<common_type_t<_Duration, seconds>>
+  to_utc(const gps_time<_Duration>& __time) noexcept {
+    using _Rp                    = common_type_t<_Duration, seconds>;
+    _Duration __time_since_epoch = __time.time_since_epoch();
+    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch >= utc_time<_Rp>::min().time_since_epoch() + __offset,
+                                          "the GPS to UTC conversion would underflow");
+
+    return utc_time<_Rp>{__time_since_epoch + __offset};
+  }
+
+  template <class _Duration>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static gps_time<common_type_t<_Duration, seconds>>
+  from_utc(const utc_time<_Duration>& __time) noexcept {
+    using _Rp                    = common_type_t<_Duration, seconds>;
+    _Duration __time_since_epoch = __time.time_since_epoch();
+    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__time_since_epoch <= utc_time<_Rp>::max().time_since_epoch() - __offset,
+                                          "the UTC to GPS conversion would overflow");
+
+    return gps_time<_Rp>{__time_since_epoch - __offset};
+  }
+};
+
+} // namespace chrono
+
+#  endif // _LIBCPP_STD_VER >= 20 && _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM &&
+         // _LIBCPP_HAS_LOCALIZATION
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
+
+#endif // _LIBCPP___CHRONO_GPS_CLOCK_H
diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h
index b8cd6a4680662b0..7a01b186780cb5e 100644
--- a/libcxx/include/__chrono/ostream.h
+++ b/libcxx/include/__chrono/ostream.h
@@ -18,6 +18,7 @@
 #  include <__chrono/day.h>
 #  include <__chrono/duration.h>
 #  include <__chrono/file_clock.h>
+#  include <__chrono/gps_clock.h>
 #  include <__chrono/hh_mm_ss.h>
 #  include <__chrono/local_info.h>
 #  include <__chrono/month.h>
@@ -78,6 +79,12 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const tai_time<_Duration>& __tp
   return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp);
 }
 
+template <class _CharT, class _Traits, class _Duration>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
+operator<<(basic_ostream<_CharT, _Traits>& __os, const gps_time<_Duration>& __tp) {
+  return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%F %T}"), __tp);
+}
+
 #      endif // _LIBCPP_HAS_EXPERIMENTAL_TZDB
 #    endif   // _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM
 
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index bd4c98600440c48..8d4adc80dc1e530 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -363,6 +363,33 @@ template<class charT, class traits, class Duration>     // C++20
   basic_ostream<charT, traits>&
     operator<<(basic_ostream<charT, traits>& os, const tai_time<Duration>& t);
 
+// [time.clock.gps], class gps_clock
+class gps_clock {                                      // C++20
+public:
+    using rep                       = a signed arithmetic type;
+    using period                    = ratio<unspecified, unspecified>;
+    using duration                  = chrono::duration<rep, period>;
+    using time_point                = chrono::time_point<gps_clock>;
+    static constexpr bool is_steady = unspecified;
+
+    static time_point now();
+
+    template<class Duration>
+      static utc_time<common_type_t<Duration, seconds>>
+        to_utc(const gps_time<Duration>& t);
+    template<class Duration>
+      static gps_time<common_type_t<Duration, seconds>>
+        from_utc(const utc_time<Duration>& t);
+};
+
+template<class Duration>
+using gps_time  = time_point<gps_clock, Duration>;      // C++20
+using gps_seconds = gps_time<seconds>;                  // C++20
+
+template<class charT, class traits, class Duration>     // C++20
+  basic_ostream<charT, traits>&
+    operator<<(basic_ostream<charT, traits>& os, const gps_time<Duration>& t);
+
 class file_clock                                        // C++20
 {
 public:
@@ -928,6 +955,8 @@ namespace std {
     struct formatter<chrono::utc_time<Duration>, charT>;                          // C++20
   template<class Duration, class charT>
     struct formatter<chrono::tai_time<Duration>, charT>;                          // C++20
+  template<class Duration, class charT>
+    struct formatter<chrono::gps_time<Duration>, charT>;                          // C++20
   template<class Duration, class charT>
     struct formatter<chrono::filetime<Duration>, charT>;                          // C++20
   template<class Duration, class charT>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index fd39c946b992a43..eb46c2f95e055f8 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -935,6 +935,10 @@ module std [system] {
     module exception                  { header "__chrono/exception.h" }
     module file_clock                 { header "__chrono/file_clock.h" }
     module formatter                  { header "__chrono/formatter.h" }
+    module gps_clock {
+      header "__chrono/gps_clock.h"
+      export std.chrono.time_point
+    }
     module hh_mm_ss                   { header "__chrono/hh_mm_ss.h" }
     module high_resolution_clock {
       header "__chrono/high_resolution_clock.h"
diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc
index 43e8da36e904489..66eccd8d290ad17 100644
--- a/libcxx/modules/std/chrono.inc
+++ b/libcxx/modules/std/chrono.inc
@@ -103,13 +103,11 @@ export namespace std {
     using std::chrono::tai_seconds;
     using std::chrono::tai_time;
 
-#    if 0
     // [time.clock.gps], class gps_clock
     using std::chrono::gps_clock;
 
     using std::chrono::gps_seconds;
     using std::chrono::gps_time;
-#    endif
 #  endif // _LIBCPP_ENABLE_EXPERIMENTAL
 #endif   //  _LIBCPP_HAS_TIME_ZONE_DATABASE && _LIBCPP_HAS_FILESYSTEM && _LIBCPP_HAS_LOCALIZATION
 
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
index bb40e0cfc4e1b8a..4e7380b86399359 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
@@ -113,4 +113,15 @@ void test(std::chrono::time_zone tz, std::chrono::time_zone_link link, std::chro
     // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
     std::chrono::tai_clock::from_utc(std::chrono::utc_seconds{});
   }
+
+  { // [time.clock.gps]
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::gps_clock::now();
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::gps_clock::to_utc(std::chrono::gps_seconds{});
+
+    // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+    std::chrono::gps_clock::from_utc(std::chrono::utc_seconds{});
+  }
 }
diff --git a/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp
new file mode 100644
index 000000000000000..d8200439d973761
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.from_utc.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// REQUIRES: has-unix-headers
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <chrono>
+//
+// class gps_clock;
+
+// static gps_time<common_type_t<_Duration, seconds>>
+// from_utc(const utc_time<_Duration>& t) noexcept;
+
+#include <chrono>
+
+#include "check_assertion.h"
+
+// The function is specified as
+//   gps_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} + 378691210s
+// When t == t.max() there will be a signed integral overflow (other values too).
+int main(int, char**) {
+  using namespace std::literals::chrono_literals;
+  constexpr std::chrono::seconds offset{315964809};
+
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::nanoseconds>::max() - offset);
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::nanoseconds>::max() - offset + 1ns),
+      "the UTC to GPS conversion would overflow");
+
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::microseconds>::max() - offset);
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::microseconds>::max() - offset + 1us),
+      "the UTC to GPS conversion would overflow");
+
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::milliseconds>::max() - offset);
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::milliseconds>::max() - offset + 1ms),
+      "the UTC to GPS conversion would overflow");
+
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_seconds::max() - offset);
+  TEST_LIBCPP_ASSERT_FAILURE(std::chrono::gps_clock::from_utc(std::chrono::utc_seconds::max() - offset + 1s),
+                             "the UTC to GPS conversion would overflow");
+
+  // The conversion uses `common_type_t<Duration, seconds>` so types "larger"
+  // than seconds are converted to seconds. Types "larger" than seconds are
+  // stored in "smaller" intergral and the overflow can never occur.
+
+  // Validate the types can never overflow on all current (and future) supported platforms.
+  static_assert(std::chrono::utc_time<std::chrono::days>::max() <= std::chrono::utc_seconds::max() - offset);
+  static_assert(std::chrono::utc_time<std::chrono::weeks>::max() <= std::chrono::utc_seconds::max() - offset);
+  static_assert(std::chrono::utc_time<std::chrono::months>::max() <= std::chrono::utc_seconds::max() - offset);
+  static_assert(std::chrono::utc_time<std::chrono::years>::max() <= std::chrono::utc_seconds::max() - offset);
+
+  // Validate the run-time conversion works.
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::days>::max());
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::weeks>::max());
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::months>::max());
+  (void)std::chrono::gps_clock::from_utc(std::chrono::utc_time<std::chrono::years>::max());
+
+  return 0;
+}
diff --git a/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp
new file mode 100644
index 000000000000000..d61b3374f661f46
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.clock/time.clock.gps/time.clock.gps.members/assert.to_utc.pass.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++20
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// REQUIRES: has-unix-headers
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <chrono>
+//
+// class gps_clock;
+
+// static utc_time<common_type_t<_Duration, seconds>>
+// to_utc(const gps_time<_Duration>& t) noexcept;
+
+#include <chrono>
+
+#include "check_assertion.h"
+
+// The function is specified as
+//   utc_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} - 378691210s
+// When t == t.min() there will be a signed integral underlow (other values too).
+int main(int, char**) {
+  using namespace std::literals::chrono_literals;
+  constexpr std::chrono::seconds offset{315964809};
+
+  (void)std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::nanoseconds>::min() + offset);
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::nanoseconds>::min() + offset - 1ns),
+      "the GPS to UTC conversion would underflow");
+
+  (void)std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::microseconds>::min() + offset);
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::microseconds>::min() + offset - 1us),
+      "the GPS to UTC conversion would underflow");
+
+  (void)std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::milliseconds>::min() + offset);
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::gps_clock::to_utc(std::chrono::gps_time<std::chrono::milliseconds>::min() + offset - 1ms),
+      "the GPS to UTC conversion would underflow");
+
+  (void)std::chrono::gps_clock::to_utc(s...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/125921


More information about the libcxx-commits mailing list