diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2024-07-26 18:11:26 +0100 |
---|---|---|
committer | Jonathan Wakely <redi@gcc.gnu.org> | 2024-07-30 21:14:28 +0100 |
commit | 8f05ada7dfb9a40d4333a2aa9ccb5ddcdf8e2b06 (patch) | |
tree | 7c26413c30662d43baadcd2380a9bc1bb8256c0b /libstdc++-v3/testsuite/std | |
parent | a9e472c6b748abde55b5ecde2e2d98dcb2f96ded (diff) | |
download | gcc-8f05ada7dfb9a40d4333a2aa9ccb5ddcdf8e2b06.zip gcc-8f05ada7dfb9a40d4333a2aa9ccb5ddcdf8e2b06.tar.gz gcc-8f05ada7dfb9a40d4333a2aa9ccb5ddcdf8e2b06.tar.bz2 |
libstdc++: Fix std::format output for std::chrono::zoned_time
When formatting a chrono::zoned_time with an empty chrono-specs, we were
only formatting its _M_time member, but the ostream insertion operator
uses the format "{:L%F %T %Z}" which includes the time zone
abbreviation. The %Z should also be used when formatting with an empty
chrono-specs.
This commit makes _M_format_to_ostream handle __local_time_fmt
specializations directly, rather than calling itself recursively to
format the _M_time member. We need to be able to customize the output of
_M_format_to_ostream for __local_time_fmt, because we use that type for
gps_time and tai_time as well as for zoned_time and __local_time_fmt.
When formatting gps_time and tai_time we don't want to include the time
zone abbreviation in the "{}" output, but for zoned_time we do want to.
We can reuse the __is_neg flag passed to _M_format_to_ostream (via
_M_format) to say that we want the time zone abbreviation. Currently
the __is_neg flag is only used for duration specializations, so it's
available for __local_time_fmt to use.
In addition to fixing the zoned_time output to use %Z, this commit also
changes the __local_time_fmt output to use %Z. Previously it didn't use
it, just like zoned_time. The standard doesn't actually say how to
format local-time-format-t for an empty chrono-specs, but this behaviour
seems sensible and is what I'm proposing as part of LWG 4124.
While testing this I noticed that some chrono types were not being
tested with empty chrono-specs, so this adds more tests. I also noticed
that std/time/clock/local/io.cc was testing tai_time instead of
local_time, which was completely wrong. That's fixed now too.
libstdc++-v3/ChangeLog:
* include/bits/chrono_io.h (__local_fmt_t): Remove unused
declaration.
(__formatter_chrono::_M_format_to_ostream): Add explicit
handling for specializations of __local_time_fmt, including the
time zone abbreviation in the output if __is_neg is true.
(formatter<chrono::tai_time<D>>::format): Add comment.
(formatter<chrono::gps_time<D>>::format): Likewise.
(formatter<chrono::__detail::__local_time_fmt::format): Call
_M_format with true for the __is_neg flag.
* testsuite/std/time/clock/gps/io.cc: Remove unused variable.
* testsuite/std/time/clock/local/io.cc: Fix test error that
checked tai_time instead of local_time. Add tests for
local-time-format-t formatting.
* testsuite/std/time/clock/system/io.cc: Check empty
chrono-specs.
* testsuite/std/time/clock/tai/io.cc: Likewise.
* testsuite/std/time/zoned_time/io.cc: Likewise.
Diffstat (limited to 'libstdc++-v3/testsuite/std')
-rw-r--r-- | libstdc++-v3/testsuite/std/time/clock/gps/io.cc | 1 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/time/clock/local/io.cc | 78 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/time/clock/system/io.cc | 8 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/time/clock/tai/io.cc | 3 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/time/zoned_time/io.cc | 11 |
5 files changed, 95 insertions, 6 deletions
diff --git a/libstdc++-v3/testsuite/std/time/clock/gps/io.cc b/libstdc++-v3/testsuite/std/time/clock/gps/io.cc index d5405f6..e995d9f 100644 --- a/libstdc++-v3/testsuite/std/time/clock/gps/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/gps/io.cc @@ -22,7 +22,6 @@ test_ostream() ss << gt; VERIFY( ss.str() == "2000-01-01 00:00:13" ); - gps_time<duration<float>> gtf = gt; ss.str(""); ss.clear(); ss << (gps_time<duration<long double>>(gt) + 20ms); diff --git a/libstdc++-v3/testsuite/std/time/clock/local/io.cc b/libstdc++-v3/testsuite/std/time/clock/local/io.cc index bb682cd..b6e8b35 100644 --- a/libstdc++-v3/testsuite/std/time/clock/local/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/local/io.cc @@ -8,14 +8,84 @@ void test_ostream() { + using namespace std::chrono; + + auto lt = local_time<seconds>(1722198122s); + + std::ostringstream ss; + ss << lt; + auto s = ss.str(); + ss.str(""); + ss.clear(); + ss << sys_time<seconds>{lt.time_since_epoch()}; + auto s2 = ss.str(); + VERIFY( s == s2 ); +} + +void +test_format() +{ using std::format; using namespace std::chrono; - auto st = sys_days{2000y/January/1}; - auto tt = clock_cast<tai_clock>(st); + auto lt = local_seconds(1722198122s); + +#if __cpp_exceptions + auto args = std::make_format_args(lt); + try + { + (void) std::vformat("{:%Z}", args); + VERIFY(false); + } + catch (const std::format_error&) + { + } + try + { + (void) std::vformat("{:%z}", args); + VERIFY(false); + } + catch (const std::format_error&) + { + } +#endif + + auto s = format("{0:%F %T %a}", lt); + VERIFY( s == "2024-07-28 20:22:02 Sun" ); + + s = format("{}", lt); + VERIFY( s == "2024-07-28 20:22:02" ); - auto s = format("{0:%F %T %Z} == {1:%F %T %Z}", st, tt); - VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:32 TAI" ); + // Test formatting for chrono::local_time_format and local-time-format-t too: + auto ltf = local_time_format(lt); + s = std::format("{:%F %T %a %b}", ltf); + VERIFY( s == "2024-07-28 20:22:02 Sun Jul" ); +#if __cpp_exceptions + try + { + (void) std::format("{:%Z}", ltf); + VERIFY(false); + } + catch (const std::format_error&) + { + } + try + { + (void) std::format("{:%z}", ltf); + VERIFY(false); + } + catch (const std::format_error&) + { + } +#endif + std::string abbrev = "FOO"; + seconds off = -3600s; + ltf = local_time_format(lt, &abbrev, &off); + s = std::format("{}", ltf); + VERIFY( s == "2024-07-28 20:22:02 FOO" ); + s = std::format("{:%Z %T %F %z %Ez}", ltf); + __builtin_puts(s.c_str()); + VERIFY( s == "FOO 20:22:02 2024-07-28 -0100 -01:00" ); } void diff --git a/libstdc++-v3/testsuite/std/time/clock/system/io.cc b/libstdc++-v3/testsuite/std/time/clock/system/io.cc index 2cc1161..5c223a9 100644 --- a/libstdc++-v3/testsuite/std/time/clock/system/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/system/io.cc @@ -64,13 +64,19 @@ test_format() " | 25.708 | 17:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22" " | 17:26:25 | 22 | 2022 | +0000 | UTC" ); + auto st = std::chrono::time_point_cast<std::chrono::seconds>(t); auto loc = std::locale::classic(); auto smod = std::format(loc, "{:%Ec %EC %Od %Oe %OH %OI %Om %OM %OS %Ou %OU" " %Ow %OW %Ex %EX %Oy %Ey %EY %Ez %Oz}", t); s = std::format("{:%c %C %d %e %H %I %m %M %S %u %U" " %w %W %x %X %y %y %Y +00:00 +00:00}", - std::chrono::time_point_cast<std::chrono::seconds>(t)); + st); VERIFY( smod == s ); + + s = std::format("{}", t); + VERIFY( s == "2022-12-19 17:26:25.708" ); + s = std::format("{0:} {0:=<21}", st); + VERIFY( s == "2022-12-19 17:26:25 2022-12-19 17:26:25==" ); } void diff --git a/libstdc++-v3/testsuite/std/time/clock/tai/io.cc b/libstdc++-v3/testsuite/std/time/clock/tai/io.cc index 0fd61c0..dc0c3d2 100644 --- a/libstdc++-v3/testsuite/std/time/clock/tai/io.cc +++ b/libstdc++-v3/testsuite/std/time/clock/tai/io.cc @@ -16,6 +16,9 @@ test_ostream() auto s = format("{0:%F %T %Z} == {1:%F %T %Z}", st, tt); VERIFY( s == "2000-01-01 00:00:00 UTC == 2000-01-01 00:00:32 TAI" ); + + s = std::format("{:=>21}", tt); + VERIFY( s == "==2000-01-01 00:00:32" ); } void diff --git a/libstdc++-v3/testsuite/std/time/zoned_time/io.cc b/libstdc++-v3/testsuite/std/time/zoned_time/io.cc index 376b273..ee3b9ed 100644 --- a/libstdc++-v3/testsuite/std/time/zoned_time/io.cc +++ b/libstdc++-v3/testsuite/std/time/zoned_time/io.cc @@ -37,6 +37,7 @@ test_format() " | 25.708 | 12:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22" " | 12:26:25 | 22 | 2022 | -0500 | EST" ); +#ifdef _GLIBCXX_USE_WCHAR_T std::wstring ws = std::format(L"{:%a | %A | %b | %B | %c" " | %C | %d | %D | %e | %F | %g | %G | %h" " | %H | %I | %j | %m | %M | %p | %r | %R" @@ -47,6 +48,7 @@ test_format() " | 12 | 12 | 353 | 12 | 26 | PM | 12:26:25 PM | 12:26" " | 25.708 | 12:26:25.708 | 1 | 51 | 51 | 1 | 51 | 12/19/22" " | 12:26:25 | 22 | 2022 | -0500 | EST" ); +#endif auto loc = std::locale::classic(); auto smod = std::format(loc, "{:%Ec %EC %Od %Oe %OH %OI %Om %OM %OS %Ou %OU" @@ -55,6 +57,15 @@ test_format() " %w %W %x %X %y %y %Y -05:00 -05:00}", zoned_time<seconds>(zone, time_point_cast<seconds>(t))); VERIFY( smod == s ); + + s = std::format("{}", zt); + VERIFY( s == "2022-12-19 12:26:25.708 EST" ); + s = std::format("{1:=>30}", 1, zt); + VERIFY( s == "===2022-12-19 12:26:25.708 EST" ); +#ifdef _GLIBCXX_USE_WCHAR_T + ws = std::format(L"{:+^34}", zoned_time<microseconds>(zone, t)); + VERIFY( ws == L"++2022-12-19 12:26:25.708000 EST++" ); +#endif } int main() |