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.
Section: 29.11.8 [time.zone.leap] Status: C++20 Submitter: Asher Dunn Opened: 2019-12-16 Last modified: 2021-02-25
Priority: 3
View all issues with C++20 status.
Discussion:
class leap (which is expected to be renamed by P1981R0 to leap_second) defined in 29.11.8 [time.zone.leap] should include support for both positive leap seconds (23:59:60 added to UTC at a specified time) and negative leap seconds (23:59:59 removed from UTC at a specified time). While only positive leap seconds have been inserted to date, the definition of UTC allows for both.
Update 29.11.8 [time.zone.leap] to specify the value of leap seconds in addition to their insertion date, and update wording and examples in 29.7 [time.clock] and 29.12 [time.format] that involve leap seconds to account for both types of leap second.[2020-01 Priority set to 3 after review on the reflector.]
Previous resolution [SUPERSEDED]:This wording is relative to N4842.
Modify 29.7.3.2 [time.clock.utc.members] as indicated:
template<class Duration> static sys_time<common_type_t<Duration, seconds>> to_sys(const utc_time<Duration>& u);-2- Returns: A sys_time t, such that from_sys(t) == u if such a mapping exists. Otherwise u represents a time_point during a positive leap second insertion, the conversion counts that leap second as not inserted, and the last representable value of sys_time prior to the insertion of the leap second is returned.
template<class Duration> static utc_time<common_type_t<Duration, seconds>> from_sys(const sys_time<Duration>& t);-3- Returns: A utc_time u, such that u.time_since_epoch() - t.time_since_epoch() is equal to the
[…]numbersum of leap seconds that were inserted between t and 1970-01-01. If t is exactly the date of leap second insertion, then the conversion counts that leap second as inserted.Modify 29.7.3.3 [time.clock.utc.nonmembers] as indicated:
template<class Duration> leap_second_info get_leap_second_info(const utc_time<Duration>& ut);-6- Returns: A leap_second_info where is_leap_second is true if ut is during a positive leap second insertion, and otherwise false. elapsed is the
numbersum of leap seconds between 1970-01-01 and ut. If is_leap_second is true, the leap second referred to by ut is included in the count.Modify 29.7.4.1 [time.clock.tai.overview] as indicated:
-1- The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into TAI. Therefore every time a leap second is inserted into UTC, UTC
falls another second behindshifts another second with respect to TAI. For example by 2000-01-01 there had been 22 positive and 0 negative leap seconds inserted so 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the initial 10s offset).Modify 29.7.5.1 [time.clock.gps.overview] as indicated:
-1- The clock gps_clock measures seconds since the first Sunday of January, 1980 00:00:00 UTC. Leap seconds are not inserted into GPS. Therefore every time a leap second is inserted into UTC, UTC
falls another second behindshifts another second with respect to GPS. Aside from the offset from 1958y/January/1 to 1980y/January/Sunday[1], GPS is behind TAI by 19s due to the 10s offset between 1958 and 1970 and the additional 9 leap seconds inserted between 1970 and 1980.Modify 29.11.8.1 [time.zone.leap.overview] as indicated:
namespace std::chrono { class leap { public: leap(const leap&) = default; leap& operator=(const leap&) = default; // unspecified additional constructors constexpr sys_seconds date() const noexcept; constexpr seconds value() const noexcept; }; }-1- Objects of type leap representing the date and value of the leap second insertions are constructed and stored in the time zone database when initialized.
-2- [Example:for (auto& l : get_tzdb().leaps) if (l <= 2018y/March/17d) cout << l.date() << ": " << l.value() << '\n';Produces the output:
1972-07-01 00:00:00: 1s 1973-01-01 00:00:00: 1s 1974-01-01 00:00:00: 1s 1975-01-01 00:00:00: 1s 1976-01-01 00:00:00: 1s 1977-01-01 00:00:00: 1s 1978-01-01 00:00:00: 1s 1979-01-01 00:00:00: 1s 1980-01-01 00:00:00: 1s 1981-07-01 00:00:00: 1s 1982-07-01 00:00:00: 1s 1983-07-01 00:00:00: 1s 1985-07-01 00:00:00: 1s 1988-01-01 00:00:00: 1s 1990-01-01 00:00:00: 1s 1991-01-01 00:00:00: 1s 1992-07-01 00:00:00: 1s 1993-07-01 00:00:00: 1s 1994-07-01 00:00:00: 1s 1996-01-01 00:00:00: 1s 1997-07-01 00:00:00: 1s 1999-01-01 00:00:00: 1s 2006-01-01 00:00:00: 1s 2009-01-01 00:00:00: 1s 2012-07-01 00:00:00: 1s 2015-07-01 00:00:00: 1s 2017-01-01 00:00:00: 1s— end example]
Modify 29.11.8.2 [time.zone.leap.members] as indicated:
constexpr sys_seconds date() const noexcept;-1- Returns: The date and time at which the leap second was inserted.
constexpr seconds value() const noexcept;-?- Returns: The value of the leap second. Always +1s to indicate a positive leap second or -1s to indicate a negative leap second. All leap seconds inserted up through 2017 were positive leap seconds.
Modify 29.12 [time.format] as indicated:
template<class Duration, class charT> struct formatter<chrono::utc_time<Duration>, charT>;-7- Remarks: If %Z is used, it is replaced with STATICALLY-WIDEN<charT>("UTC"). If %z (or a modified variant of %z) is used, an offset of 0min is formatted. If the argument represents a time during a positive leap second insertion, and if a seconds field is formatted, the integral portion of that format is STATICALLY-WIDEN<charT>("60").
[2020-02-14; Prague]
LWG Review. Some wording improvements have been made and lead to revised wording.
Proposed resolution:
This wording is relative to N4849.
Modify 29.7.3.2 [time.clock.utc.members] as indicated:
template<class Duration> static sys_time<common_type_t<Duration, seconds>> to_sys(const utc_time<Duration>& u);-2- Returns: A sys_time t, such that from_sys(t) == u if such a mapping exists. Otherwise u represents a time_point during a positive leap second insertion, the conversion counts that leap second as not inserted, and the last representable value of sys_time prior to the insertion of the leap second is returned.
template<class Duration> static utc_time<common_type_t<Duration, seconds>> from_sys(const sys_time<Duration>& t);-3- Returns: A utc_time u, such that u.time_since_epoch() - t.time_since_epoch() is equal to the
[…]numbersum of leap seconds that were inserted between t and 1970-01-01. If t is exactly the date of leap second insertion, then the conversion counts that leap second as inserted.
Modify 29.7.3.3 [time.clock.utc.nonmembers] as indicated:
template<class Duration> leap_second_info get_leap_second_info(const utc_time<Duration>& ut);-6- Returns: A leap_second_info, lsi, where lsi.is_leap_second is true if ut is during a positive leap second insertion, and otherwise false. lsi.elapsed is the
numbersum of leap seconds between 1970-01-01 and ut. If lsi.is_leap_second is true, the leap second referred to by ut is included in thecountsum.
Modify 29.7.4.1 [time.clock.tai.overview] as indicated:
-1- The clock tai_clock measures seconds since 1958-01-01 00:00:00 and is offset 10s ahead of UTC at this date. That is, 1958-01-01 00:00:00 TAI is equivalent to 1957-12-31 23:59:50 UTC. Leap seconds are not inserted into TAI. Therefore every time a leap second is inserted into UTC, UTC
falls another second behindshifts another second with respect to TAI. For example by 2000-01-01 there had been 22 positive and 0 negative leap seconds inserted so 2000-01-01 00:00:00 UTC is equivalent to 2000-01-01 00:00:32 TAI (22s plus the initial 10s offset).
Modify 29.7.5.1 [time.clock.gps.overview] as indicated:
-1- The clock gps_clock measures seconds since the first Sunday of January, 1980 00:00:00 UTC. Leap seconds are not inserted into GPS. Therefore every time a leap second is inserted into UTC, UTC
falls another second behindshifts another second with respect to GPS. Aside from the offset from 1958y/January/1 to 1980y/January/Sunday[1], GPS is behind TAI by 19s due to the 10s offset between 1958 and 1970 and the additional 9 leap seconds inserted between 1970 and 1980.
Modify 29.11.8.1 [time.zone.leap.overview] as indicated:
namespace std::chrono { class leap { public: leap(const leap&) = default; leap& operator=(const leap&) = default; // unspecified additional constructors constexpr sys_seconds date() const noexcept; constexpr seconds value() const noexcept; }; }-1- Objects of type leap representing the date and value of the leap second insertions are constructed and stored in the time zone database when initialized.
-2- [Example:for (auto& l : get_tzdb().leaps) if (l <= 2018y/March/17d) cout << l.date() << ": " << l.value() << '\n';Produces the output:
1972-07-01 00:00:00: 1s 1973-01-01 00:00:00: 1s 1974-01-01 00:00:00: 1s 1975-01-01 00:00:00: 1s 1976-01-01 00:00:00: 1s 1977-01-01 00:00:00: 1s 1978-01-01 00:00:00: 1s 1979-01-01 00:00:00: 1s 1980-01-01 00:00:00: 1s 1981-07-01 00:00:00: 1s 1982-07-01 00:00:00: 1s 1983-07-01 00:00:00: 1s 1985-07-01 00:00:00: 1s 1988-01-01 00:00:00: 1s 1990-01-01 00:00:00: 1s 1991-01-01 00:00:00: 1s 1992-07-01 00:00:00: 1s 1993-07-01 00:00:00: 1s 1994-07-01 00:00:00: 1s 1996-01-01 00:00:00: 1s 1997-07-01 00:00:00: 1s 1999-01-01 00:00:00: 1s 2006-01-01 00:00:00: 1s 2009-01-01 00:00:00: 1s 2012-07-01 00:00:00: 1s 2015-07-01 00:00:00: 1s 2017-01-01 00:00:00: 1s— end example]
Modify 29.11.8.2 [time.zone.leap.members] as indicated:
constexpr sys_seconds date() const noexcept;-1- Returns: The date and time at which the leap second was inserted.
constexpr seconds value() const noexcept;-?- Returns: +1s to indicate a positive leap second or -1s to indicate a negative leap second. [Note: All leap seconds inserted up through 2019 were positive leap seconds. — end note]
Modify 29.12 [time.format] as indicated:
template<class Duration, class charT> struct formatter<chrono::utc_time<Duration>, charT>;-7- Remarks: If %Z is used, it is replaced with STATICALLY-WIDEN<charT>("UTC"). If %z (or a modified variant of %z) is used, an offset of 0min is formatted. If the argument represents a time during a positive leap second insertion, and if a seconds field is formatted, the integral portion of that format is STATICALLY-WIDEN<charT>("60").