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. 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 > > > > > >