Skip to content

Commit 42728d0

Browse files
committed
[libc++][TZDB] Adds local_info formatter.
Note the code using a local_info object will be done in a separate commit. Implements parts of: - P0355 Extending to Calendars and Time Zones - P1361 Integration of chrono with text formatting
1 parent 96bc907 commit 42728d0

File tree

14 files changed

+410
-2
lines changed

14 files changed

+410
-2
lines changed

libcxx/docs/Status/FormatPaper.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
2525
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::year_month_weekday_last``",,Mark de Wever,|Complete|,16.0
2626
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::hh_mm_ss<duration<Rep, Period>>``",,Mark de Wever,|Complete|,17.0
2727
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::sys_info``",,Mark de Wever,|Complete|,19.0
28-
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_info``",A ``<chrono>`` implementation,Mark de Wever,,
28+
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::local_info``",,Mark de Wever,|Complete|,19.0
2929
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::zoned_time<Duration, TimeZonePtr>``",A ``<chrono>`` implementation,Mark de Wever,,
3030

3131
"`P2693R1 <https://wg21.link/P2693R1>`__","Formatting ``thread::id`` and ``stacktrace``"

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ set(files
284284
__chrono/high_resolution_clock.h
285285
__chrono/leap_second.h
286286
__chrono/literals.h
287+
__chrono/local_info.h
287288
__chrono/month.h
288289
__chrono/month_weekday.h
289290
__chrono/monthday.h

libcxx/include/__chrono/convert_to_tm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <__chrono/duration.h>
1717
#include <__chrono/file_clock.h>
1818
#include <__chrono/hh_mm_ss.h>
19+
#include <__chrono/local_info.h>
1920
#include <__chrono/month.h>
2021
#include <__chrono/month_weekday.h>
2122
#include <__chrono/monthday.h>
@@ -175,6 +176,8 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) {
175176
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
176177
} else if constexpr (same_as<_ChronoT, chrono::sys_info>) {
177178
// Has no time information.
179+
} else if constexpr (same_as<_ChronoT, chrono::local_info>) {
180+
// Has no time information.
178181
# endif
179182
} else
180183
static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization");

libcxx/include/__chrono/formatter.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <__chrono/duration.h>
1919
#include <__chrono/file_clock.h>
2020
#include <__chrono/hh_mm_ss.h>
21+
#include <__chrono/local_info.h>
2122
#include <__chrono/month.h>
2223
#include <__chrono/month_weekday.h>
2324
#include <__chrono/monthday.h>
@@ -420,6 +421,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) {
420421
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
421422
else if constexpr (same_as<_Tp, chrono::sys_info>)
422423
return true;
424+
else if constexpr (same_as<_Tp, chrono::local_info>)
425+
return true;
423426
# endif
424427
else
425428
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
@@ -464,6 +467,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) {
464467
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
465468
else if constexpr (same_as<_Tp, chrono::sys_info>)
466469
return true;
470+
else if constexpr (same_as<_Tp, chrono::local_info>)
471+
return true;
467472
# endif
468473
else
469474
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
@@ -508,6 +513,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) {
508513
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
509514
else if constexpr (same_as<_Tp, chrono::sys_info>)
510515
return true;
516+
else if constexpr (same_as<_Tp, chrono::local_info>)
517+
return true;
511518
# endif
512519
else
513520
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
@@ -552,6 +559,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) {
552559
# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
553560
else if constexpr (same_as<_Tp, chrono::sys_info>)
554561
return true;
562+
else if constexpr (same_as<_Tp, chrono::local_info>)
563+
return true;
555564
# endif
556565
else
557566
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
@@ -894,6 +903,17 @@ struct formatter<chrono::sys_info, _CharT> : public __formatter_chrono<_CharT> {
894903
return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time_zone);
895904
}
896905
};
906+
907+
template <__fmt_char_type _CharT>
908+
struct formatter<chrono::local_info, _CharT> : public __formatter_chrono<_CharT> {
909+
public:
910+
using _Base = __formatter_chrono<_CharT>;
911+
912+
template <class _ParseContext>
913+
_LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
914+
return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags{});
915+
}
916+
};
897917
# endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
898918

899919
#endif // if _LIBCPP_STD_VER >= 20

libcxx/include/__chrono/local_info.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
11+
12+
#ifndef _LIBCPP___CHRONO_LOCAL_INFO_H
13+
#define _LIBCPP___CHRONO_LOCAL_INFO_H
14+
15+
#include <version>
16+
// Enable the contents of the header only when libc++ was built with experimental features enabled.
17+
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
18+
19+
# include <__chrono/sys_info.h>
20+
# include <__config>
21+
22+
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23+
# pragma GCC system_header
24+
# endif
25+
26+
_LIBCPP_BEGIN_NAMESPACE_STD
27+
28+
# if _LIBCPP_STD_VER >= 20
29+
30+
namespace chrono {
31+
32+
struct local_info {
33+
static constexpr int unique = 0;
34+
static constexpr int nonexistent = 1;
35+
static constexpr int ambiguous = 2;
36+
37+
int result;
38+
sys_info first;
39+
sys_info second;
40+
};
41+
42+
} // namespace chrono
43+
44+
# endif // _LIBCPP_STD_VER >= 20
45+
46+
_LIBCPP_END_NAMESPACE_STD
47+
48+
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
49+
50+
#endif // _LIBCPP___CHRONO_LOCAL_INFO_H

libcxx/include/__chrono/ostream.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <__chrono/duration.h>
1616
#include <__chrono/file_clock.h>
1717
#include <__chrono/hh_mm_ss.h>
18+
#include <__chrono/local_info.h>
1819
#include <__chrono/month.h>
1920
#include <__chrono/month_weekday.h>
2021
#include <__chrono/monthday.h>
@@ -280,6 +281,27 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __info) {
280281
__abbrev);
281282
}
282283

284+
template <class _CharT, class _Traits>
285+
_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
286+
operator<<(basic_ostream<_CharT, _Traits>& __os, const local_info& __info) {
287+
auto __result = [&] -> basic_string<_CharT> {
288+
switch (__info.result) {
289+
case local_info::unique:
290+
return _LIBCPP_STATICALLY_WIDEN(_CharT, "unique");
291+
case local_info::nonexistent:
292+
return _LIBCPP_STATICALLY_WIDEN(_CharT, "non-existent");
293+
case local_info::ambiguous:
294+
return _LIBCPP_STATICALLY_WIDEN(_CharT, "ambiguous");
295+
296+
default:
297+
return std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "unspecified result ({})"), __info.result);
298+
};
299+
};
300+
301+
return __os << std::format(
302+
_LIBCPP_STATICALLY_WIDEN(_CharT, "{}: {{{}, {}}}"), __result(), __info.first, __info.second);
303+
}
304+
283305
# endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
284306

285307
} // namespace chrono

libcxx/include/chrono

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,20 @@ template<class charT, class traits>
737737
basic_ostream<charT, traits>&
738738
operator<<(basic_ostream<charT, traits>& os, const sys_info& si);
739739
740+
struct local_info { // C++20
741+
static constexpr int unique = 0;
742+
static constexpr int nonexistent = 1;
743+
static constexpr int ambiguous = 2;
744+
745+
int result;
746+
sys_info first;
747+
sys_info second;
748+
};
749+
750+
template<class charT, class traits> // C++20
751+
basic_ostream<charT, traits>&
752+
operator<<(basic_ostream<charT, traits>& os, const local_info& li);
753+
740754
// 25.10.5, class time_zone // C++20
741755
enum class choose {earliest, latest};
742756
class time_zone {
@@ -834,6 +848,7 @@ namespace std {
834848
template<class Rep, class Period, class charT>
835849
struct formatter<chrono::hh_mm_ss<duration<Rep, Period>>, charT>; // C++20
836850
template<class charT> struct formatter<chrono::sys_info, charT>; // C++20
851+
template<class charT> struct formatter<chrono::local_info, charT>; // C++20
837852
} // namespace std
838853
839854
namespace chrono {
@@ -894,6 +909,7 @@ constexpr chrono::year operator ""y(unsigned lo
894909
#include <__chrono/hh_mm_ss.h>
895910
#include <__chrono/high_resolution_clock.h>
896911
#include <__chrono/literals.h>
912+
#include <__chrono/local_info.h>
897913
#include <__chrono/month.h>
898914
#include <__chrono/month_weekday.h>
899915
#include <__chrono/monthday.h>

libcxx/include/libcxx.imp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@
281281
{ include: [ "<__chrono/high_resolution_clock.h>", "private", "<chrono>", "public" ] },
282282
{ include: [ "<__chrono/leap_second.h>", "private", "<chrono>", "public" ] },
283283
{ include: [ "<__chrono/literals.h>", "private", "<chrono>", "public" ] },
284+
{ include: [ "<__chrono/local_info.h>", "private", "<chrono>", "public" ] },
284285
{ include: [ "<__chrono/month.h>", "private", "<chrono>", "public" ] },
285286
{ include: [ "<__chrono/month_weekday.h>", "private", "<chrono>", "public" ] },
286287
{ include: [ "<__chrono/monthday.h>", "private", "<chrono>", "public" ] },

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,7 @@ module std_private_chrono_high_resolution_clock [system] {
11471147
}
11481148
module std_private_chrono_leap_second [system] { header "__chrono/leap_second.h" }
11491149
module std_private_chrono_literals [system] { header "__chrono/literals.h" }
1150+
module std_private_chrono_local_info [system] { header "__chrono/local_info.h" }
11501151
module std_private_chrono_month [system] { header "__chrono/month.h" }
11511152
module std_private_chrono_month_weekday [system] { header "__chrono/month_weekday.h" }
11521153
module std_private_chrono_monthday [system] { header "__chrono/monthday.h" }

libcxx/modules/std/chrono.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ export namespace std {
215215
# endif // if 0
216216

217217
// [time.zone.info], information classes
218+
using std::chrono::local_info;
218219
using std::chrono::sys_info;
219220

220221
# if 0
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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-localization
11+
12+
// TODO FMT This test should not require std::to_chars(floating-point)
13+
// XFAIL: availability-fp_to_chars-missing
14+
15+
// XFAIL: libcpp-has-no-incomplete-tzdb
16+
17+
// <chrono>
18+
19+
// template<class charT, class traits>
20+
// basic_ostream<charT, traits>&
21+
// operator<<(basic_ostream<charT, traits>& os, const local_info& r);
22+
23+
// [time.zone.info.local]
24+
// 7 Effects: Streams out the local_info object r in an unspecified format.
25+
// 8 Returns: os.
26+
//
27+
// Tests the output produced by this function.
28+
29+
#include <cassert>
30+
#include <chrono>
31+
#include <memory>
32+
#include <sstream>
33+
34+
#include "assert_macros.h"
35+
#include "test_macros.h"
36+
#include "make_string.h"
37+
#include "concat_macros.h"
38+
39+
#define SV(S) MAKE_STRING_VIEW(CharT, S)
40+
41+
template <class CharT>
42+
static void test(std::basic_string_view<CharT> expected, std::chrono::local_info&& info) {
43+
std::basic_stringstream<CharT> sstr;
44+
sstr << info;
45+
std::basic_string<CharT> output = sstr.str();
46+
47+
TEST_REQUIRE(expected == output,
48+
TEST_WRITE_CONCATENATED("\nExpected output ", expected, "\nActual output ", output, '\n'));
49+
}
50+
51+
template <class CharT>
52+
static void test() {
53+
using namespace std::literals::chrono_literals;
54+
namespace tz = std::chrono;
55+
// result values matching the "known" results
56+
test(SV("unique: "
57+
"{[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min TZ, "
58+
"[1970-01-01 00:00:00, 1970-01-01 00:00:00) 00:00:00 0min }"),
59+
tz::local_info{tz::local_info::unique,
60+
tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"},
61+
tz::sys_info{}});
62+
63+
test(SV("non-existent: "
64+
"{[1970-01-01 00:00:00, 2038-12-31 00:00:00) 12:23:45 -67min NEG, "
65+
"[1970-01-01 00:00:00, 2038-12-31 00:00:00) -12:23:45 67min POS}"),
66+
tz::local_info{
67+
tz::local_info::nonexistent,
68+
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
69+
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
70+
12h + 23min + 45s,
71+
-67min,
72+
"NEG"},
73+
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
74+
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
75+
-(12h + 23min + 45s),
76+
67min,
77+
"POS"}});
78+
79+
test(SV("ambiguous: "
80+
"{[1970-01-01 00:00:00, 2038-12-31 00:00:00) 12:23:45 -67min NEG, "
81+
"[1970-01-01 00:00:00, 2038-12-31 00:00:00) -12:23:45 67min POS}"),
82+
tz::local_info{
83+
tz::local_info::ambiguous,
84+
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
85+
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
86+
12h + 23min + 45s,
87+
-67min,
88+
"NEG"},
89+
tz::sys_info{static_cast<tz::sys_days>(tz::year_month_day{1970y, tz::January, 1d}),
90+
static_cast<tz::sys_days>(tz::year_month_day{2038y, tz::December, 31d}),
91+
-(12h + 23min + 45s),
92+
67min,
93+
"POS"}});
94+
95+
// result values not matching the "known" results
96+
test(
97+
SV("unspecified result (-1): "
98+
"{[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min TZ, "
99+
"[1970-01-01 00:00:00, 1970-01-01 00:00:00) 00:00:00 0min }"),
100+
tz::local_info{-1, tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"}, tz::sys_info{}});
101+
test(SV("unspecified result (3): "
102+
"{[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min TZ, "
103+
"[1970-01-01 00:00:00, 1970-01-01 00:00:00) 00:00:00 0min }"),
104+
tz::local_info{3, tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"}, tz::sys_info{}});
105+
}
106+
107+
int main(int, const char**) {
108+
test<char>();
109+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
110+
test<wchar_t>();
111+
#endif
112+
113+
return 0;
114+
}

0 commit comments

Comments
 (0)