zoned_time
with resolution coarser than secondsSection: 30.12 [time.format] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2024-07-26 Last modified: 2024-08-02
Priority: Not Prioritized
View other active issues in [time.format].
View all other issues in [time.format].
View all issues with Tentatively Ready status.
Discussion:
The
std::formatter<std::chrono::zoned_time<Duration, TimeZonePtr>>
specialization calls tp.get_local_time()
for the object it passes to its
base class' format
function. But get_local_time()
does not return a
local_time<Duration>
, it returns
local_time<common_type_t<Duration, seconds>>
.
The base class' format
function is only defined for
local_time<Duration>
.
That means this is ill-formed, even though the static assert passes:
using namespace std::chrono;
static_assert( std::formattable<zoned_time<minutes>, char> );
zoned_time<minutes> zt;
(void) std::format("{}", zt); // error: cannot convert local_time<seconds> to local_time<minutes>
Additionally, it's not specified what output you should get for:
std::format("{}", local_time_format(zt.get_local_time()));
30.12 [time.format] p7 says it's formatted as if by streaming to an
ostringstream
,
but there is no operator<<
for local-time-format-t
.
Presumably it should give the same result as operator<<
for
a zoned_time
, i.e. "{:L%F %T %Z}"
with padding adjustments etc.
The proposed resolution below has been implemented in libstdc++.
[2024-08-02; Reflector poll]
Set status to Tentatively Ready after seven votes in favour during reflector poll.
Proposed resolution:
This wording is relative to N4986.
Modify 30.12 [time.format] as indicated:
template<classDuration, class charT> struct formatter<chrono::local-time-format-t<Duration>, charT>;-17- Let
f
be alocale-time-format-t<Duration>
object passed toformatter::format
.-18- Remarks: If the chrono-specs is omitted, the result is equivalent to using
%F %T %Z
as the chrono-specs. If%Z
is used, it is replaced with*f.abbrev
iff.abbrev
is not a null pointer value. If%Z
is used andf.abbrev
is a null pointer value, an exception of typeformat_error
is thrown. If%z
(or a modified variant of%z
) is used, it is formatted with the value of*f.offset_sec
iff.offset_sec
is not a null pointer value. If%z
(or a modified variant of%z
) is used andf.offset_sec
is a null pointer value, then an exception of typeformat_error
is thrown.template<class Duration, class TimeZonePtr, class charT> struct formatter<chrono::zoned_time<Duration, TimeZonePtr>, charT> : formatter<chrono::local-time-format-t<common_type_t<Duration, seconds>>, charT> { template<class FormatContext> typename FormatContext::iterator format(const chrono::zoned_time<Duration, TimeZonePtr>& tp, FormatContext& ctx) const; };template<class FormatContext> typename FormatContext::iterator format(const chrono::zoned_time<Duration, TimeZonePtr>& tp, FormatContext& ctx) const;-19- Effects: Equivalent to:
sys_info info = tp.get_info(); return formatter<chrono::local-time-format-t<common_type_t<Duration, seconds>>, charT>:: format({tp.get_local_time(), &info.abbrev, &info.offset}, ctx);