-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[libc++][TZDB] Adds sys_info formatter. #85896
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
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) ChangesImplements parts of:
Full diff: https://github.com/llvm/llvm-project/pull/85896.diff 8 Files Affected:
diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv
index 82da54284c7386..32166ec72da753 100644
--- a/libcxx/docs/Status/FormatPaper.csv
+++ b/libcxx/docs/Status/FormatPaper.csv
@@ -24,7 +24,7 @@ Section,Description,Dependencies,Assignee,Status,First released version
`[time.syn] <https://wg21.link/time.syn>`_,"Formatter ``chrono::year_month_weekday``",,Mark de Wever,|Complete|,16.0
`[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``",A ``<chrono>`` implementation,Mark de Wever,,
+`[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::zoned_time<Duration, TimeZonePtr>``",A ``<chrono>`` implementation,Mark de Wever,,
diff --git a/libcxx/include/__chrono/convert_to_tm.h b/libcxx/include/__chrono/convert_to_tm.h
index 1301cd6f1f1ada..d2c5cf922ba671 100644
--- a/libcxx/include/__chrono/convert_to_tm.h
+++ b/libcxx/include/__chrono/convert_to_tm.h
@@ -20,6 +20,7 @@
#include <__chrono/month_weekday.h>
#include <__chrono/monthday.h>
#include <__chrono/statically_widen.h>
+#include <__chrono/sys_info.h>
#include <__chrono/system_clock.h>
#include <__chrono/time_point.h>
#include <__chrono/weekday.h>
@@ -171,6 +172,10 @@ _LIBCPP_HIDE_FROM_ABI _Tm __convert_to_tm(const _ChronoT& __value) {
if (__value.hours().count() > std::numeric_limits<decltype(__result.tm_hour)>::max())
std::__throw_format_error("Formatting hh_mm_ss, encountered an hour overflow");
__result.tm_hour = __value.hours().count();
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+ } else if constexpr (same_as<_ChronoT, chrono::sys_info>) {
+ // Has no time information.
+# endif
} else
static_assert(sizeof(_ChronoT) == 0, "Add the missing type specialization");
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index 8b8592041a1fb9..f5474e3ea6d078 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -24,6 +24,7 @@
#include <__chrono/ostream.h>
#include <__chrono/parser_std_format_spec.h>
#include <__chrono/statically_widen.h>
+#include <__chrono/sys_info.h>
#include <__chrono/system_clock.h>
#include <__chrono/time_point.h>
#include <__chrono/weekday.h>
@@ -202,6 +203,12 @@ struct _LIBCPP_HIDE_FROM_ABI __time_zone {
template <class _Tp>
_LIBCPP_HIDE_FROM_ABI __time_zone __convert_to_time_zone([[maybe_unused]] const _Tp& __value) {
__time_zone __result;
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+ if constexpr (same_as<_Tp, chrono::sys_info>) {
+ __result.__offset = __value.offset;
+ __result.__abbrev = __value.abbrev;
+ }
+# endif
return __result;
}
@@ -411,6 +418,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_ok(const _Tp& __value) {
return __value.weekday().ok();
else if constexpr (__is_hh_mm_ss<_Tp>)
return true;
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+ else if constexpr (same_as<_Tp, chrono::sys_info>)
+ return true;
+# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
}
@@ -451,6 +462,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __weekday_name_ok(const _Tp& __value) {
return __value.weekday().ok();
else if constexpr (__is_hh_mm_ss<_Tp>)
return true;
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+ else if constexpr (same_as<_Tp, chrono::sys_info>)
+ return true;
+# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
}
@@ -491,6 +506,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __date_ok(const _Tp& __value) {
return __value.ok();
else if constexpr (__is_hh_mm_ss<_Tp>)
return true;
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+ else if constexpr (same_as<_Tp, chrono::sys_info>)
+ return true;
+# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
}
@@ -531,6 +550,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __month_name_ok(const _Tp& __value) {
return __value.month().ok();
else if constexpr (__is_hh_mm_ss<_Tp>)
return true;
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+ else if constexpr (same_as<_Tp, chrono::sys_info>)
+ return true;
+# endif
else
static_assert(sizeof(_Tp) == 0, "Add the missing type specialization");
}
@@ -860,6 +883,20 @@ struct formatter<chrono::hh_mm_ss<_Duration>, _CharT> : public __formatter_chron
return _Base::__parse(__ctx, __format_spec::__fields_chrono, __format_spec::__flags::__time);
}
};
+
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+template <__fmt_char_type _CharT>
+struct formatter<chrono::sys_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::__time_zone);
+ }
+};
+# endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
#endif // if _LIBCPP_STD_VER >= 20
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__chrono/ostream.h b/libcxx/include/__chrono/ostream.h
index b687ef8059d5f5..68ddb1d6cd2e13 100644
--- a/libcxx/include/__chrono/ostream.h
+++ b/libcxx/include/__chrono/ostream.h
@@ -19,6 +19,7 @@
#include <__chrono/month_weekday.h>
#include <__chrono/monthday.h>
#include <__chrono/statically_widen.h>
+#include <__chrono/sys_info.h>
#include <__chrono/system_clock.h>
#include <__chrono/weekday.h>
#include <__chrono/year.h>
@@ -262,6 +263,25 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const hh_mm_ss<_Duration> __hms
return __os << std::format(__os.getloc(), _LIBCPP_STATICALLY_WIDEN(_CharT, "{:L%T}"), __hms);
}
+# if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+template <class _CharT, class _Traits>
+_LIBCPP_HIDE_FROM_ABI basic_ostream<_CharT, _Traits>&
+operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_info& __info) {
+ // __info.abbrev is always std::basic_string<char>.
+ // Since these strings typically are short the conversion should be cheap.
+ std::basic_string<_CharT> __abbrev{__info.abbrev.begin(), __info.abbrev.end()};
+ return __os << std::format(
+ _LIBCPP_STATICALLY_WIDEN(_CharT, "[{}, {}) {:%T} {:%Q%q} {}"),
+ __info.begin,
+ __info.end,
+ hh_mm_ss{__info.offset},
+ __info.save,
+ __abbrev);
+}
+
+# endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
} // namespace chrono
#endif // if _LIBCPP_STD_VER >= 20
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index 00b940a6610a3a..c068bbef73245b 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -733,6 +733,10 @@ struct sys_info {
string abbrev;
};
+template<class charT, class traits> // C++20
+ basic_ostream<charT, traits>&
+ operator<<(basic_ostream<charT, traits>& os, const sys_info& si);
+
// 25.10.5, class time_zone // C++20
enum class choose {earliest, latest};
class time_zone {
@@ -829,6 +833,7 @@ namespace std {
template<class charT> struct formatter<chrono::year_month_weekday_last, charT>; // C++20
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
} // namespace std
namespace chrono {
diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.info/time.zone.info.sys/ostream.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.info/time.zone.info.sys/ostream.pass.cpp
new file mode 100644
index 00000000000000..26a8ddd3bfbad9
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.zone/time.zone.info/time.zone.info.sys/ostream.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+
+// <chrono>
+
+// template<class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const sys_info& r);
+
+// [time.zone.info.sys]
+// 7 Effects: Streams out the sys_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::sys_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;
+
+ test(SV("[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min TZ"),
+ tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"});
+
+ test(SV("[1970-01-01 00:00:00, 2038-12-31 00:00:00) 12:23:45 -67min DMY"),
+ 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,
+ "DMY"});
+}
+
+int main(int, const char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.syn/formatter.sys_info.pass.cpp b/libcxx/test/std/time/time.syn/formatter.sys_info.pass.cpp
new file mode 100644
index 00000000000000..53da20668c64f5
--- /dev/null
+++ b/libcxx/test/std/time/time.syn/formatter.sys_info.pass.cpp
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+// 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
+// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
+
+// TODO FMT This test should not require std::to_chars(floating-point)
+// XFAIL: availability-fp_to_chars-missing
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+
+// REQUIRES: locale.fr_FR.UTF-8
+// REQUIRES: locale.ja_JP.UTF-8
+
+// <chrono>
+//
+// template<class charT> struct formatter<chrono::sys_info, charT>;
+
+#include <chrono>
+#include <format>
+
+#include <cassert>
+#include <concepts>
+#include <locale>
+#include <iostream>
+#include <type_traits>
+
+#include "formatter_tests.h"
+#include "make_string.h"
+#include "platform_support.h" // locale name macros
+#include "test_macros.h"
+
+template <class CharT>
+static void test_no_chrono_specs() {
+// This test libc++ specific due to
+// [time.zone.info.sys]/7
+// Effects: Streams out the sys_info object r in an unspecified format.
+#ifdef _LIBCPP_VERSION
+ using namespace std::literals::chrono_literals;
+ namespace tz = std::chrono;
+
+ std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
+
+ // Non localized output
+
+ check(SV("[-10484-10-16 15:30:08, 14423-03-17 15:30:07) 00:00:00 0min TZ"),
+ SV("{}"),
+ tz::sys_info{tz::sys_seconds::min(), tz::sys_seconds::max(), 0s, 0min, "TZ"});
+
+ check(SV("[1970-01-01 00:00:00, 2038-12-31 00:00:00) 12:23:45 -67min DMY"),
+ SV("{}"),
+ 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,
+ "DMY"});
+
+ std::locale::global(std::locale::classic());
+#endif // _LIBCPP_VERSION
+}
+
+template <class CharT>
+static void test_valid_values() {
+ using namespace std::literals::chrono_literals;
+
+ constexpr std::basic_string_view<CharT> fmt = SV("{:%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}");
+ constexpr std::basic_string_view<CharT> lfmt = SV("{:L%%z='%z'%t%%Ez='%Ez'%t%%Oz='%Oz'%t%%Z='%Z'%n}");
+
+ const std::locale loc(LOCALE_ja_JP_UTF_8);
+ std::locale::global(std::locale(LOCALE_fr_FR_UTF_8));
+
+ // Non localized output using C-locale
+ check(SV("%z='-0200'\t%Ez='-02:00'\t%Oz='-02:00'\t%Z='NEG'\n"),
+ fmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, -2h, 0min, "NEG"});
+
+ check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='ZERO'\n"),
+ fmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, 0s, 0min, "ZERO"});
+
+ check(SV("%z='+1115'\t%Ez='+11:15'\t%Oz='+11:15'\t%Z='POS'\n"),
+ fmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, 11h + 15min, 0min, "POS"});
+
+ // Use the global locale (fr_FR)
+ check(SV("%z='-0200'\t%Ez='-02:00'\t%Oz='-02:00'\t%Z='NEG'\n"),
+ lfmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, -2h, 0min, "NEG"});
+
+ check(SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='ZERO'\n"),
+ lfmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, 0s, 0min, "ZERO"});
+
+ check(SV("%z='+1115'\t%Ez='+11:15'\t%Oz='+11:15'\t%Z='POS'\n"),
+ lfmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, 11h + 15min, 0min, "POS"});
+
+ // Use supplied locale (ja_JP).
+ check(loc,
+ SV("%z='-0200'\t%Ez='-02:00'\t%Oz='-02:00'\t%Z='NEG'\n"),
+ lfmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, -2h, 0min, "NEG"});
+
+ check(loc,
+ SV("%z='+0000'\t%Ez='+00:00'\t%Oz='+00:00'\t%Z='ZERO'\n"),
+ lfmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, 0s, 0min, "ZERO"});
+
+ check(loc,
+ SV("%z='+1115'\t%Ez='+11:15'\t%Oz='+11:15'\t%Z='POS'\n"),
+ lfmt,
+ std::chrono::sys_info{std::chrono::sys_seconds{0s}, std::chrono::sys_seconds{0s}, 11h + 15min, 0min, "POS"});
+
+ std::locale::global(std::locale::classic());
+}
+
+template <class CharT>
+static void test() {
+ test_no_chrono_specs<CharT>();
+ test_valid_values<CharT>();
+
+ check_invalid_types<CharT>({SV("z"), SV("Z"), SV("Ez"), SV("Oz")}, std::chrono::sys_info{});
+}
+
+int main(int, char**) {
+ test<char>();
+
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/ostream.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/ostream.pass.cpp
new file mode 100644
index 00000000000000..4edbdb065b1c90
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/ostream.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+
+// <chrono>
+
+// template<class charT, class traits>
+// basic_ostream<charT, traits>&
+// operator<<(basic_ostream<charT, traits>& os, const sys_info& r);
+
+// [time.zone.info.sys]
+// 7 Effects: Streams out the sys_info object r in an unspecified format.
+// 8 Returns: os.
+//
+// There is a private libc++ test that validates the exact output.
+
+#include <cassert>
+#include <chrono>
+#include <memory>
+#include <sstream>
+
+#include "test_macros.h"
+
+template <class CharT>
+static void test() {
+ std::chrono::sys_info s;
+ std::basic_ostringstream<CharT> os;
+ std::basic_ostream<CharT>& result = std::chrono::operator<<(os, s);
+ assert(std::addressof(result) == std::addressof(os));
+}
+
+int main(int, const char**) {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+
+ return 0;
+}
|
3eaa059
to
73e4a9e
Compare
f3e7b58
to
677956d
Compare
e6ae1f0
to
96bc907
Compare
ldionne
approved these changes
Apr 16, 2024
mordante
commented
Apr 16, 2024
677956d
to
96fbdc0
Compare
Base automatically changed from
users/mordante/improves_chrono_year_formatting
to
main
April 17, 2024 15:02
Implements parts of: - P0355 Extending <chrono> to Calendars and Time Zones - P1361 Integration of chrono with text formatting
96bc907
to
c75ae7b
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Implements parts of: