Skip to content

[libc++][TZDB] Adds local_info formatter. #86256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libcxx/docs/Status/FormatPaper.csv
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::year_month_weekday_last``",,Mark de Wever,|Complete|,16.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::hh_mm_ss<duration<Rep, Period>>``",,Mark de Wever,|Complete|,17.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::sys_info``",,Mark de Wever,|Complete|,19.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_info``",A ``<chrono>`` implementation,Mark de Wever,,
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_info``",,Mark de Wever,|Complete|,19.0
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::zoned_time<Duration, TimeZonePtr>``",A ``<chrono>`` implementation,Mark de Wever,,

"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``"
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ set(files
__chrono/high_resolution_clock.h
__chrono/leap_second.h
__chrono/literals.h
__chrono/local_info.h
__chrono/month.h
__chrono/month_weekday.h
__chrono/monthday.h
Expand Down
3 changes: 3 additions & 0 deletions libcxx/include/__chrono/convert_to_tm.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <__chrono/duration.h>
#include <__chrono/file_clock.h>
#include <__chrono/hh_mm_ss.h>
#include <__chrono/local_info.h>
#include <__chrono/month.h>
#include <__chrono/month_weekday.h>
#include <__chrono/monthday.h>
Expand Down Expand Up @@ -175,6 +176,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) {
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
} else if constexpr (same_as<_ChronoT, chrono::sys_info>) {
// Has no time information.
} else if constexpr (same_as<_ChronoT, chrono::local_info>) {
// Has no time information.
# endif
} else
static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization");
Expand Down
20 changes: 20 additions & 0 deletions libcxx/include/__chrono/formatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <__chrono/duration.h>
#include <__chrono/file_clock.h>
#include <__chrono/hh_mm_ss.h>
#include <__chrono/local_info.h>
#include <__chrono/month.h>
#include <__chrono/month_weekday.h>
#include <__chrono/monthday.h>
Expand Down Expand Up @@ -419,6 +420,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) {
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
else if constexpr (same_as<_Tp, chrono::sys_info>)
return true;
else if constexpr (same_as<_Tp, chrono::local_info>)
return true;
# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
Expand Down Expand Up @@ -463,6 +466,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) {
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
else if constexpr (same_as<_Tp, chrono::sys_info>)
return true;
else if constexpr (same_as<_Tp, chrono::local_info>)
return true;
# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
Expand Down Expand Up @@ -507,6 +512,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) {
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
else if constexpr (same_as<_Tp, chrono::sys_info>)
return true;
else if constexpr (same_as<_Tp, chrono::local_info>)
return true;
# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
Expand Down Expand Up @@ -551,6 +558,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) {
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
else if constexpr (same_as<_Tp, chrono::sys_info>)
return true;
else if constexpr (same_as<_Tp, chrono::local_info>)
return true;
# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
Expand Down Expand Up @@ -893,6 +902,17 @@ struct formatter<chrono::sys_info, _CharT> : public __formatter_chrono<_CharT> {
return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time_zone);
}
};

template <__fmt_char_type _CharT>
struct formatter<chrono::local_info, _CharT> : public __formatter_chrono<_CharT> {
public:
using _Base = __formatter_chrono<_CharT>;

template <class _ParseContext>
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags{});
}
};
# endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)

#endif // if _LIBCPP_STD_VER >= 20
Expand Down
50 changes: 50 additions & 0 deletions libcxx/include/__chrono/local_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// -*- 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_LOCAL_INFO_H
#define _LIBCPP___CHRONO_LOCAL_INFO_H

#include <version>
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)

# include <__chrono/sys_info.h>
# include <__config>

# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
# endif

_LIBCPP_BEGIN_NAMESPACE_STD

# if _LIBCPP_STD_VER >= 20

namespace chrono {

struct local_info {
static constexpr int unique = 0;
static constexpr int nonexistent = 1;
static constexpr int ambiguous = 2;

int result;
sys_info first;
sys_info second;
};

} // namespace chrono

# endif // _LIBCPP_STD_VER >= 20

_LIBCPP_END_NAMESPACE_STD

#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)

#endif // _LIBCPP___CHRONO_LOCAL_INFO_H
22 changes: 22 additions & 0 deletions libcxx/include/__chrono/ostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <__chrono/duration.h>
#include <__chrono/file_clock.h>
#include <__chrono/hh_mm_ss.h>
#include <__chrono/local_info.h>
#include <__chrono/month.h>
#include <__chrono/month_weekday.h>
#include <__chrono/monthday.h>
Expand Down Expand Up @@ -280,6 +281,27 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __info) {
__abbrev);
}

template <class _CharT, class _Traits>
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __info) {
auto __result = [&]() -> basic_string<_CharT> {
switch (__info.result) {
case local_info::unique:
return _LIBCPP_STATICALLY_WIDEN(_CharT, "unique");
case local_info::nonexistent:
return _LIBCPP_STATICALLY_WIDEN(_CharT, "non-existent");
case local_info::ambiguous:
return _LIBCPP_STATICALLY_WIDEN(_CharT, "ambiguous");

default:
return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "unspecified result ({})"), __info.result);
};
};

return __os << std::format(
_LIBCPP_STATICALLY_WIDEN(_CharT, "{}: {{{}, {}}}"), __result(), __info.first, __info.second);
}

# endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)

} // namespace chrono
Expand Down
16 changes: 16 additions & 0 deletions libcxx/include/chrono
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,20 @@ template<class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, const sys_info& si);

struct local_info { // C++20
static constexpr int unique = 0;
static constexpr int nonexistent = 1;
static constexpr int ambiguous = 2;

int result;
sys_info first;
sys_info second;
};

template<class charT, class traits> // C++20
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, const local_info& li);

// 25.10.5, class time_zone // C++20
enum class choose {earliest, latest};
class time_zone {
Expand Down Expand Up @@ -834,6 +848,7 @@ namespace std {
template<class Rep, class Period, class charT>
struct formatter<chrono::hh_mm_ss<duration<Rep, Period>>, charT>; // C++20
template<class charT> struct formatter<chrono::sys_info, charT>; // C++20
template<class charT> struct formatter<chrono::local_info, charT>; // C++20
} // namespace std

namespace chrono {
Expand Down Expand Up @@ -899,6 +914,7 @@ constexpr chrono::year operator ""y(unsigned lo
# include <__chrono/day.h>
# include <__chrono/hh_mm_ss.h>
# include <__chrono/literals.h>
# include <__chrono/local_info.h>
# include <__chrono/month.h>
# include <__chrono/month_weekday.h>
# include <__chrono/monthday.h>
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/libcxx.imp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@
{ include: [ "<__chrono/high_resolution_clock.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/leap_second.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/literals.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/local_info.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/month.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/month_weekday.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/monthday.h>", "private", "<chrono>", "public" ] },
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,7 @@ module std_private_chrono_high_resolution_clock [system] {
}
module std_private_chrono_leap_second [system] { header "__chrono/leap_second.h" }
module std_private_chrono_literals [system] { header "__chrono/literals.h" }
module std_private_chrono_local_info [system] { header "__chrono/local_info.h" }
module std_private_chrono_month [system] { header "__chrono/month.h" }
module std_private_chrono_month_weekday [system] { header "__chrono/month_weekday.h" }
module std_private_chrono_monthday [system] { header "__chrono/monthday.h" }
Expand Down
1 change: 1 addition & 0 deletions libcxx/modules/std/chrono.inc
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export namespace std {
# endif // if 0

// [time.zone.info], information classes
using std::chrono::local_info;
using std::chrono::sys_info;

# if 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//===----------------------------------------------------------------------===//
//
// 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-localization

// TODO FMT This test should not require std::to_chars(floating-point)
// XFAIL: availability-fp_to_chars-missing

// XFAIL: libcpp-has-no-incomplete-tzdb

// <chrono>

// template<class charT, class traits>
// basic_ostream<charT, traits>&
// operator<<(basic_ostream<charT, traits>& os, const local_info& r);

// [time.zone.info.local]
// 7 Effects: Streams out the local_info object r in an unspecified format.
// 8 Returns: os.
//
// Tests the output produced by this function.

#include <cassert>
#include <chrono>
#include <memory>
#include <sstream>

#include "assert_macros.h"
#include "test_macros.h"
#include "make_string.h"
#include "concat_macros.h"

#define SV(S) MAKE_STRING_VIEW(CharT, S)

template <class CharT>
static void test(std::basic_string_view<CharT> expected, std::chrono::local_info&& info) {
std::basic_stringstream<CharT> sstr;
sstr << info;
std::basic_string<CharT> output = sstr.str();

TEST_REQUIRE(expected == output,
TEST_WRITE_CONCATENATED("\nExpected output ", expected, "\nActual output ", output, '\n'));
}

template <class CharT>
static void test() {
using namespace std::literals::chrono_literals;
namespace tz = std::chrono;
// result values matching the "known" results
test(SV("unique: "
"{[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min \"TZ\", "
"[1970-01-01 00:00:00, 1970-01-01 00:00:00) 00:00:00 0min \"\"}"),
tz::local_info{tz::local_info::unique,
tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"},
tz::sys_info{}});

test(SV("non-existent: "
"{[1970-01-01 00:00:00, 2038-12-31 00:00:00) 12:23:45 -67min \"NEG\", "
"[1970-01-01 00:00:00, 2038-12-31 00:00:00) -12:23:45 67min \"POS\"}"),
tz::local_info{
tz::local_info::nonexistent,
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
12h + 23min + 45s,
-67min,
"NEG"},
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
-(12h + 23min + 45s),
67min,
"POS"}});

test(SV("ambiguous: "
"{[1970-01-01 00:00:00, 2038-12-31 00:00:00) 12:23:45 -67min \"NEG\", "
"[1970-01-01 00:00:00, 2038-12-31 00:00:00) -12:23:45 67min \"POS\"}"),
tz::local_info{
tz::local_info::ambiguous,
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
12h + 23min + 45s,
-67min,
"NEG"},
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
-(12h + 23min + 45s),
67min,
"POS"}});

// result values not matching the "known" results
test(
SV("unspecified result (-1): "
"{[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min \"TZ\", "
"[1970-01-01 00:00:00, 1970-01-01 00:00:00) 00:00:00 0min \"\"}"),
tz::local_info{-1, tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"}, tz::sys_info{}});
test(SV("unspecified result (3): "
"{[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min \"TZ\", "
"[1970-01-01 00:00:00, 1970-01-01 00:00:00) 00:00:00 0min \"\"}"),
tz::local_info{3, tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"}, tz::sys_info{}});
}

int main(int, const char**) {
test<char>();
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test<wchar_t>();
#endif

return 0;
}
Loading