Skip to content

Commit edac504

Browse files
committed
[libc++][TZDB] Finishes zoned_time constructors.
Completes - LWG3225 zoned_time converting constructor shall not be noexcept - LWG3226 zoned_time constructor from string_view should accept zoned_time<Duration2, TimeZonePtr2> Implements parts of: - P0355 Extending to chrono Calendars and Time Zones
1 parent d0b2016 commit edac504

14 files changed

+1307
-5
lines changed

libcxx/docs/Status/Cxx20Issues.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@
162162
"`3209 <https://wg21.link/LWG3209>`__","Expression in ``year::ok()``\ returns clause is ill-formed","Cologne","|Complete|",""
163163
"","","","","",""
164164
"`3231 <https://wg21.link/LWG3231>`__","``year_month_day_last::day``\ specification does not cover ``!ok()``\ values","Belfast","|Nothing To Do|",""
165-
"`3225 <https://wg21.link/LWG3225>`__","``zoned_time``\ converting constructor shall not be ``noexcept``\ ","Belfast","","","|chrono|"
165+
"`3225 <https://wg21.link/LWG3225>`__","``zoned_time``\ converting constructor shall not be ``noexcept``\ ","Belfast","|Complete|","19.0","|chrono|"
166166
"`3190 <https://wg21.link/LWG3190>`__","``std::allocator::allocate``\ sometimes returns too little storage","Belfast","|Complete|","14.0"
167167
"`3218 <https://wg21.link/LWG3218>`__","Modifier for ``%d``\ parse flag does not match POSIX and ``format``\ specification","Belfast","","","|chrono| |format|"
168168
"`3224 <https://wg21.link/LWG3224>`__","``zoned_time``\ constructor from ``TimeZonePtr``\ does not specify initialization of ``tp_``\ ","Belfast","|Complete|","19.0","|chrono|"
@@ -199,7 +199,7 @@
199199
"`3194 <https://wg21.link/LWG3194>`__","``ConvertibleTo``\ prose does not match code","Prague","|Complete|","13.0"
200200
"`3200 <https://wg21.link/LWG3200>`__","``midpoint``\ should not constrain ``T``\ is complete","Prague","|Nothing To Do|",""
201201
"`3201 <https://wg21.link/LWG3201>`__","``lerp``\ should be marked as ``noexcept``\ ","Prague","|Complete|",""
202-
"`3226 <https://wg21.link/LWG3226>`__","``zoned_time``\ constructor from ``string_view``\ should accept ``zoned_time<Duration2, TimeZonePtr2>``\ ","Prague","","","|chrono|"
202+
"`3226 <https://wg21.link/LWG3226>`__","``zoned_time``\ constructor from ``string_view``\ should accept ``zoned_time<Duration2, TimeZonePtr2>``\ ","Prague","|Complete|","19.0","|chrono|"
203203
"`3233 <https://wg21.link/LWG3233>`__","Broken requirements for ``shared_ptr``\ converting constructors","Prague","|Complete|","19.0"
204204
"`3237 <https://wg21.link/LWG3237>`__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","16.0"
205205
"`3238 <https://wg21.link/LWG3238>`__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","|Nothing To Do|",""

libcxx/include/__chrono/zoned_time.h

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// Enable the contents of the header only when libc++ was built with experimental features enabled.
1717
#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
1818

19+
# include <__chrono/calendar.h>
1920
# include <__chrono/duration.h>
2021
# include <__chrono/system_clock.h>
2122
# include <__chrono/time_zone.h>
@@ -56,6 +57,10 @@ class zoned_time {
5657
static_assert(__is_duration<_Duration>::value,
5758
"the program is ill-formed since _Duration is not a specialization of std::chrono::duration");
5859

60+
// There are several constraints like
61+
// constructible_from<zoned_time, decltype(__traits::locate_zone(string_view{}))>
62+
// This would create a dependency on itself. Instead depend on the fact an
63+
// constructor overload taking a _TimeZonePtr is present.
5964
using __traits = zoned_traits<_TimeZonePtr>;
6065

6166
public:
@@ -76,12 +81,71 @@ class zoned_time {
7681

7782
_LIBCPP_HIDE_FROM_ABI explicit zoned_time(string_view __name)
7883
requires(requires { __traits::locate_zone(string_view{}); } &&
79-
// constructible_from<zoned_time, decltype(__traits::locate_zone(string_view{}))>
80-
// would create a dependency on itself. Instead depend on the fact
81-
// a constructor taking a _TimeZonePtr exists.
8284
constructible_from<_TimeZonePtr, decltype(__traits::locate_zone(string_view{}))>)
8385
: __zone_{__traits::locate_zone(__name)}, __tp_{} {}
8486

87+
template <class _Duration2>
88+
_LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& __zt)
89+
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
90+
: __zone_{__zt.get_time_zone()}, __tp_{__zt.get_sys_time()} {}
91+
92+
_LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const sys_time<_Duration>& __tp)
93+
: __zone_{std::move(__zone)}, __tp_{__tp} {}
94+
95+
_LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const sys_time<_Duration>& __tp)
96+
requires requires { _TimeZonePtr{__traits::locate_zone(string_view{})}; }
97+
: zoned_time{__traits::locate_zone(__name), __tp} {}
98+
99+
_LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp)
100+
requires(is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})),
101+
sys_time<duration>>)
102+
: __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp)} {}
103+
104+
_LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp)
105+
requires(requires {
106+
_TimeZonePtr{__traits::locate_zone(string_view{})};
107+
} && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{})),
108+
sys_time<duration>>)
109+
: zoned_time{__traits::locate_zone(__name), __tp} {}
110+
111+
_LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const local_time<_Duration>& __tp, choose __c)
112+
requires(is_convertible_v<
113+
decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)),
114+
sys_time<duration>>)
115+
: __zone_{std::move(__zone)}, __tp_{__zone_->to_sys(__tp, __c)} {}
116+
117+
_LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const local_time<_Duration>& __tp, choose __c)
118+
requires(requires {
119+
_TimeZonePtr{__traits::locate_zone(string_view{})};
120+
} && is_convertible_v<decltype(std::declval<_TimeZonePtr&>() -> to_sys(local_time<_Duration>{}, choose::earliest)),
121+
sys_time<duration>>)
122+
: zoned_time{__traits::locate_zone(__name), __tp, __c} {}
123+
124+
template <class _Duration2, class _TimeZonePtr2>
125+
_LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt)
126+
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
127+
: __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {}
128+
129+
// per wording choose has no effect
130+
template <class _Duration2, class _TimeZonePtr2>
131+
_LIBCPP_HIDE_FROM_ABI zoned_time(_TimeZonePtr __zone, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose)
132+
requires is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>
133+
: __zone_{std::move(__zone)}, __tp_{__zt.get_sys_time()} {}
134+
135+
template <class _Duration2, class _TimeZonePtr2>
136+
_LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt)
137+
requires(requires {
138+
_TimeZonePtr{__traits::locate_zone(string_view{})};
139+
} && is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>)
140+
: zoned_time{__traits::locate_zone(__name), __zt} {}
141+
142+
template <class _Duration2, class _TimeZonePtr2>
143+
_LIBCPP_HIDE_FROM_ABI zoned_time(string_view __name, const zoned_time<_Duration2, _TimeZonePtr2>& __zt, choose __c)
144+
requires(requires {
145+
_TimeZonePtr{__traits::locate_zone(string_view{})};
146+
} && is_convertible_v<sys_time<_Duration2>, sys_time<_Duration>>)
147+
: zoned_time{__traits::locate_zone(__name), __zt, __c} {}
148+
85149
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr get_time_zone() const { return __zone_; }
86150
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<duration> get_sys_time() const { return __tp_; }
87151

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
// template<class Duration, class TimeZonePtr = const time_zone*>
18+
// class zoned_time;
19+
//
20+
// zoned_time(string_view name, const local_time<Duration>& st);
21+
22+
#include <chrono>
23+
#include <concepts>
24+
25+
#include "test_offset_time_zone.h"
26+
27+
// Verify the results of the constructed object.
28+
int main(int, char**) {
29+
{
30+
using ptr = const std::chrono::time_zone*;
31+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
32+
std::string_view,
33+
std::chrono::sys_seconds>);
34+
35+
std::chrono::zoned_time<std::chrono::seconds> zt{"Etc/GMT+1", std::chrono::local_seconds{std::chrono::seconds{0}}};
36+
37+
assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1"));
38+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::hours{1}});
39+
}
40+
41+
{
42+
using ptr = offset_time_zone<offset_time_zone_flags::none>;
43+
static_assert(!std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
44+
std::string_view,
45+
std::chrono::local_seconds>);
46+
}
47+
48+
{
49+
using ptr = offset_time_zone<offset_time_zone_flags::has_default_zone>;
50+
static_assert(!std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
51+
std::string_view,
52+
std::chrono::local_seconds>);
53+
}
54+
55+
{
56+
using ptr = offset_time_zone<offset_time_zone_flags::has_locate_zone>;
57+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
58+
std::string_view,
59+
std::chrono::local_seconds>);
60+
61+
ptr tz;
62+
std::chrono::zoned_time<std::chrono::seconds, ptr> zt{"42", std::chrono::local_seconds{std::chrono::seconds{99}}};
63+
64+
assert(zt.get_time_zone().offset() == std::chrono::seconds{42});
65+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{141}});
66+
}
67+
68+
{
69+
using ptr = offset_time_zone<offset_time_zone_flags::both>;
70+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
71+
std::string_view,
72+
std::chrono::local_seconds>);
73+
74+
ptr tz;
75+
std::chrono::zoned_time<std::chrono::seconds, ptr> zt{"42", std::chrono::local_seconds{std::chrono::seconds{99}}};
76+
77+
assert(zt.get_time_zone().offset() == std::chrono::seconds{42});
78+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{141}});
79+
}
80+
81+
return 0;
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
// template<class Duration, class TimeZonePtr = const time_zone*>
18+
// class zoned_time;
19+
//
20+
// zoned_time(string_view name, const local_time<Duration>& st, choose c);
21+
22+
#include <chrono>
23+
#include <concepts>
24+
#include <cassert>
25+
26+
#include "test_offset_time_zone.h"
27+
28+
int main(int, char**) {
29+
// Tests unique conversions. To make sure the test is does not depend on changes
30+
// in the database it uses a time zone with a fixed offset.
31+
{
32+
std::chrono::zoned_time<std::chrono::seconds> zt{
33+
"Etc/GMT+1", std::chrono::local_seconds{std::chrono::seconds{0}}, std::chrono::choose::earliest};
34+
35+
assert(zt.get_time_zone() == std::chrono::locate_zone("Etc/GMT+1"));
36+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::hours{1}});
37+
}
38+
39+
// Tests ambiguous conversions.
40+
{
41+
// Z Europe/Berlin 0:53:28 - LMT 1893 Ap
42+
// ...
43+
// 1 DE CE%sT 1980
44+
// 1 E CE%sT
45+
//
46+
// ...
47+
// R E 1981 ma - Mar lastSu 1u 1 S
48+
// R E 1996 ma - O lastSu 1u 0 -
49+
50+
using namespace std::literals::chrono_literals;
51+
{
52+
std::chrono::zoned_time<std::chrono::seconds> zt{
53+
"Europe/Berlin",
54+
std::chrono::local_seconds{
55+
(std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h + 30min).time_since_epoch()},
56+
std::chrono::choose::earliest};
57+
58+
assert(zt.get_time_zone() == std::chrono::locate_zone("Europe/Berlin"));
59+
assert(zt.get_sys_time() == std::chrono::sys_days{std::chrono::September / 28 / 1986} + 0h + 30min);
60+
}
61+
{
62+
std::chrono::zoned_time<std::chrono::seconds> zt{
63+
"Europe/Berlin",
64+
std::chrono::local_seconds{
65+
(std::chrono::sys_days{std::chrono::September / 28 / 1986} + 2h + 30min).time_since_epoch()},
66+
std::chrono::choose::latest};
67+
68+
assert(zt.get_time_zone() == std::chrono::locate_zone("Europe/Berlin"));
69+
assert(zt.get_sys_time() == std::chrono::sys_days{std::chrono::September / 28 / 1986} + 1h + 30min);
70+
}
71+
}
72+
73+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, const std::chrono::time_zone*>,
74+
std::string_view,
75+
std::chrono::local_seconds,
76+
std::chrono::choose>);
77+
78+
static_assert(!std::constructible_from<
79+
std::chrono::zoned_time<std::chrono::seconds, offset_time_zone<offset_time_zone_flags::none>>,
80+
std::string_view,
81+
std::chrono::local_seconds,
82+
std::chrono::choose>);
83+
84+
static_assert(
85+
!std::constructible_from<
86+
std::chrono::zoned_time<std::chrono::seconds, offset_time_zone<offset_time_zone_flags::has_default_zone>>,
87+
std::string_view,
88+
std::chrono::local_seconds,
89+
std::chrono::choose>);
90+
91+
static_assert(
92+
!std::constructible_from<
93+
std::chrono::zoned_time<std::chrono::seconds, offset_time_zone<offset_time_zone_flags::has_locate_zone>>,
94+
std::string_view,
95+
std::chrono::local_seconds,
96+
std::chrono::choose>);
97+
98+
static_assert(!std::constructible_from<
99+
std::chrono::zoned_time<std::chrono::seconds, offset_time_zone<offset_time_zone_flags::both>>,
100+
std::string_view,
101+
std::chrono::local_seconds,
102+
std::chrono::choose>);
103+
104+
return 0;
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
// template<class Duration, class TimeZonePtr = const time_zone*>
18+
// class zoned_time;
19+
//
20+
// zoned_time(string_view name, const sys_time<Duration>& st);
21+
22+
#include <chrono>
23+
#include <concepts>
24+
25+
#include "test_offset_time_zone.h"
26+
27+
// Verify the results of the constructed object.
28+
int main(int, char**) {
29+
{
30+
using ptr = const std::chrono::time_zone*;
31+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
32+
std::string_view,
33+
std::chrono::sys_seconds>);
34+
35+
std::chrono::zoned_time<std::chrono::seconds> zt{"UTC", std::chrono::sys_seconds{std::chrono::seconds{99}}};
36+
37+
assert(zt.get_time_zone() == std::chrono::locate_zone("UTC"));
38+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{99}});
39+
}
40+
41+
{
42+
using ptr = offset_time_zone<offset_time_zone_flags::none>;
43+
static_assert(!std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
44+
std::string_view,
45+
std::chrono::sys_seconds>);
46+
}
47+
48+
{
49+
using ptr = offset_time_zone<offset_time_zone_flags::has_default_zone>;
50+
static_assert(!std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
51+
std::string_view,
52+
std::chrono::sys_seconds>);
53+
}
54+
55+
{
56+
using ptr = offset_time_zone<offset_time_zone_flags::has_locate_zone>;
57+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
58+
std::string_view,
59+
std::chrono::sys_seconds>);
60+
61+
ptr tz;
62+
std::chrono::zoned_time<std::chrono::seconds, ptr> zt{"42", std::chrono::sys_seconds{std::chrono::seconds{99}}};
63+
64+
assert(zt.get_time_zone().offset() == std::chrono::seconds{42});
65+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{99}});
66+
}
67+
68+
{
69+
using ptr = offset_time_zone<offset_time_zone_flags::both>;
70+
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>,
71+
std::string_view,
72+
std::chrono::sys_seconds>);
73+
74+
ptr tz;
75+
std::chrono::zoned_time<std::chrono::seconds, ptr> zt{"42", std::chrono::sys_seconds{std::chrono::seconds{99}}};
76+
77+
assert(zt.get_time_zone().offset() == std::chrono::seconds{42});
78+
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{99}});
79+
}
80+
81+
return 0;
82+
}

0 commit comments

Comments
 (0)