This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.

### 3536. Should `chrono::from_stream()` assign zero to `duration` for failure?

Section: 29.5.11 [time.duration.io] Status: WP Submitter: Matt Stephanson Opened: 2021-03-19 Last modified: 2021-06-07

Priority: Not Prioritized

View all other issues in [time.duration.io].

View all issues with WP status.

Discussion:

The `duration` specialization of `from_stream` says in N4878 29.5.11 [time.duration.io]/3:

> If the parse parses everything specified by the parsing format flags without error, and yet none of the flags impacts a duration, `d` will be assigned a zero value.

This is in contrast to the other specializations that say, for example, 29.8.3.3 [time.cal.day.nonmembers]/8:

> If the parse fails to decode a valid day, `is.setstate(ios_base::failbit)` is called and `d` is not modified.

The wording ("none of the flags impacts a duration" vs. "parse fails to decode a valid [meow]") and semantics ("assigned a zero value" vs. "not modified") are different, and it's not clear why that should be so. It also leaves unspecified what should be done in case of a parse failure, for example parsing `"%j"` from a stream containing `"meow"`. 29.13 [time.parse]/12 says that `failbit` should be set, but neither it nor 29.5.11 [time.duration.io]/3 mention the `duration` result if parsing fails.

This has been discussed at the Microsoft STL project, where Howard Hinnant, coauthor of P0355R7 that added these functions, commented:

> This looks like a bug in the standard to me, due to two errors on my part.

> I believe that the standard should clearly say that if `failbit` is set, the parsed variable (`duration`, `time_point`, whatever) is not modified. I mistakenly believed that the definition of unformatted input function covered this behavior. But after review, I don't believe it does. Instead each extraction operator seems to say this separately.

> I also at first did not have my example implementation coded to leave the duration unchanged. So that's how the wording got in in the first place. Here's the commit where I fixed my implementation: HowardHinnant/date@d53db7a. And I failed to propagate that fix into the proposal/standard.

It would be clearer and simpler for users if the `from_stream` specializations were consistent in wording and behavior.

Thanks to Stephan T. Lavavej, Miya Natsuhara, and Howard Hinnant for valuable investigation and discussion of this issue.

[2021-04-20; Reflector poll]

Set status to Tentatively Ready after eight votes in favour during reflector poll.

[2021-06-07 Approved at June 2021 virtual plenary. Status changed: Voting → WP.]

Proposed resolution:

This wording is relative to N4878.

1. Modify 29.5.11 [time.duration.io] as indicated:

   >     template<class charT, class traits, class Rep, class Period, class Alloc = allocator<charT>>
   >       basic_istream<charT, traits>&
   >         from_stream(basic_istream<charT, traits>& is, const charT* fmt,
   >                     duration<Rep, Period>& d,
   >                     basic_string<charT, traits, Alloc>* abbrev = nullptr,
   >                     minutes* offset = nullptr);

   > > -3- Effects: Attempts to parse the input stream `is` into the duration `d` using the format flags given in the NTCTS `fmt` as specified in 29.13 [time.parse]. If the parse parses everything specified by the parsing format flags without error, and yet none of the flags impacts a duration, `d` will be assigned a zero value If the parse fails to decode a valid duration, `is.setstate(ios_base::failbit)` is called and `d` is not modified. If `%Z` is used and successfully parsed, that value will be assigned to `*abbrev` if `abbrev` is non-null. If `%z` (or a modified variant) is used and successfully parsed, that value will be assigned to `*offset` if `offset` is non-null.