Skip to content

[libc++][TZDB] Implements time_zone::to_local. #91003

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

Merged
merged 1 commit into from
Jun 10, 2024

Conversation

mordante
Copy link
Member

@mordante mordante commented May 3, 2024

Implements parts of:

  • P0355 Extending chrono to Calendars and Time Zones

@mordante mordante requested a review from a team as a code owner May 3, 2024 20:04
@mordante mordante force-pushed the users/mordante/time_zone__to_sys_choose branch from 775f545 to 7265479 Compare June 9, 2024 22:38
Base automatically changed from users/mordante/time_zone__to_sys_choose to main June 10, 2024 06:40
Implements parts of:
- P0355 Extending chrono to Calendars and Time Zones
@mordante mordante force-pushed the users/mordante/time_zone__to_local branch from 5f205f7 to 33deefa Compare June 10, 2024 06:41
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jun 10, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 10, 2024

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

Implements parts of:

  • P0355 Extending chrono to Calendars and Time Zones

Full diff: https://github.com/llvm/llvm-project/pull/91003.diff

4 Files Affected:

  • (modified) libcxx/include/__chrono/time_zone.h (+18)
  • (modified) libcxx/include/chrono (+4)
  • (added) libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/assert.to_local.pass.cpp (+40)
  • (added) libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_local.pass.cpp (+68)
diff --git a/libcxx/include/__chrono/time_zone.h b/libcxx/include/__chrono/time_zone.h
index 89ab6d1f21102..de11dac1eef0c 100644
--- a/libcxx/include/__chrono/time_zone.h
+++ b/libcxx/include/__chrono/time_zone.h
@@ -129,6 +129,24 @@ class _LIBCPP_AVAILABILITY_TZDB time_zone {
     return {};
   }
 
+  template <class _Duration>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time<common_type_t<_Duration, seconds>>
+  to_local(const sys_time<_Duration>& __time) const {
+    using _Dp = common_type_t<_Duration, seconds>;
+
+    sys_info __info = get_info(__time);
+
+    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
+        __info.offset >= chrono::seconds{0} || __time.time_since_epoch() >= _Dp::min() - __info.offset,
+        "cannot convert the system time; it would be before the minimum local clock value");
+
+    _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
+        __info.offset <= chrono::seconds{0} || __time.time_since_epoch() <= _Dp::max() - __info.offset,
+        "cannot convert the system time; it would be after the maximum local clock value");
+
+    return local_time<_Dp>{__time.time_since_epoch() + __info.offset};
+  }
+
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; }
 
 private:
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index 78e885f6ca373..4d47dc57ba654 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -778,6 +778,10 @@ class time_zone {
   template<class Duration>
   sys_time<common_type_t<Duration, seconds>>
     to_sys(const local_time<Duration>& tp, choose z) const;
+
+  template<class Duration>
+  local_time<common_type_t<Duration, seconds>>
+    to_local(const sys_time<Duration>& tp) 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
diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/assert.to_local.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/assert.to_local.pass.cpp
new file mode 100644
index 0000000000000..d9ca1c80751cc
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/assert.to_local.pass.cpp
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// REQUIRES: has-unix-headers
+// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// template <class _Duration>
+// local_time<common_type_t<Duration, seconds>>
+//   to_local(const sys_time<Duration>& tp) const;
+
+#include <chrono>
+
+#include "check_assertion.h"
+
+// Tests values that cannot be converted. To make sure the test is does not depend on changes
+// in the database it uses a time zone with a fixed offset.
+int main(int, char**) {
+  TEST_LIBCPP_ASSERT_FAILURE(std::chrono::locate_zone("Etc/GMT+1")->to_local(std::chrono::sys_seconds::min()),
+                             "cannot convert the system time; it would be before the minimum local clock value");
+
+  // TODO TZDB look why std::chrono::sys_seconds::max()  fails
+  TEST_LIBCPP_ASSERT_FAILURE(
+      std::chrono::locate_zone("Etc/GMT-1")->to_local(std::chrono::sys_seconds::max() - std::chrono::seconds(1)),
+      "cannot convert the system time; it would be after the maximum local clock value");
+
+  return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_local.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_local.pass.cpp
new file mode 100644
index 0000000000000..28d61455710cb
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/to_local.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-experimental-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class time_zone;
+
+// template <class _Duration>
+// local_time<common_type_t<Duration, seconds>>
+//   to_local(const sys_time<Duration>& tp) const;
+
+#include <chrono>
+#include <format>
+#include <cassert>
+#include <string_view>
+
+#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+int main(int, char**) {
+  // To make sure the test does not depend on changes in the database it uses a
+  // time zone with a fixed offset.
+  using namespace std::literals::chrono_literals;
+
+  const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1");
+
+  assert(tz->to_local(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
+         std::chrono::local_time<std::chrono::nanoseconds>{-1ns - 1h});
+
+  assert(tz->to_local(std::chrono::sys_time<std::chrono::microseconds>{0us}) ==
+         std::chrono::local_time<std::chrono::microseconds>{0us - 1h});
+
+  assert(tz->to_local(
+             std::chrono::sys_time<std::chrono::seconds>{std::chrono::sys_days{std::chrono::January / 1 / -21970}}) ==
+         std::chrono::local_time<std::chrono::seconds>{
+             (std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch() - 1h});
+
+  assert(
+      tz->to_local(std::chrono::sys_time<std::chrono::days>{std::chrono::sys_days{std::chrono::January / 1 / 21970}}) ==
+      std::chrono::local_time<std::chrono::seconds>{
+          (std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch() - 1h});
+
+  assert(tz->to_local(std::chrono::sys_time<std::chrono::weeks>{}) ==
+         std::chrono::local_time<std::chrono::seconds>{
+             (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() - 1h});
+
+  assert(tz->to_local(std::chrono::sys_time<std::chrono::months>{}) ==
+         std::chrono::local_time<std::chrono::seconds>{
+             (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() - 1h});
+
+  assert(tz->to_local(std::chrono::sys_time<std::chrono::years>{}) ==
+         std::chrono::local_time<std::chrono::seconds>{
+             (std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() - 1h});
+
+  return 0;
+}

@mordante mordante merged commit da03175 into main Jun 10, 2024
54 of 55 checks passed
@mordante mordante deleted the users/mordante/time_zone__to_local branch June 10, 2024 10:40
@HerrCai0907 HerrCai0907 mentioned this pull request Jun 13, 2024
fmayer added a commit to fmayer/llvm-project that referenced this pull request Sep 13, 2024
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.

3 participants