The standard does not currently specify how the precision value
is interpreted if specify, only prohibit it from being used for
formatting any other object than durations with floating point types.

This patch interprets user-specified duration value as follows:
 * if spec is empty for floating-point duration, the ostringstream
   is configured with precision value
 * for "%Q" is used for floating-point duration, the duration units
   are formated with format string that includes precision
 * for "%S" the precision controls the number of decimal digits
   for subseconds that is printed.

With support in "%S" setting precision makes sense also for time-points.
This patch takes simple approach of always allowing precision to be specified,
and the value is ignored if no specifier are affected. We could also limit
if to situations when _Subseconds or _EpochUnits for floating point rep
are requested.

Finally, for integral durations, the precision is trimmed to 18 digits,
this can be adjusted, if we decide to go with direction of this patch.

libstdc++-v3/ChangeLog:

        * include/bits/chrono_io.h (__foramtter_chrono::_M_parse):
        Parse precision value into _M_spec.
        (__formatter_chrono::_M_Q): Include precision in format string,
        if specified.
        (__formatter_duration::_M_format_to_ostream): Configure precision
        if provided.
        * testsuite/std/time/format/format.cc: Precision is now allowed.
        * testsuite/std/time/format/precision.cc: Adjusted tests.
---
This patch is not meant to be landed now, it provides implementation 
exprience for one of the direction of resolving meaning of precision.

 libstdc++-v3/include/bits/chrono_io.h         |  25 ++--
 .../testsuite/std/time/format/format.cc       |   2 +-
 .../testsuite/std/time/format/precision.cc    | 113 +++++++++++++-----
 3 files changed, 92 insertions(+), 48 deletions(-)

diff --git a/libstdc++-v3/include/bits/chrono_io.h 
b/libstdc++-v3/include/bits/chrono_io.h
index d6bc6c7cf2a..a3264932024 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -594,19 +594,9 @@ namespace __format
          if (__finished())
            return __first;
 
-         if (*__first == '.')
-           {
-             if ((__parts & _ChronoParts::_EpochUnits) == 0
-                 || !__spec._M_floating_point_rep)
-               __throw_format_error("format error: invalid precision for 
duration");
-
-             // Precision is allowed, but value is ignored.
-             __first = _Spec<_CharT>()._M_parse_precision(__first, __last, 
__pc);
-             // Still inditate that there was user supplied precision.
-             __spec._M_prec_kind = _WP_value;
-            if (__finished())
-              return __first;
-           }
+         __first = __spec._M_parse_precision(__first, __last, __pc);
+         if (__finished())
+           return __first;
 
          __spec._M_localized = false;
          __first = __spec._M_parse_locale(__first, __last);
@@ -1499,7 +1489,12 @@ namespace __format
             _FormatContext& __ctx) const
        {
          // %Q The duration's numeric value.
-         return std::vformat_to(std::move(__out), _S_empty_spec, __t._M_ereps);
+
+         __string_view __fs = _S_empty_spec;
+         if (_M_spec._M_floating_point_rep 
+               && _M_spec._M_prec_kind != _WP_none)
+           __fs = _GLIBCXX_WIDEN("{0:.{2}}");
+         return std::vformat_to(std::move(__out), __fs, __t._M_ereps);
        }
 
       template<typename _FormatContext>
@@ -1903,6 +1898,8 @@ namespace __format
 
           if (__is_neg) [[unlikely]]
             __os << this->_S_plus_minus[1];
+          if (_M_spec._M_prec_kind != _WP_none)
+            __os.precision(_M_spec._M_get_precision(__fc));
           __os << __d;
 
          auto __str = std::move(__os).str();
diff --git a/libstdc++-v3/testsuite/std/time/format/format.cc 
b/libstdc++-v3/testsuite/std/time/format/format.cc
index d6e35832cb5..474b1b5a938 100644
--- a/libstdc++-v3/testsuite/std/time/format/format.cc
+++ b/libstdc++-v3/testsuite/std/time/format/format.cc
@@ -56,7 +56,7 @@ test_bad_format_strings()
   VERIFY( not is_format_string_for("{:04%T}", t) );
 
   // precision only valid for chrono::duration types with floating-point rep.
-  VERIFY( not is_format_string_for("{:.4}", t) );
+  // VERIFY( not is_format_string_for("{:.4}", t) );
 
   // unfinished format string
   VERIFY( not is_format_string_for("{:", t) );
diff --git a/libstdc++-v3/testsuite/std/time/format/precision.cc 
b/libstdc++-v3/testsuite/std/time/format/precision.cc
index aa266156c1f..46a774f70f4 100644
--- a/libstdc++-v3/testsuite/std/time/format/precision.cc
+++ b/libstdc++-v3/testsuite/std/time/format/precision.cc
@@ -19,26 +19,25 @@ test_empty()
   res = std::format(WIDEN("{:}"), d);
   VERIFY( res == WIDEN("33.1112s") );
   res = std::format(WIDEN("{:.0}"), d);
-  VERIFY( res == WIDEN("33.1112s") );
+  VERIFY( res == WIDEN("3e+01s") );
   res = std::format(WIDEN("{:.3}"), d);
-  VERIFY( res == WIDEN("33.1112s") );
+  VERIFY( res == WIDEN("33.1s") );
   res = std::format(WIDEN("{:.6}"), d);
   VERIFY( res == WIDEN("33.1112s") );
   res = std::format(WIDEN("{:.9}"), d);
-  VERIFY( res == WIDEN("33.1112s") );
+  VERIFY( res == WIDEN("33.111222s") );
 
-  // Uses ostream operator<<
   const duration<double, std::nano> nd = d;
   res = std::format(WIDEN("{:}"), nd);
   VERIFY( res == WIDEN("3.31112e+10ns") );
   res = std::format(WIDEN("{:.0}"), nd);
-  VERIFY( res == WIDEN("3.31112e+10ns") );
+  VERIFY( res == WIDEN("3e+10ns") );
   res = std::format(WIDEN("{:.3}"), nd);
-  VERIFY( res == WIDEN("3.31112e+10ns") );
+  VERIFY( res == WIDEN("3.31e+10ns") );
   res = std::format(WIDEN("{:.6}"), nd);
   VERIFY( res == WIDEN("3.31112e+10ns") );
   res = std::format(WIDEN("{:.9}"), nd);
-  VERIFY( res == WIDEN("3.31112e+10ns") );
+  VERIFY( res == WIDEN("3.3111222e+10ns") );
 }
 
 template<typename CharT>
@@ -51,11 +50,11 @@ test_Q()
   res = std::format(WIDEN("{:%Q}"), d);
   VERIFY( res == WIDEN("7.111222") );
   res = std::format(WIDEN("{:.0%Q}"), d);
-  VERIFY( res == WIDEN("7.111222") );
+  VERIFY( res == WIDEN("7") );
   res = std::format(WIDEN("{:.3%Q}"), d);
-  VERIFY( res == WIDEN("7.111222") );
+  VERIFY( res == WIDEN("7.11") );
   res = std::format(WIDEN("{:.6%Q}"), d);
-  VERIFY( res == WIDEN("7.111222") );
+  VERIFY( res == WIDEN("7.11122") );
   res = std::format(WIDEN("{:.9%Q}"), d);
   VERIFY( res == WIDEN("7.111222") );
 
@@ -63,11 +62,11 @@ test_Q()
   res = std::format(WIDEN("{:%Q}"), md);
   VERIFY( res == WIDEN("7111.222") );
   res = std::format(WIDEN("{:.0%Q}"), md);
-  VERIFY( res == WIDEN("7111.222") );
+  VERIFY( res == WIDEN("7e+03") );
   res = std::format(WIDEN("{:.3%Q}"), md);
-  VERIFY( res == WIDEN("7111.222") );
+  VERIFY( res == WIDEN("7.11e+03") );
   res = std::format(WIDEN("{:.6%Q}"), md);
-  VERIFY( res == WIDEN("7111.222") );
+  VERIFY( res == WIDEN("7111.22") );
   res = std::format(WIDEN("{:.9%Q}"), md);
   VERIFY( res == WIDEN("7111.222") );
 
@@ -75,13 +74,13 @@ test_Q()
   res = std::format(WIDEN("{:%Q}"), nd);
   VERIFY( res == WIDEN("7111222000") );
   res = std::format(WIDEN("{:.0%Q}"), nd);
-  VERIFY( res == WIDEN("7111222000") );
+  VERIFY( res == WIDEN("7e+09") );
   res = std::format(WIDEN("{:.3%Q}"), nd);
-  VERIFY( res == WIDEN("7111222000") );
+  VERIFY( res == WIDEN("7.11e+09") );
   res = std::format(WIDEN("{:.6%Q}"), nd);
-  VERIFY( res == WIDEN("7111222000") );
+  VERIFY( res == WIDEN("7.11122e+09") );
   res = std::format(WIDEN("{:.9%Q}"), nd);
-  VERIFY( res == WIDEN("7111222000") );
+  VERIFY( res == WIDEN("7.111222e+09") );
 }
 
 template<typename CharT>
@@ -97,45 +96,45 @@ test_S_fp()
   res = std::format(WIDEN("{:.0%S}"), d);
   VERIFY( res == WIDEN("05") );
   res = std::format(WIDEN("{:.3%S}"), d);
-  VERIFY( res == WIDEN("05") );
+  VERIFY( res == WIDEN("05.111") );
   res = std::format(WIDEN("{:.6%S}"), d);
-  VERIFY( res == WIDEN("05") );
+  VERIFY( res == WIDEN("05.111222") );
   res = std::format(WIDEN("{:.9%S}"), d);
-  VERIFY( res == WIDEN("05") );
+  VERIFY( res == WIDEN("05.111222000") );
 
   duration<double, std::milli> md = d;
   res = std::format(WIDEN("{:%S}"), md);
   VERIFY( res == WIDEN("05.111") );
   res = std::format(WIDEN("{:.0%S}"), md);
-  VERIFY( res == WIDEN("05.111") );
+  VERIFY( res == WIDEN("05") );
   res = std::format(WIDEN("{:.3%S}"), md);
   VERIFY( res == WIDEN("05.111") );
   res = std::format(WIDEN("{:.6%S}"), md);
-  VERIFY( res == WIDEN("05.111") );
+  VERIFY( res == WIDEN("05.111222") );
   res = std::format(WIDEN("{:.9%S}"), md);
-  VERIFY( res == WIDEN("05.111") );
+  VERIFY( res == WIDEN("05.111222000") );
 
   duration<double, std::micro> ud = d;
   res = std::format(WIDEN("{:%S}"), ud);
   VERIFY( res == WIDEN("05.111222") );
   res = std::format(WIDEN("{:.0%S}"), ud);
-  VERIFY( res == WIDEN("05.111222") );
+  VERIFY( res == WIDEN("05") );
   res = std::format(WIDEN("{:.3%S}"), ud);
-  VERIFY( res == WIDEN("05.111222") );
+  VERIFY( res == WIDEN("05.111") );
   res = std::format(WIDEN("{:.6%S}"), ud);
   VERIFY( res == WIDEN("05.111222") );
   res = std::format(WIDEN("{:.9%S}"), ud);
-  VERIFY( res == WIDEN("05.111222") );
+  VERIFY( res == WIDEN("05.111222000") );
 
   duration<double, std::nano> nd = d;
   res = std::format(WIDEN("{:%S}"), nd);
   VERIFY( res == WIDEN("05.111222000") );
   res = std::format(WIDEN("{:.0%S}"), nd);
-  VERIFY( res == WIDEN("05.111222000") );
+  VERIFY( res == WIDEN("05") );
   res = std::format(WIDEN("{:.3%S}"), nd);
-  VERIFY( res == WIDEN("05.111222000") );
+  VERIFY( res == WIDEN("05.111") );
   res = std::format(WIDEN("{:.6%S}"), nd);
-  VERIFY( res == WIDEN("05.111222000") );
+  VERIFY( res == WIDEN("05.111222") );
   res = std::format(WIDEN("{:.9%S}"), nd);
   VERIFY( res == WIDEN("05.111222000") );
 
@@ -143,13 +142,13 @@ test_S_fp()
   res = std::format(WIDEN("{:%S}"), pd);
   VERIFY( res == WIDEN("05.111222000000") );
   res = std::format(WIDEN("{:.0%S}"), pd);
-  VERIFY( res == WIDEN("05.111222000000") );
+  VERIFY( res == WIDEN("05") );
   res = std::format(WIDEN("{:.3%S}"), pd);
-  VERIFY( res == WIDEN("05.111222000000") );
+  VERIFY( res == WIDEN("05.111") );
   res = std::format(WIDEN("{:.6%S}"), pd);
-  VERIFY( res == WIDEN("05.111222000000") );
+  VERIFY( res == WIDEN("05.111222") );
   res = std::format(WIDEN("{:.9%S}"), pd);
-  VERIFY( res == WIDEN("05.111222000000") );
+  VERIFY( res == WIDEN("05.111222000") );
 }
 
 template<typename CharT>
@@ -162,23 +161,71 @@ test_S_int()
   auto d = floor<seconds>(src);
   res = std::format(WIDEN("{:%S}"), d);
   VERIFY( res == WIDEN("07") );
+  res = std::format(WIDEN("{:.0%S}"), d);
+  VERIFY( res == WIDEN("07") );
+  res = std::format(WIDEN("{:.3%S}"), d);
+  VERIFY( res == WIDEN("07.000") );
+  res = std::format(WIDEN("{:.6%S}"), d);
+  VERIFY( res == WIDEN("07.000000") );
+  res = std::format(WIDEN("{:.9%S}"), d);
+  VERIFY( res == WIDEN("07.000000000") );
+  res = std::format(WIDEN("{:.12%S}"), d);
+  VERIFY( res == WIDEN("07.000000000000") );
 
   auto md = floor<milliseconds>(src);
   res = std::format(WIDEN("{:%S}"), md);
   VERIFY( res == WIDEN("07.000") );
+  res = std::format(WIDEN("{:.3%S}"), md);
+  VERIFY( res == WIDEN("07.000") );
+  res = std::format(WIDEN("{:.6%S}"), md);
+  VERIFY( res == WIDEN("07.000000") );
+  res = std::format(WIDEN("{:.9%S}"), md);
+  VERIFY( res == WIDEN("07.000000000") );
+  res = std::format(WIDEN("{:.12%S}"), md);
+  VERIFY( res == WIDEN("07.000000000000") );
 
   auto ud = floor<microseconds>(src);
   res = std::format(WIDEN("{:%S}"), ud);
   VERIFY( res == WIDEN("07.000012") );
+  res = std::format(WIDEN("{:.0%S}"), ud);
+  VERIFY( res == WIDEN("07") );
+  res = std::format(WIDEN("{:.3%S}"), ud);
+  VERIFY( res == WIDEN("07.000") );
+  res = std::format(WIDEN("{:.6%S}"), ud);
+  VERIFY( res == WIDEN("07.000012") );
+  res = std::format(WIDEN("{:.9%S}"), ud);
+  VERIFY( res == WIDEN("07.000012000") );
+  res = std::format(WIDEN("{:.12%S}"), ud);
+  VERIFY( res == WIDEN("07.000012000000") );
 
   auto nd = floor<nanoseconds>(src);
   res = std::format(WIDEN("{:%S}"), nd);
   VERIFY( res == WIDEN("07.000012345") );
+  res = std::format(WIDEN("{:.0%S}"), nd);
+  VERIFY( res == WIDEN("07") );
+  res = std::format(WIDEN("{:.3%S}"), nd);
+  VERIFY( res == WIDEN("07.000") );
+  res = std::format(WIDEN("{:.6%S}"), nd);
+  VERIFY( res == WIDEN("07.000012") );
+  res = std::format(WIDEN("{:.9%S}"), nd);
+  VERIFY( res == WIDEN("07.000012345") );
+  res = std::format(WIDEN("{:.12%S}"), nd);
+  VERIFY( res == WIDEN("07.000012345000") );
 
   using picoseconds = duration<unsigned long long, std::pico>;
   auto pd = floor<picoseconds>(src);
   res = std::format(WIDEN("{:%S}"), pd);
   VERIFY( res == WIDEN("07.000012345000") );
+  res = std::format(WIDEN("{:.0%S}"), pd);
+  VERIFY( res == WIDEN("07") );
+  res = std::format(WIDEN("{:.3%S}"), pd);
+  VERIFY( res == WIDEN("07.000") );
+  res = std::format(WIDEN("{:.6%S}"), pd);
+  VERIFY( res == WIDEN("07.000012") );
+  res = std::format(WIDEN("{:.9%S}"), pd);
+  VERIFY( res == WIDEN("07.000012345") );
+  res = std::format(WIDEN("{:.12%S}"), pd);
+  VERIFY( res == WIDEN("07.000012345000") );
 }
 
 template<typename CharT>
-- 
2.49.0

Reply via email to