Skip to content

Commit

Permalink
[libc++][TZDB] Adds basics of zoned_time class.
Browse files Browse the repository at this point in the history
This implements the class, its non-templated constructors and its getters to
verify the construction.

Completes
- LWG3224 zoned_time constructor from TimeZonePtr does not specify initialization of tp_

Implements parts of:
- P0355 Extending chrono to Calendars and Time Zones
  • Loading branch information
mordante committed Jun 10, 2024
1 parent 151bd7c commit d0b2016
Show file tree
Hide file tree
Showing 16 changed files with 830 additions and 2 deletions.
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx20Issues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
"`3225 <https://wg21.link/LWG3225>`__","``zoned_time``\ converting constructor shall not be ``noexcept``\ ","Belfast","","","|chrono|"
"`3190 <https://wg21.link/LWG3190>`__","``std::allocator::allocate``\ sometimes returns too little storage","Belfast","|Complete|","14.0"
"`3218 <https://wg21.link/LWG3218>`__","Modifier for ``%d``\ parse flag does not match POSIX and ``format``\ specification","Belfast","","","|chrono| |format|"
"`3224 <https://wg21.link/LWG3224>`__","``zoned_time``\ constructor from ``TimeZonePtr``\ does not specify initialization of ``tp_``\ ","Belfast","","","|chrono|"
"`3224 <https://wg21.link/LWG3224>`__","``zoned_time``\ constructor from ``TimeZonePtr``\ does not specify initialization of ``tp_``\ ","Belfast","|Complete|","19.0","|chrono|"
"`3230 <https://wg21.link/LWG3230>`__","Format specifier ``%y/%Y``\ is missing locale alternative versions","Belfast","|Complete|","16.0","|chrono| |format|"
"`3232 <https://wg21.link/LWG3232>`__","Inconsistency in ``zoned_time``\ deduction guides","Belfast","","","|chrono|"
"`3222 <https://wg21.link/LWG3222>`__","P0574R1 introduced preconditions on non-existent parameters","Belfast","",""
Expand Down
49 changes: 49 additions & 0 deletions libcxx/include/__chrono/zoned_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,22 @@
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)

# include <__chrono/duration.h>
# include <__chrono/system_clock.h>
# include <__chrono/time_zone.h>
# include <__chrono/tzdb_list.h>
# include <__config>
# include <__fwd/string_view.h>
# include <__type_traits/common_type.h>
# include <__utility/move.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 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
Expand All @@ -43,13 +50,55 @@ struct zoned_traits<const time_zone*> {
}
};

template <class _Duration, class _TimeZonePtr = const time_zone*>
class zoned_time {
// [time.zone.zonedtime.ctor]/2
static_assert(__is_duration<_Duration>::value,
"the program is ill-formed since _Duration is not a specialization of std::chrono::duration");

using __traits = zoned_traits<_TimeZonePtr>;

public:
using duration = common_type_t<_Duration, seconds>;

_LIBCPP_HIDE_FROM_ABI zoned_time()
requires requires { __traits::default_zone(); }
: __zone_{__traits::default_zone()}, __tp_{} {}

_LIBCPP_HIDE_FROM_ABI zoned_time(const zoned_time&) = default;
_LIBCPP_HIDE_FROM_ABI zoned_time& operator=(const zoned_time&) = default;

_LIBCPP_HIDE_FROM_ABI zoned_time(const sys_time<_Duration>& __tp)
requires requires { __traits::default_zone(); }
: __zone_{__traits::default_zone()}, __tp_{__tp} {}

_LIBCPP_HIDE_FROM_ABI explicit zoned_time(_TimeZonePtr __zone) : __zone_{std::move(__zone)}, __tp_{} {}

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

[[nodiscard]] _LIBCPP_HIDE_FROM_ABI _TimeZonePtr get_time_zone() const { return __zone_; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI sys_time<duration> get_sys_time() const { return __tp_; }

private:
_TimeZonePtr __zone_;
sys_time<duration> __tp_;
};

} // namespace chrono

# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
// && !defined(_LIBCPP_HAS_NO_LOCALIZATION)

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)

#endif // _LIBCPP___CHRONO_ZONED_TIME_H
4 changes: 4 additions & 0 deletions libcxx/include/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,10 @@ strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept;
// [time.zone.zonedtraits], class template zoned_traits
template<class T> struct zoned_traits; // C++20
// [time.zone.zonedtime], class template zoned_time
template<class Duration, class TimeZonePtr = const time_zone*> // C++20
class zoned_time;
// [time.zone.leap], leap second support
class leap_second { // C++20
public:
Expand Down
2 changes: 1 addition & 1 deletion libcxx/modules/std/chrono.inc
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,10 @@ export namespace std {
// [time.zone.zonedtraits], class template zoned_traits
using std::chrono::zoned_traits;

# if 0
// [time.zone.zonedtime], class template zoned_time
using std::chrono::zoned_time;

# if 0
using std::chrono::zoned_seconds;
# endif // if 0

Expand Down
6 changes: 6 additions & 0 deletions libcxx/test/libcxx/diagnostics/chrono.nodiscard.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,10 @@ void test() {
t::default_zone(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
t::locate_zone(""); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}

{
std::chrono::zoned_time<std::chrono::seconds> 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}}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// 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>

// template<class Duration, class TimeZonePtr = const time_zone*>
// class zoned_time;
//
// zoned_time& operator=(const zoned_time&) = default;

#include <cassert>
#include <chrono>

int main(int, char**) {
std::chrono::zoned_time<std::chrono::seconds> zt{std::chrono::sys_seconds{std::chrono::seconds{42}}};
assert(zt.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{42}});

std::chrono::zoned_time<std::chrono::seconds> copy;
copy = zt;
assert(copy.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(copy.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{42}});

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//===----------------------------------------------------------------------===//
//
// 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>

// template<class Duration, class TimeZonePtr = const time_zone*>
// class zoned_time;
//
// zoned_time(const zoned_time&) = default;

#include <cassert>
#include <chrono>

int main(int, char**) {
std::chrono::zoned_time<std::chrono::seconds> zt{std::chrono::sys_seconds{std::chrono::seconds{42}}};
assert(zt.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(zt.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{42}});

{
std::chrono::zoned_time<std::chrono::seconds> copy{zt};
assert(copy.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(copy.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{42}});
}

{
std::chrono::zoned_time<std::chrono::seconds> copy = zt;
assert(copy.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(copy.get_sys_time() == std::chrono::sys_seconds{std::chrono::seconds{42}});
}

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===----------------------------------------------------------------------===//
//
// 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>

// template<class Duration, class TimeZonePtr = const time_zone*>
// class zoned_time;
//
// zoned_time();

#include <chrono>
#include <concepts>
#include <type_traits>

#include "test_offset_time_zone.h"

// Verify the results of the default constructed object,
// and whether the constructor's constrains are satisfied.
int main(int, char**) {
{
static_assert(std::default_initializable<std::chrono::zoned_time<std::chrono::seconds>>);
std::chrono::zoned_time<std::chrono::seconds> zt;
assert(zt.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(zt.get_sys_time() == std::chrono::sys_seconds{});
}

static_assert(!std::default_initializable<
std::chrono::zoned_time<std::chrono::seconds, offset_time_zone<offset_time_zone_flags::none>>>);

{
using type = offset_time_zone<offset_time_zone_flags::has_default_zone>;
static_assert(std::default_initializable<std::chrono::zoned_time<std::chrono::seconds, type>>);

std::chrono::zoned_time<std::chrono::seconds, type> zt;

assert(zt.get_time_zone().offset() == std::chrono::seconds{0});
assert(zt.get_sys_time() == std::chrono::sys_seconds{});
}

static_assert(
!std::default_initializable<
std::chrono::zoned_time<std::chrono::seconds, offset_time_zone<offset_time_zone_flags::has_locate_zone>>>);

{
using type = offset_time_zone<offset_time_zone_flags::both>;
static_assert(std::default_initializable<std::chrono::zoned_time<std::chrono::seconds, type>>);

std::chrono::zoned_time<std::chrono::seconds, type> zt;

assert(zt.get_time_zone().offset() == std::chrono::seconds{0});
assert(zt.get_sys_time() == std::chrono::sys_seconds{});
}

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// 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>

// template<class Duration, class TimeZonePtr = const time_zone*>
// class zoned_time;
//
// explicit zoned_time(string_view name);

#include <chrono>
#include <concepts>

#include "test_offset_time_zone.h"

// Verify the results of the constructed object.
int main(int, char**) {
{
using ptr = const std::chrono::time_zone*;
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>, std::string_view>);
static_assert(!std::convertible_to<std::string_view, std::chrono::zoned_time<std::chrono::seconds, ptr>>);

std::chrono::zoned_time<std::chrono::seconds> zt{"UTC"};

assert(zt.get_time_zone() == std::chrono::locate_zone("UTC"));
assert(zt.get_sys_time() == std::chrono::sys_seconds{});
}

{
using ptr = offset_time_zone<offset_time_zone_flags::none>;
static_assert(!std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>, std::string_view>);
static_assert(!std::convertible_to<std::string_view, std::chrono::zoned_time<std::chrono::seconds, ptr>>);
}

{
using ptr = offset_time_zone<offset_time_zone_flags::has_default_zone>;
static_assert(!std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>, std::string_view>);
static_assert(!std::convertible_to<std::string_view, std::chrono::zoned_time<std::chrono::seconds, ptr>>);
}

{
using ptr = offset_time_zone<offset_time_zone_flags::has_locate_zone>;
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>, std::string_view>);
static_assert(!std::convertible_to<std::string_view, std::chrono::zoned_time<std::chrono::seconds, ptr>>);

ptr tz;
std::chrono::zoned_time<std::chrono::seconds, ptr> zt{"42"};

assert(zt.get_time_zone().offset() == std::chrono::seconds{42});
assert(zt.get_sys_time() == std::chrono::sys_seconds{});
}

{
using ptr = offset_time_zone<offset_time_zone_flags::both>;
static_assert(std::constructible_from<std::chrono::zoned_time<std::chrono::seconds, ptr>, std::string_view>);
static_assert(!std::convertible_to<std::string_view, std::chrono::zoned_time<std::chrono::seconds, ptr>>);

ptr tz;
std::chrono::zoned_time<std::chrono::seconds, ptr> zt{"42"};

assert(zt.get_time_zone().offset() == std::chrono::seconds{42});
assert(zt.get_sys_time() == std::chrono::sys_seconds{});
}

return 0;
}
Loading

0 comments on commit d0b2016

Please sign in to comment.