C++ Logo

std-proposals

Advanced search

Re: chrono system_clock to_time_t/from_time_t unexpected integer overflow

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Thu, 7 Oct 2021 10:02:40 -0400
On Thu, Oct 7, 2021 at 8:05 AM Igor Ingultsov via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> Hello,
>
> recently I've stumbled upon an unexpected issue which is also not really documented (or am I wrong?).
>
> Consider the code:
>
> // time_t for year 2500
> time_t t = 16756675140; // which is ok on many systems as time_t is usually now 64bit
> auto tp = std::chrono::system_clock::from_time_t(t);
> std::cout << std::chrono::system_clock::to_time_t(tp);
>
> I would naively expect identity
> t == to_time_t(from_time_t(t));
>
> but what happens in reality is, time_t as seconds is being put into the time_point with resolution (on Linux/libstdc++) of nanoseconds, which has an upper limit of around Year 2262.

Because apparently this is the default duration for
`system_clock::time_point` in your implementation.

> Is there any reason, why there would be an implicit conversion from time_t to time_point with nanoseconds duration?
>
> As far as I know, time_t is everywhere the amount of seconds since epoch (and in C++20 anyway since 1970).
>
> The solution could be:
> std::system_clock::from_time_t should return time_point of the same resolution as time_t in current implementation.
>
> Problem ist however, there would be no guard against:
> time_point<seconds> ts = from_time_t(t);
> time_point<nanoseconds> tns = ts; // ok from perspective of time_point/duration cast, as we don't loose precision, but we could still silently loose resolution.
>
> Do you have any ideas how this could be changed?

The easiest way to solve this is to not use `from_time_t`.

This function was useful when the epoch for `system_clock` was not
defined and when you don't know the epoch for `time_t`. But since
C++20 defines `system_clock`'s epoch, and your code assumes that
`time_t` is a count in seconds from the same epoch, you no longer need
that function. You just need to do exactly what you *mean* to do: take
a time in seconds from the `system_clock`'s epoch and make a time
point out of it:

auto tp = std::chrono::sys_seconds(std::chrono::seconds(t));

Done.

If you want to avoid the assumption of `time_t`'s epoch, it's possible
that a template overload of `from_time_t` could be added which allows
you to specify the duration, rather than using `system_clock`'s
default duration.

Received on 2021-10-07 09:02:59