[libc++][TZDB] Implements zoned_traits. (#91059)

Implements parts of:
- P0355 Extending chrono to Calendars and Time Zones
This commit is contained in:
Mark de Wever 2024-06-10 17:13:08 +02:00 committed by GitHub
parent cb3ff9a393
commit 151bd7cab4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 182 additions and 2 deletions

View File

@ -277,6 +277,7 @@ set(files
__chrono/year_month.h
__chrono/year_month_day.h
__chrono/year_month_weekday.h
__chrono/zoned_time.h
__compare/common_comparison_category.h
__compare/compare_partial_order_fallback.h
__compare/compare_strong_order_fallback.h

View File

@ -0,0 +1,55 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
#ifndef _LIBCPP___CHRONO_ZONED_TIME_H
#define _LIBCPP___CHRONO_ZONED_TIME_H
#include <version>
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
# include <__chrono/time_zone.h>
# include <__chrono/tzdb_list.h>
# include <__config>
# include <__fwd/string_view.h>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
# endif
_LIBCPP_BEGIN_NAMESPACE_STD
# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
namespace chrono {
template <class>
struct zoned_traits {};
template <>
struct zoned_traits<const time_zone*> {
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* default_zone() { return chrono::locate_zone("UTC"); }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static const time_zone* locate_zone(string_view __name) {
return chrono::locate_zone(__name);
}
};
} // 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
#endif // !defined(_LIBCPP_HAS_NO_EXPERIMENTAL_TZDB)
#endif // _LIBCPP___CHRONO_ZONED_TIME_H

View File

@ -786,6 +786,9 @@ class time_zone {
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
// [time.zone.zonedtraits], class template zoned_traits
template<class T> struct zoned_traits; // C++20
// [time.zone.leap], leap second support
class leap_second { // C++20
public:
@ -959,6 +962,7 @@ constexpr chrono::year operator ""y(unsigned lo
# include <__chrono/time_zone_link.h>
# include <__chrono/tzdb.h>
# include <__chrono/tzdb_list.h>
# include <__chrono/zoned_time.h>
# endif
#endif

View File

@ -1159,6 +1159,7 @@ module std_private_chrono_year [system] { header "__chrono/yea
module std_private_chrono_year_month [system] { header "__chrono/year_month.h" }
module std_private_chrono_year_month_day [system] { header "__chrono/year_month_day.h" }
module std_private_chrono_year_month_weekday [system] { header "__chrono/year_month_weekday.h" }
module std_private_chrono_zoned_time [system] { header "__chrono/zoned_time.h" }
module std_private_compare_common_comparison_category [system] { header "__compare/common_comparison_category.h" }
module std_private_compare_compare_partial_order_fallback [system] { header "__compare/compare_partial_order_fallback.h" }

View File

@ -227,11 +227,10 @@ export namespace std {
using std::chrono::choose;
using std::chrono::time_zone;
# if 0
// [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;

View File

@ -72,4 +72,10 @@ void test() {
leap.date(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
leap.value(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
{
using t = std::chrono::zoned_traits<const std::chrono::time_zone*>;
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}}
}
}

View File

@ -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<> struct zoned_traits<const time_zone*>;
// static const time_zone* default_zone();
#include <chrono>
#include <cassert>
int main(int, char**) {
std::same_as<const std::chrono::time_zone*> decltype(auto) tz =
std::chrono::zoned_traits<const std::chrono::time_zone*>::default_zone();
assert(tz);
// The time zone "UTC" can be a link, this means tz->name() can be something
// differently. For example, "Etc/UTC". Instead validate whether same time
// zone is returned by comparing the addresses.
const std::chrono::time_zone* expected = std::chrono::locate_zone("UTC");
assert(tz == expected);
return 0;
}

View File

@ -0,0 +1,45 @@
//===----------------------------------------------------------------------===//
//
// 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<> struct zoned_traits<const time_zone*>;
// static const time_zone* locate_zone(string_view name);
#include <chrono>
#include <cassert>
#include <concepts>
#include "assert_macros.h"
static void test(std::string_view name) {
std::same_as<const std::chrono::time_zone*> decltype(auto) tz =
std::chrono::zoned_traits<const std::chrono::time_zone*>::locate_zone(name);
const std::chrono::time_zone* expected = std::chrono::locate_zone(name);
assert(tz == expected);
}
int main(int, char**) {
test("UTC");
test("Europe/Berlin");
test("Asia/Hong_Kong");
TEST_THROWS_TYPE(std::runtime_error,
TEST_IGNORE_NODISCARD std::chrono::zoned_traits<const std::chrono::time_zone*>::locate_zone(
"there_is_no_time_zone_with_this_name"));
return 0;
}

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// 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 T> struct zoned_traits {};
//
// A specialization for const time_zone* is provided by the implementation:
// template<> struct zoned_traits<const time_zone*> { ... }
#include <chrono>
#include <type_traits>
// This test test whether non-specialized versions exhibit the expected
// behavior. (Note these specializations are not really useful.)
static_assert(std::is_trivial_v<std::chrono::zoned_traits<int>>);
static_assert(std::is_trivial_v<std::chrono::zoned_traits<float>>);
static_assert(std::is_trivial_v<std::chrono::zoned_traits<void*>>);
struct foo {};
static_assert(std::is_empty_v<std::chrono::zoned_traits<foo>>);
static_assert(std::is_trivial_v<std::chrono::zoned_traits<foo>>);