On Wed, 4 Jun 2025 at 15:35, Tomasz Kaminski <tkami...@redhat.com> wrote: > > > > On Wed, Jun 4, 2025 at 4:04 PM Jonathan Wakely <jwak...@redhat.com> wrote: >> >> On 04/06/25 13:06 +0200, Tomasz Kamiński wrote: >> >Adding a tests for behavior of the ostream operator and the formatting >> >with empty chronio-spec for the chrono types. Current coverage is: >> > * time point, zoned_time and local_time_format in this commit, >> > * duration and hh_mm_ss in r16-1099-gac0a04b7a254fb, >> > * calendar types in r16-1016-g28a17985dd34b7. >> > >> >libstdc++-v3/ChangeLog: >> > >> > * testsuite/std/time/format/empty_spec.cc: New tests. >> >--- >> >The only change is mention of the duration test in commit message, >> >after the rebase. OK for trunk? >> >> OK with one comment added, as suggested below. Thanks. >> >> >> > .../testsuite/std/time/format/empty_spec.cc | 208 ++++++++++++++++-- >> > 1 file changed, 194 insertions(+), 14 deletions(-) >> > >> >diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc >> >b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc >> >index 46942dc30fc..1cb0066a608 100644 >> >--- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc >> >+++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc >> >@@ -12,6 +12,46 @@ using namespace std::chrono; >> > #define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S) >> > #define WIDEN(S) WIDEN_(_CharT, S) >> > >> >+template<typename CharT, typename T> >> >+void >> >+test_no_empty_spec() >> >+{ >> >+ try >> >+ { >> >+ T t{}; >> >+ >> >+ if constexpr (std::is_same_v<CharT, char>) >> >+ (void)std::vformat("{}", std::make_format_args(t)); >> >+#ifdef _GLIBCXX_USE_WCHAR_T >> >+ else >> >+ (void)std::vformat(L"{}", std::make_wformat_args(t)); >> >+#endif // _GLIBCXX_USE_WCHAR_T >> >+ VERIFY(false); >> >+ } >> >+ catch (const std::format_error&) >> >+ { >> >+ VERIFY(true); >> >+ } >> >+} >> >+ >> >+template<typename T, typename _CharT> >> >+void verify(const T& t, std::basic_string_view<_CharT> str) >> >+{ >> >+ std::basic_string<_CharT> res; >> >+ >> >+ res = std::format(WIDEN("{}"), t); >> >+ VERIFY( res == str ); >> >+ >> >+ std::basic_stringstream<_CharT> os; >> >+ os << t; >> >+ res = std::move(os).str(); >> >+ VERIFY( res == str ); >> >+} >> >+ >> >+template<typename T, typename CharT> >> >+void verify(const T& t, const CharT* str) >> >+{ verify(t, std::basic_string_view<CharT>(str)); } >> >+ >> > template<typename _CharT> >> > void >> > test_padding() >> >@@ -37,20 +77,6 @@ test_padding() >> > VERIFY( res == WIDEN("==16 is not a valid month==") ); >> > } >> > >> >-template<typename T, typename _CharT> >> >-void verify(const T& t, const _CharT* str) >> >-{ >> >- std::basic_string<_CharT> res; >> >- >> >- res = std::format(WIDEN("{}"), t); >> >- VERIFY( res == str ); >> >- >> >- std::basic_stringstream<_CharT> os; >> >- os << t; >> >- res = std::move(os).str(); >> >- VERIFY( res == str ); >> >-} >> >- >> > template<typename Ret = void> >> > struct Rep >> > { >> >@@ -553,6 +579,159 @@ test_calendar() >> > test_year_month_weekday_last<CharT>(); >> > } >> > >> >+template<typename Clock, typename Dur, typename Dur2> >> >+constexpr auto >> >+wall_cast(const local_time<Dur2>& tp) >> >+{ >> >+ using TP = time_point<Clock, std::common_type_t<Dur, days>>; >> >+ if constexpr (std::is_same_v<Clock, utc_clock> || std::is_same_v<Clock, >> >file_clock>) >> >+ return clock_cast<Clock>(wall_cast<system_clock, Dur>(tp)); >> >+ else if constexpr (std::is_same_v<Clock, tai_clock>) >> >+ return TP(floor<Dur>(tp.time_since_epoch()) + days(4383)); >> >+ else if constexpr (std::is_same_v<Clock, gps_clock>) >> >+ return TP(floor<Dur>(tp.time_since_epoch()) - days(3657)); >> >+ else >> >> I would find "else // system_clock" helpful here, so that it's easier >> to quickly find which case is used for sys times. Otherwise I have to >> carefully read all the other cases to be sure they don't mention >> system_clock. > > Added // system_clock, local_t > We also use local_t time to call the floor.
Ah yes, thanks. > I was discussing with Howard having to_local/from_local and > clock_cast_conversion > specializations, to construct or fetch wall time. But then I failed to find a > good way to handle leap > seconds, as local_time cannot represent them. >> >> >> >+ return time_point<Clock, Dur>(floor<Dur>(tp.time_since_epoch())); >> >+} >> >+ >> >+using decadays = duration<days::rep, std::ratio_multiply<std::deca, >> >days::period>>; >> >+using kilodays = duration<days::rep, std::ratio_multiply<std::kilo, >> >days::period>>; >> >+ >> >+template<typename _CharT, typename Clock> >> >+void >> >+test_time_point(bool daysAsTime) >> >+{ >> >+ std::basic_string<_CharT> res; >> >+ >> >+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + >> >111222333ns; >> >+ auto strip_time = [daysAsTime](std::basic_string_view<_CharT> sv) >> >+ { return daysAsTime ? sv : sv.substr(0, 10); }; >> >+ >> >+ verify( wall_cast<Clock, nanoseconds>(lt), >> >+ WIDEN("2024-03-22 13:24:54.111222333") ); >> >+ verify( wall_cast<Clock, microseconds>(lt), >> >+ WIDEN("2024-03-22 13:24:54.111222") ); >> >+ verify( wall_cast<Clock, milliseconds>(lt), >> >+ WIDEN("2024-03-22 13:24:54.111") ); >> >+ verify( wall_cast<Clock, seconds>(lt), >> >+ WIDEN("2024-03-22 13:24:54") ); >> >+ verify( wall_cast<Clock, minutes>(lt), >> >+ WIDEN("2024-03-22 13:24:00") ); >> >+ verify( wall_cast<Clock, hours>(lt), >> >+ WIDEN("2024-03-22 13:00:00") ); >> >+ verify( wall_cast<Clock, days>(lt), >> >+ strip_time(WIDEN("2024-03-22 00:00:00")) ); >> >+ verify( wall_cast<Clock, decadays>(lt), >> >+ strip_time(WIDEN("2024-03-18 00:00:00")) ); >> >+ verify( wall_cast<Clock, kilodays>(lt), >> >+ strip_time(WIDEN("2022-01-08 00:00:00")) ); >> >+} >> >+ >> >+template<typename _CharT> >> >+void >> >+test_leap_second() >> >+{ >> >+ std::basic_string<_CharT> res; >> >+ >> >+ const auto st = sys_days(2012y/June/30) + 23h + 59min + 59s + >> >111222333ns; >> >+ auto tp = clock_cast<utc_clock>(st); >> >+ tp += 1s; >> >+ >> >+ verify( floor<nanoseconds>(tp), >> >+ WIDEN("2012-06-30 23:59:60.111222333") ); >> >+ verify( floor<microseconds>(tp), >> >+ WIDEN("2012-06-30 23:59:60.111222") ); >> >+ verify( floor<milliseconds>(tp), >> >+ WIDEN("2012-06-30 23:59:60.111") ); >> >+ verify( floor<seconds>(tp), >> >+ WIDEN("2012-06-30 23:59:60") ); >> >> Thanks for remembering to test the sneaky leap second case. >> >> >+} >> >+ >> >+template<typename Dur, typename Dur2> >> >+auto >> >+make_zoned(const sys_time<Dur2>& st, const time_zone* tz) >> >+{ return zoned_time<Dur>(tz, floor<Dur>(st)); } >> >+ >> >+template<typename _CharT> >> >+void >> >+test_zoned_time() >> >+{ >> >+ const auto st = sys_days(2024y/March/22) + 13h + 24min + 54s + >> >111222333ns; >> >+ const time_zone* tz = locate_zone("Europe/Sofia"); >> >+ VERIFY( tz != nullptr ); >> >+ >> >+ verify( make_zoned<nanoseconds>(st, tz), >> >+ WIDEN("2024-03-22 15:24:54.111222333 EET") ); >> >+ verify( make_zoned<microseconds>(st, tz), >> >+ WIDEN("2024-03-22 15:24:54.111222 EET") ); >> >+ verify( make_zoned<milliseconds>(st, tz), >> >+ WIDEN("2024-03-22 15:24:54.111 EET") ); >> >+ verify( make_zoned<seconds>(st, tz), >> >+ WIDEN("2024-03-22 15:24:54 EET") ); >> >+ verify( make_zoned<minutes>(st, tz), >> >+ WIDEN("2024-03-22 15:24:00 EET") ); >> >+ verify( make_zoned<hours>(st, tz), >> >+ WIDEN("2024-03-22 15:00:00 EET") ); >> >+ verify( make_zoned<days>(st, tz), >> >+ WIDEN("2024-03-22 02:00:00 EET") ); >> >+ verify( make_zoned<decadays>(st, tz), >> >+ WIDEN("2024-03-18 02:00:00 EET") ); >> >+ verify( make_zoned<kilodays>(st, tz), >> >+ WIDEN("2022-01-08 02:00:00 EET") ); >> >+} >> >+ >> >+template<typename Dur, typename Dur2> >> >+auto >> >+local_fmt(const local_time<Dur2>& lt, std::string* zone) >> >+{ return local_time_format(floor<Dur>(lt), zone); } >> >+ >> >+template<typename _CharT> >> >+void >> >+test_local_time_format() >> >+{ >> >+ std::basic_string<_CharT> res; >> >+ >> >+ std::string abbrev = "Zone"; >> >+ const auto lt = local_days(2024y/March/22) + 13h + 24min + 54s + >> >111222333ns; >> >+ >> >+ res = std::format(WIDEN("{}"), local_fmt<nanoseconds>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111222333 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<microseconds>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111222 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<milliseconds>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 13:24:54.111 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<seconds>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 13:24:54 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<minutes>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 13:24:00 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<hours>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 13:00:00 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<days>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-22 00:00:00 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<decadays>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2024-03-18 00:00:00 Zone") ); >> >+ res = std::format(WIDEN("{}"), local_fmt<kilodays>(lt, &abbrev)); >> >+ VERIFY( res == WIDEN("2022-01-08 00:00:00 Zone") ); >> >+} >> >+ >> >+template<typename CharT> >> >+void >> >+test_time_points() >> >+{ >> >+ test_time_point<CharT, local_t>(false); >> >+ test_time_point<CharT, system_clock>(false); >> >+ test_time_point<CharT, utc_clock>(true); >> >+ test_time_point<CharT, tai_clock>(true); >> >+ test_time_point<CharT, gps_clock>(true); >> >+ test_time_point<CharT, file_clock>(true); >> >+ test_leap_second<CharT>(); >> >+ test_zoned_time<CharT>(); >> >+ test_local_time_format<CharT>(); >> >+ >> >+ test_no_empty_spec<CharT, sys_time<years>>(); >> >+ test_no_empty_spec<CharT, sys_time<duration<float>>>(); >> >+} >> >+ >> > template<typename CharT> >> > void >> > test_all() >> >@@ -560,6 +739,7 @@ test_all() >> > test_padding<CharT>(); >> > test_durations<CharT>(); >> > test_calendar<CharT>(); >> >+ test_time_points<CharT>(); >> > } >> > >> > int main() >> >-- >> >2.49.0 >> > >> > >>