This is a collection of minor fixes and upgrades to the <chrono>
library that have come to my attention since the acceptance of
P0355r7.
Feedback from the field asks for a way to identify if a
utc_time
represents a leap second. This proposed API is the only API that has field experience in providing that information in a way that is efficient, and provides all information the client desires when making a query in this area. It is used in the implementation of the conversion betweenutc_time
andsys_time
, and in the parsing and formatting ofutc_time
, so is likely to be present in any event. If we choose to specify it, it can be spelled without underscores, and be available to clients of<chrono>
.
Insert into the synopsis 26.2 Header <chrono>
synopsis [time.syn]:
struct leap_second_info; template <class Duration> leap_second_info get_leap_second_info(utc_time<Duration> const& ut);
Insert new paragraphs in 26.7.2.3 Non-member functions [time.clock.utc.nonmembers]:
struct leap_second_info { bool is_leap_second; seconds elapsed; };The type
leap_second_info
has data members, and special members specified above. It has no base classes or members other than those specified.template <class Duration> leap_second_info get_leap_second_info(utc_time<Duration> const& ut);Returns: A
leap_second_info
whereis_leap_second
is true ifut
is during a leap second insertion, and otherwise false.elapsed
is the number of leap seconds between 1970-01-01 andut
. Ifis_leap_second
is true, the leap second referred to byut
is included in the count.
Feedback from the field asks for a way to customize the spacing between a duration's value and its unit (e.g. supply a space, or a Unicode custom space between the value and the unit). This item proposes
%Q
to represent the durations's value and%q
to represent the duration's unit, for formatting only. Example:format("%Q %q", 45ms) == "45 ms"
.
Add two new rows to Table 87 — Meaning of format
conversion
specifiers:
%Q
The duration's numeric value (as if extracted via .count()
).%q
The duration's unit suffix as specified in [time.duration.io].
About half of the clients are upset that the currently specified encoding for
weekday
implies that Sunday is the first day of the week (consistent with the current C and C++ specifications fortm.tm_wday
), and the other half of the clients will be upset if theweekday
encoding follows the ISO specification of [1, 7] maps to [Monday, Sunday].This change strikes a compromise in an attempt to please everyone (a nearly impossible task).
The
weekday{unsigned}
constructor accepts both mappings, which means that [0, 6] maps to [Sunday, Saturday] and [1, 7] maps to [Monday, Sunday]. This is possible by simply accepting [0, 7] where [1, 6] maps to [Monday, Saturday] and both 0 and 7 map to Sunday.The explicit conversion to
unsigned
is removed fromweekday
and named conversions are inserted in its place:c_encoding()
andiso_encoding()
. The client can choose which mapping fromweekday
tounsigned
he desires by choosing one of these member functions.
Modify 26.8.6.2 [time.cal.wd.members] as indicated:
constexpr explicit weekday(unsigned wd) noexcept;Effects: Constructs an object of type
weekday
by initializingwd_
withwd
, except ifwd_ == 7
, stores0
. The value held is unspecified if wd is not in the range [0, 255].constexpr explicit operator unsigned() const noexcept;
Returns:wd_
.constexpr unsigned c_encoding() const noexcept;Returns:
wd_
.constexpr unsigned iso_encoding() const noexcept;Returns:
wd_ == 0u ? 7u : wd_
.
time_of_day
is poorly specified. It suffers from an overly complicated specification, and at the same time, insufficient functionality from that specification. Additionally, guidance from the LEWG mailing list indicates significant dissatisfaction with the name oftime_of_day
and its internal state that changes mode between 24h and 12h time. This note changes the name oftime_of_day
tohh_mm_ss
to bring the semantics away from holding just a time duration since midnight, and more towards holding any duration as an{hours, minutes, seconds, subseconds}
data structure. Also the 24h/12h functionality is moved out of this structure and into namespace-scope functions. And finally this change both simplifies the specification while providing more pertinent functionality. However the basic functionality is maintained:hh_mm_ss
is an{hours, minutes, seconds, subseconds}
structure which easily converts to and from aduration
and provides easy formatting.
Modify 26.1 General [time.general]
Table 85 — Time library summary Subclause Header(s) ... 26.8 Civil calendar 26.9 Class template time_of_day
hh_mm_ss
26.10 12/24 hour functions 26.1026.11Time zones ... Modify 26.2 Header
<chrono>
synopsis [time.syn]... // 26.9, class templatetime_of_dayhh_mm_ss template <class Duration> classtime_of_dayhh_mm_ss;template<> class time_of_day<hours>;template<> class time_of_day<minutes>;template<> class time_of_day<seconds>;template<class Rep, class Period> class time_of_day<duration<Rep, Period>>;template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const time_of_day<hours>& t); template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const time_of_day<minutes>& t); template<class charT, class traits> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const time_of_day<seconds>& t);template<class charT, class traits, classRep, class PeriodDuration> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, consttime_of_dayhh_mm_ss<Dduration<Rep, Period>>& t); // 26.10, 12/24 hour functions constexpr bool is_am(hours const& h) noexcept; constexpr bool is_pm(hours const& h) noexcept; constexpr hours make12(hours h) noexcept; constexpr hours make24(hours h, bool is_pm) noexcept; ...Modify 26.7.1.3 Non-member functions [time.clock.system.nonmembers]
Effects:
...
os << year_month_day{dp} << ' ' <<time_of_dayhh_mm_ss{tp-dp};Replace [time.tod] with [time.hms]:
26.9 Class template
hh_mm_ss
[time.hms]26.9.1 Overview [time.hms.overview]
template <class Duration> class hh_mm_ss { bool is_neg; // exposition only chrono::hours h; // exposition only chrono::minutes m; // exposition only chrono::seconds s; // exposition only precision ss; // exposition only public: static unsigned constexpr fractional_width = see below; using precision = see below; constexpr hh_mm_ss() noexcept : hh_mm_ss{Duration::zero()} {} constexpr explicit hh_mm_ss(Duration d) noexcept; constexpr bool is_negative() const noexcept; constexpr chrono::hours hours() const noexcept; constexpr chrono::minutes minutes() const noexcept; constexpr chrono::seconds seconds() const noexcept; constexpr precision subseconds() const noexcept; constexpr explicit operator precision() const noexcept; constexpr precision to_duration() const noexcept; }; template <class charT, class traits, class Duration> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, hh_mm_ss<Duration> const& hms);The
hh_mm_ss
class template splits a duration into a “broken down” time hours:minutes:seconds and possibly subseconds, where subseconds will be aduration
unit based on a negative power of 10. TheDuration
template parameter dictates the precision to which the time is broken down. Ahh_mm_ss
models negative durations with a distinctis_negative
getter that returnstrue
when the input duration is negative. The individual duration fields always return non-negative durations even whenis_negative()
indicates the structure is representing a negative duration.If
Duration
is not an instance ofduration
, the program is ill-formed.26.9.2 Members [time.hms.members]
static unsigned constexpr fractional_width = see below;
fractional_width
is the number of fractional decimal digits represented byprecision
.fractional_width
has the value of the smallest possible integer in the range [0, 18] such thatprecision
will exactly represent all values ofDuration
. If no such value offractional_width
exists, thenfractional_width
is 6.[Example:
Duration
fractional_width
Formatted fractional second
output ofDuration{1}
hours
,minutes
, andseconds
0
milliseconds
3
.001 microseconds
6
.000001 nanoseconds
9
.000000001 duration<int, ratio<1, 2>>
1
.5 duration<int, ratio<1, 3>>
6
.333333 duration<int, ratio<1, 4>>
2
.25 duration<int, ratio<1, 5>>
1
.2 duration<int, ratio<1, 6>>
6
.166666 duration<int, ratio<1, 7>>
6
.142857 duration<int, ratio<1, 8>>
3
.125 duration<int, ratio<1, 9>>
6
.111111 duration<int, ratio<1, 10>>
1
.1 duration<int, ratio<756, 625>> //
microfortnights4
.2096 — end example]
using precision = see below;
precision
isduration<common_type_t<Duration::rep, seconds::rep>, ratio<1, 10fractional_width>>
.constexpr explicit hh_mm_ss(Duration d) noexcept;Effects: constructs an object of type
hh_mm_ss
which represents theDuration d
with precisionprecision
. Thehours
,minutes
,seconds
andsubseconds
are stored. Also stored is the fact ifd
is negative or non-negative.Stores
d < Duration::zero()
inis_neg
.Stores
duration_cast<chrono::hours>(abs(d))
inh
.Stores
duration_cast<chrono::minutes>(abs(d) - hours())
inm
.Stores
duration_cast<chrono::seconds>(abs(d) - hours() - minutes())
ins
.If
treat_as_floating_point_v<precision::rep>
istrue
, storesabs(d) - hours() - minutes() - seconds()
inss
. Else storesduration_cast<precision>(abs(d) - hours() - minutes() - seconds())
inss
. [Note: Whenprecision
isseconds
with integral representation,subseconds()
always returns0s
— end note]Ensures: If
treat_as_floating_point_v<precision::rep>
istrue
,to_duration()
returnsd
, elseto_duration()
returnsfloor<precision>(d)
.constexpr bool is_negative() const noexcept;Returns:
is_neg
.constexpr chrono::hours hours() const noexcept;Returns:
h
.constexpr chrono::minutes minutes() const noexcept;Returns:
m
.constexpr chrono::seconds seconds() const noexcept;Returns:
s
.constexpr precision subseconds() const noexcept;Returns:
ss
.constexpr precision to_duration() const noexcept;Returns: If
is_neg
, returns-(h + m + s + ss)
, else returnsh + m + s + ss
.constexpr explicit operator precision() const noexcept;Returns:
to_duration()
.26.9.3 Non-members [time.hms.nonmembers]
template <class charT, class traits, class Duration> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, hh_mm_ss<Duration> const& hms);Effects: Outputs to
os
according to the format"%T"
([time.format]). Ifhms.is_negative()
, the output is preceded with'-'
.Returns:
os
.[Example:
for (auto ms : {-4083007ms, 4083007ms, 65745123ms}) { hh_mm_ss hms{ms}; cout << hms << '\n'; } cout << hh_mm_ss{65745s} << '\n';Produces the output (assuming the "C" locale):
-01:08:03.007 01:08:03.007 18:15:45.123 18:15:45— end example]
Insert a new section, 26.10 12/24 hour functions [time.12]:
26.10 12/24 hour functions [time.12]
These functions aid in translating between a 12h format time of day, and a 24h format time of day.
constexpr bool is_am(hours const& h) noexcept;Returns:
0h <= h && h <= 11h
.constexpr bool is_pm(hours const& h) noexcept;Returns:
12h <= h && h <= 23h
.constexpr hours make12(hours h) noexcept;Returns: The 12-hour equivalent of
h
in the range[1h, 12h]
. Ifh
is not in the range[0h, 23h]
, the value returned is unspecified.constexpr hours make24(hours h, bool is_pm) noexcept;Returns: If
is_pm
isfalse
, returns the 24-hour equivalent ofh
in the range[0h, 11h]
, assumingh
represents an ante meridiem hour. Else returns the 24-hour equivalent ofh
in the range[12h, 23h]
, assumingh
represents a post meridiem hour. Ifh
is not in the range[1h, 12h]
, the value returned is unspecified.