From ad83e31016100fede20971e7ac16dbdd8137504d Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Wed, 17 Apr 2024 21:00:22 +0200 Subject: [PATCH] [libc++][TZDB] Finishes zoned_time member functions. Note the implementation of zoned_time& operator=(const local_time& lt); is not correct; however the wording cannot be easily implemented. It could be if the object caches the local_time assigned. However this does not seem to intended. The current implementation matches MSVC STL and libstdc++. Implements parts of: - P0355 Extending to chrono Calendars and Time Zones --- libcxx/include/__chrono/zoned_time.h | 22 ++ .../diagnostics/chrono.nodiscard.verify.cpp | 12 +- .../assign.local_time.pass.cpp | 245 ++++++++++++++++++ .../assign.sys_time.pass.cpp | 134 ++++++++++ .../get_info.pass.cpp | 49 ++++ .../get_local_time.pass.cpp | 131 ++++++++++ .../operator_local_time.pass.cpp | 133 ++++++++++ .../operator_sys_time.pass.cpp | 123 +++++++++ 8 files changed, 847 insertions(+), 2 deletions(-) create mode 100644 libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.local_time.pass.cpp create mode 100644 libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.sys_time.pass.cpp create mode 100644 libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_info.pass.cpp create mode 100644 libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_local_time.pass.cpp create mode 100644 libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_local_time.pass.cpp create mode 100644 libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_sys_time.pass.cpp diff --git a/libcxx/include/__chrono/zoned_time.h b/libcxx/include/__chrono/zoned_time.h index bf8e04b6407ef9..169efb8e9d6f37 100644 --- a/libcxx/include/__chrono/zoned_time.h +++ b/libcxx/include/__chrono/zoned_time.h @@ -18,6 +18,7 @@ # include <__chrono/calendar.h> # include <__chrono/duration.h> +# include <__chrono/sys_info.h> # include <__chrono/system_clock.h> # include <__chrono/time_zone.h> # include <__chrono/tzdb_list.h> @@ -146,8 +147,29 @@ class zoned_time { } && is_convertible_v, sys_time<_Duration>>) : zoned_time{__traits::locate_zone(__name), __zt, __c} {} + _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const sys_time<_Duration>& __tp) { + __tp_ = __tp; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const local_time<_Duration>& __tp) { + // TODO TZDB This seems wrong. + // Assigning a non-existant or abiguous time will throw and not satisfy + // the post condition. This seems quite odd; I constructed an object with + // choose::earliest and that choice is not respected. + // what did LEWG do with this. + // MSVC STL and libstdc++ behave the same + __tp_ = __zone_->to_sys(__tp); + return *this; + } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI operator sys_time() const { return get_sys_time(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI explicit operator local_time() const { return get_local_time(); } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr get_time_zone() const { return __zone_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time get_local_time() const { return __zone_->to_local(__tp_); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time get_sys_time() const { return __tp_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_info get_info() const { return __zone_->get_info(__tp_); } private: _TimeZonePtr __zone_; diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp index e8337cb33822e9..32a67dc4dc9c48 100644 --- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp @@ -81,7 +81,15 @@ void test() { { std::chrono::zoned_time zt; - zt.get_time_zone(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} - zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + static_cast(zt); + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + static_cast(zt); + + zt.get_time_zone(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + zt.get_local_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + zt.get_sys_time(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + zt.get_info(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} } } diff --git a/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.local_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.local_time.pass.cpp new file mode 100644 index 00000000000000..e5f2e5d92e71a3 --- /dev/null +++ b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.local_time.pass.cpp @@ -0,0 +1,245 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class zoned_time; +// +// zoned_time& operator=(const local_time& st); + +// TODO TZDB Investigate the issues in this test, this seems like +// a design issue of the class. +// +// [time.zone.zonedtime.members]/3 +// Effects: After assignment, get_local_time() == lt. +// This assignment has no effect on the return value of get_time_zone(). +// +// The test cases describe the issues. + +#include +#include +#include +#include + +// Tests unique conversions. To make sure the test is does not depend on changes +// in the database it uses a time zone with a fixed offset. +static void test_unique() { + // common_type_t -> duration + { + using duration = std::chrono::nanoseconds; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{42}}); + assert(zt.get_local_time() == local_time_point{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == local_time_point{duration{99}}); + } + { + using duration = std::chrono::microseconds; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{42}}); + assert(zt.get_local_time() == local_time_point{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == local_time_point{duration{99}}); + } + { + using duration = std::chrono::milliseconds; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{42}}); + assert(zt.get_local_time() == local_time_point{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == local_time_point{duration{99}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::seconds; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{42}}); + assert(zt.get_local_time() == local_time_point{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == sys_time_point{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == local_time_point{duration{99}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::days; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == std::chrono::sys_seconds{duration{42}}); + assert(zt.get_local_time() == std::chrono::local_seconds{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == std::chrono::sys_seconds{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == std::chrono::local_seconds{duration{99}}); + } + { + using duration = std::chrono::weeks; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == std::chrono::sys_seconds{duration{42}}); + assert(zt.get_local_time() == std::chrono::local_seconds{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == std::chrono::sys_seconds{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == std::chrono::local_seconds{duration{99}}); + } + /* This does not work; due to using __tp_ = __zone_->to_sys(__tp); + * Here the ambiguous/non-existent exception can't stream months and years, + * leading to a compilation error. + { + using duration = std::chrono::months; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{"Etc/GMT+1", sys_time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == std::chrono::sys_seconds{duration{42}}); + assert(zt.get_local_time() == std::chrono::local_seconds{duration{42} - std::chrono::hours{1}}); + + std::same_as decltype(auto) _ = zt = local_time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1")); + assert(zt.get_sys_time() == std::chrono::sys_seconds{duration{99} + std::chrono::hours{1}}); + assert(zt.get_local_time() == std::chrono::local_seconds{duration{99}}); + } */ +} + +// Tests non-existant conversions. +static void test_nonexistent() { + using namespace std::literals::chrono_literals; + + const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin"); + + // Z Europe/Berlin 0:53:28 - LMT 1893 Ap + // ... + // 1 DE CE%sT 1980 + // 1 E CE%sT + // + // ... + // R E 1981 ma - Mar lastSu 1u 1 S + // R E 1996 ma - O lastSu 1u 0 - + + // Pick an historic date where it's well known what the time zone rules were. + // This makes it unlikely updates to the database change these rules. + std::chrono::local_time time{ + (std::chrono::sys_days{std::chrono::March / 30 / 1986} + 2h + 30min).time_since_epoch()}; + + using duration = std::chrono::seconds; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{tz}; + +#ifndef TEST_NOEXCEPT + bool thrown = false; + try { + std::same_as decltype(auto) _ = zt = time; + } catch (const std::chrono::nonexistent_local_time&) { + thrown = true; + } + // There is no system type that can represent the current local time. So the + // assertion passes. The current implementation throws an exception too. + assert(zt.get_local_time() != time); + assert(thrown); +#endif +} + +// Tests ambiguous conversions. +static void test_ambiguous() { + using namespace std::literals::chrono_literals; + + const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin"); + + // Z Europe/Berlin 0:53:28 - LMT 1893 Ap + // ... + // 1 DE CE%sT 1980 + // 1 E CE%sT + // + // ... + // R E 1981 ma - Mar lastSu 1u 1 S + // R E 1996 ma - O lastSu 1u 0 - + + // Pick an historic date where it's well known what the time zone rules were. + // This makes it unlikely updates to the database change these rules. + std::chrono::local_time time{ + (std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h + 30min).time_since_epoch()}; + + using duration = std::chrono::seconds; + using sys_time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{tz}; + +#ifndef TEST_NOEXCEPT + bool thrown = false; + try { + std::same_as decltype(auto) _ = zt = time; + } catch (const std::chrono::ambiguous_local_time&) { + thrown = true; + } + // There is no system type that can represent the current local time. So the + // assertion passes. The current implementation throws an exception too. + assert(zt.get_local_time() != time); + assert(thrown); +#endif +} + +int main(int, char**) { + test_unique(); + test_nonexistent(); + test_ambiguous(); + + return 0; +} diff --git a/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.sys_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.sys_time.pass.cpp new file mode 100644 index 00000000000000..ab824bce154474 --- /dev/null +++ b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/assign.sys_time.pass.cpp @@ -0,0 +1,134 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class zoned_time; +// +// zoned_time& operator=(const sys_time& st); + +#include +#include +#include +#include + +int main(int, char**) { + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::microseconds; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::milliseconds; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::seconds; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::days; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::weeks; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::months; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + { + using duration = std::chrono::years; + using time_point = std::chrono::sys_time; + using zoned_time = std::chrono::zoned_time; + zoned_time zt{time_point{duration{42}}}; + + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{42}}); + + std::same_as decltype(auto) _ = zt = time_point{duration{99}}; + assert(zt.get_time_zone() == std::chrono::locate_zone("UTC")); + assert(zt.get_sys_time() == time_point{duration{99}}); + } + + return 0; +} diff --git a/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_info.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_info.pass.cpp new file mode 100644 index 00000000000000..2206692aba6161 --- /dev/null +++ b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_info.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class zoned_time; +// +// sys_info get_info() const; + +#include +#include +#include + +int main(int, char**) { + { + std::chrono::zoned_time zt; + + std::same_as decltype(auto) info = zt.get_info(); + assert(info.begin == std::chrono::sys_seconds::min()); + assert(info.end == std::chrono::sys_seconds::max()); + assert(info.offset == std::chrono::seconds{0}); + assert(info.save == std::chrono::minutes{0}); + assert(info.abbrev == "UTC"); + } + { + const std::chrono::zoned_time zt; + + std::same_as decltype(auto) info = zt.get_info(); + assert(info.begin == std::chrono::sys_seconds::min()); + assert(info.end == std::chrono::sys_seconds::max()); + assert(info.offset == std::chrono::seconds{0}); + assert(info.save == std::chrono::minutes{0}); + assert(info.abbrev == "UTC"); + } + + return 0; +} diff --git a/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_local_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_local_time.pass.cpp new file mode 100644 index 00000000000000..bd12e8017a24b8 --- /dev/null +++ b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/get_local_time.pass.cpp @@ -0,0 +1,131 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class zoned_time; +// +// local_time get_local_time() const; + +#include +#include + +#include "test_offset_time_zone.h" + +static void test_const_member() { + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + const std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } +} + +static void test_duration_conversion() { + // common_type_t -> duration + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::microseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::milliseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::seconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::days; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::weeks; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::months; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::years; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = zt.get_local_time(); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } +} + +int main(int, char**) { + test_const_member(); + test_duration_conversion(); + + return 0; +} diff --git a/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_local_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_local_time.pass.cpp new file mode 100644 index 00000000000000..23e3e1a217d6be --- /dev/null +++ b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_local_time.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class zoned_time; +// +// explicit operator local_time() const; + +#include +#include + +#include "test_offset_time_zone.h" + +static void test_const_member() { + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + static_assert(!std::is_convertible_v>); + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + static_assert(!std::is_convertible_v>); + const std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } +} + +static void test_duration_conversion() { + // common_type_t -> duration + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::microseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::milliseconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::seconds; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::days; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::weeks; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::months; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } + { + using duration = std::chrono::years; + using time_point = std::chrono::sys_time; + using local_time_point = std::chrono::local_time; + std::chrono::zoned_time zt{"Etc/GMT+1", time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == local_time_point{duration{42} - std::chrono::hours{1}}); + } +} + +int main(int, char**) { + test_const_member(); + test_duration_conversion(); + + return 0; +} diff --git a/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_sys_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_sys_time.pass.cpp new file mode 100644 index 00000000000000..22f2b5455ec6b8 --- /dev/null +++ b/libcxx/test/std/time/time.zone/time.zone.zonedtime/time.zone.zonedtime.members/operator_sys_time.pass.cpp @@ -0,0 +1,123 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class zoned_time; +// +// operator sys_time() const; + +#include +#include + +#include "test_offset_time_zone.h" + +static void test_const_member() { + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + static_assert(std::is_convertible_v>); + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + static_assert(std::is_convertible_v>); + const std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } +} + +static void test_duration_conversion() { + // common_type_t -> duration + { + using duration = std::chrono::nanoseconds; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + { + using duration = std::chrono::microseconds; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + { + using duration = std::chrono::milliseconds; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::seconds; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + // common_type_t -> seconds + { + using duration = std::chrono::days; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + { + using duration = std::chrono::weeks; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + { + using duration = std::chrono::months; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } + { + using duration = std::chrono::years; + using time_point = std::chrono::sys_time; + std::chrono::zoned_time zt{time_point{duration{42}}}; + + std::same_as decltype(auto) time = static_cast(zt); + assert(time == time_point{duration{42}}); + } +} + +int main(int, char**) { + test_const_member(); + test_duration_conversion(); + + return 0; +}