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

3272. %I%p should parse/format duration since midnight

Section: 29.12 [time.format], 29.13 [time.parse] Status: C++20 Submitter: Howard Hinnant Opened: 2019-09-02 Last modified: 2021-02-25

Priority: 0

View other active issues in [time.format].

View all other issues in [time.format].

View all issues with C++20 status.

Discussion:

It is clear how "%I%p" parses and formats time points. What is not clear is how these flags interact with durations. We should treat durations as "elapsed time since midnight". For example:

#include <chrono>
#include <iostream>
#include <string>
#include <sstream>

int main()
{
  using namespace std;
  using namespace std::chrono;
  // Format
  {
    // format time_point with %I%p
    cout << format("{:%F %I%p}", sys_days{2019_y/August/10}+14h) << '\n';
  }
  {
    // format duration with %I%p
    cout << format("{:%I%p}", 14h) << '\n';
  }

  // Parse
  {
    // Parse %I%p as day-of-year combined with an hour into a time_point
    istringstream in{"2019-08-10 2pm"};
    system_clock::time_point tp;
    in >> parse("%F %I%p", tp);
    cout << tp << '\n';
  }
  {
    // Parse %I%p as number of hours into a duration
    istringstream in{"2pm"};
    hours d;
    in >> parse("%I%p", d);
    cout << d << '\n';
  }
}

Output:

2019-08-10 02PM
02PM
2019-08-10 14:00:00.000000
14h

[2019-10 Status set to 'Tentatively Ready' after reflector discussion]

Proposed resolution:

This wording is relative to N4830.

  1. Modify 29.12 [time.format] as indicated:

    -3- Unless explicitly requested, the result of formatting a chrono type does not contain time zone abbreviation and time zone offset information. If the information is available, the conversion specifiers %Z and %z will format this information (respectively). [Note: If the information is not available and a %Z or %z conversion specifier appears in the chrono-format-spec, an exception of type format_error is thrown, as described above. — end note]

    -?- If the type being formatted does not contain the information that the format flag needs, an exception of type format_error is thrown. [Example: A duration does not contain enough information to format as a weekdayend example]. However if a flag refers to a "time of day" (e.g. %H, %I, %p, etc.), then a specialization of duration is interpreted as the time of day elapsed since midnight.

  2. Modify 29.13 [time.parse] as indicated:

    [Drafting note: The modification of 29.13 [time.parse] p1 is intended to be non-conflictingly mergeable with the change suggested by LWG 3269(i) and LWG 3271(i) at the same paragraph.]

    -1- Each parse overload specified in this subclause calls from_stream unqualified, so as to enable argument dependent lookup (6.5.4 [basic.lookup.argdep]). In the following paragraphs, let is denote an object of type basic_istream<charT, traits>, where charT and traits are template parameters in that context.

    […]

    -10- All from_stream overloads behave as unformatted input functions, except that they have an unspecified effect on the value returned by subsequent calls to basic_istream<>::gcount(). Each overload takes a format string containing ordinary characters and flags which have special meaning. Each flag begins with a %. Some flags can be modified by E or O. During parsing each flag interprets characters as parts of date and time types according to Table [tab:time.parse.spec]. Some flags can be modified by a width parameter given as a positive decimal integer called out as N below which governs how many characters are parsed from the stream in interpreting the flag. All characters in the format string that are not represented in Table [tab:time.parse.spec], except for white space, are parsed unchanged from the stream. A white space character matches zero or more white space characters in the input stream.

    -?- If the type being parsed can not represent the information that the format flag refers to, is.setstate(ios_base::failbit) is called. [Example: A duration cannot represent a weekdayend example]. However if a flag refers to a "time of day" (e.g. %H, %I, %p, etc.), then a specialization of duration is parsed as the time of day elapsed since midnight.