Skip to content

Commit 33deefa

Browse files
committed
[libc++][TZDB] Implements time_zone::to_local.
Implements parts of: - P0355 Extending chrono to Calendars and Time Zones
1 parent 87cedbe commit 33deefa

File tree

4 files changed

+130
-0
lines changed

4 files changed

+130
-0
lines changed

libcxx/include/__chrono/time_zone.h

+18
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,24 @@ class _LIBCPP_AVAILABILITY_TZDB time_zone {
129129
return {};
130130
}
131131

132+
template <class _Duration>
133+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI local_time<common_type_t<_Duration, seconds>>
134+
to_local(const sys_time<_Duration>& __time) const {
135+
using _Dp = common_type_t<_Duration, seconds>;
136+
137+
sys_info __info = get_info(__time);
138+
139+
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
140+
__info.offset >= chrono::seconds{0} || __time.time_since_epoch() >= _Dp::min() - __info.offset,
141+
"cannot convert the system time; it would be before the minimum local clock value");
142+
143+
_LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
144+
__info.offset <= chrono::seconds{0} || __time.time_since_epoch() <= _Dp::max() - __info.offset,
145+
"cannot convert the system time; it would be after the maximum local clock value");
146+
147+
return local_time<_Dp>{__time.time_since_epoch() + __info.offset};
148+
}
149+
132150
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; }
133151

134152
private:

libcxx/include/chrono

+4
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,10 @@ class time_zone {
778778
template<class Duration>
779779
sys_time<common_type_t<Duration, seconds>>
780780
to_sys(const local_time<Duration>& tp, choose z) const;
781+
782+
template<class Duration>
783+
local_time<common_type_t<Duration, seconds>>
784+
to_local(const sys_time<Duration>& tp) const;
781785
};
782786
bool operator==(const time_zone& x, const time_zone& y) noexcept; // C++20
783787
strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept; // C++20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
11+
// REQUIRES: has-unix-headers
12+
// REQUIRES: libcpp-hardening-mode={{extensive|debug}}
13+
// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
14+
15+
// XFAIL: libcpp-has-no-experimental-tzdb
16+
// XFAIL: availability-tzdb-missing
17+
18+
// <chrono>
19+
20+
// template <class _Duration>
21+
// local_time<common_type_t<Duration, seconds>>
22+
// to_local(const sys_time<Duration>& tp) const;
23+
24+
#include <chrono>
25+
26+
#include "check_assertion.h"
27+
28+
// Tests values that cannot be converted. To make sure the test is does not depend on changes
29+
// in the database it uses a time zone with a fixed offset.
30+
int main(int, char**) {
31+
TEST_LIBCPP_ASSERT_FAILURE(std::chrono::locate_zone("Etc/GMT+1")->to_local(std::chrono::sys_seconds::min()),
32+
"cannot convert the system time; it would be before the minimum local clock value");
33+
34+
// TODO TZDB look why std::chrono::sys_seconds::max() fails
35+
TEST_LIBCPP_ASSERT_FAILURE(
36+
std::chrono::locate_zone("Etc/GMT-1")->to_local(std::chrono::sys_seconds::max() - std::chrono::seconds(1)),
37+
"cannot convert the system time; it would be after the maximum local clock value");
38+
39+
return 0;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14, c++17
10+
// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
11+
12+
// XFAIL: libcpp-has-no-experimental-tzdb
13+
// XFAIL: availability-tzdb-missing
14+
15+
// <chrono>
16+
17+
// class time_zone;
18+
19+
// template <class _Duration>
20+
// local_time<common_type_t<Duration, seconds>>
21+
// to_local(const sys_time<Duration>& tp) const;
22+
23+
#include <chrono>
24+
#include <format>
25+
#include <cassert>
26+
#include <string_view>
27+
28+
#include "test_macros.h"
29+
#include "assert_macros.h"
30+
#include "concat_macros.h"
31+
32+
int main(int, char**) {
33+
// To make sure the test does not depend on changes in the database it uses a
34+
// time zone with a fixed offset.
35+
using namespace std::literals::chrono_literals;
36+
37+
const std::chrono::time_zone* tz = std::chrono::locate_zone("Etc/GMT+1");
38+
39+
assert(tz->to_local(std::chrono::sys_time<std::chrono::nanoseconds>{-1ns}) ==
40+
std::chrono::local_time<std::chrono::nanoseconds>{-1ns - 1h});
41+
42+
assert(tz->to_local(std::chrono::sys_time<std::chrono::microseconds>{0us}) ==
43+
std::chrono::local_time<std::chrono::microseconds>{0us - 1h});
44+
45+
assert(tz->to_local(
46+
std::chrono::sys_time<std::chrono::seconds>{std::chrono::sys_days{std::chrono::January / 1 / -21970}}) ==
47+
std::chrono::local_time<std::chrono::seconds>{
48+
(std::chrono::sys_days{std::chrono::January / 1 / -21970}).time_since_epoch() - 1h});
49+
50+
assert(
51+
tz->to_local(std::chrono::sys_time<std::chrono::days>{std::chrono::sys_days{std::chrono::January / 1 / 21970}}) ==
52+
std::chrono::local_time<std::chrono::seconds>{
53+
(std::chrono::sys_days{std::chrono::January / 1 / 21970}).time_since_epoch() - 1h});
54+
55+
assert(tz->to_local(std::chrono::sys_time<std::chrono::weeks>{}) ==
56+
std::chrono::local_time<std::chrono::seconds>{
57+
(std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() - 1h});
58+
59+
assert(tz->to_local(std::chrono::sys_time<std::chrono::months>{}) ==
60+
std::chrono::local_time<std::chrono::seconds>{
61+
(std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() - 1h});
62+
63+
assert(tz->to_local(std::chrono::sys_time<std::chrono::years>{}) ==
64+
std::chrono::local_time<std::chrono::seconds>{
65+
(std::chrono::sys_days{std::chrono::January / 1 / 1970}).time_since_epoch() - 1h});
66+
67+
return 0;
68+
}

0 commit comments

Comments
 (0)