Hello,

chrono::system_clock provides a to_time_t[1] method to convert the time_point
into the std::time_t for the C interop and it is the only clock to provide
this functionality [2].

However, there's an issue with the implementation proposed in the standard:
the signature of the method is

    static time_t to_time_t  (const time_point& t) noexcept;

where the time_point has a concrete type
chrono::time_point<chrono::system_clock, chrono::duration<unspecified, unspecified>

On some (most) implementation, this duration has int64_t representation with nanoseconds as
a tick period. While this allows a very narrow range around the unix epoch - +/-292 years
it is normally not a problem since one can use different duration, and C++20 also includes
out of the box std::chrono::sys_seconds and std::chrono::sys_days.

Where the current implementation breaks is the fact that when one pass an instance of
std::chrono::sys_seconds to the std::chrono::system_clock::to_time_t that object gets implicitly
converted to the object of the std::chrono::system_clock::time_point, which although shares
the same clock and it has a higher precision, it has a much smaller range. This in turn
leads to the overflow at this intermediate step and the result of the function is wrong.

Here's the simple example:

  date::sys_days date = date::year(1500)/1/1; 
  time_t unix_time = std::chrono::system_clock::to_time_t(date);
  std::cout << "to_time_t: " << std::ctime(&unix_time); // Fri Jul 21 01:34:33 2084

While we can't guarantee much for this conversion because std::time_t is in the end
unspecified, we can use the best effort to minimize the error case. I propose to replace the
existing signature of the to_time_t with something akin to:

  template <typename TimePoint>
    static std::time_t
    to_time_t(const TimePoint& __t,
        typename std::enable_if<std::is_same<typename TP::clock, system_clock>::value>::type* = 0) noexcept

Since this doesn't specify the time_point's concrete type we will avoid the
implicit conversion and we'll simply cast __t.time_since_epoch() to seconds
in the possible implementation.

I believe this method is backward compatible and more permissive than the original one,
while still making the same guarantee - it shoudln't allow passing the time_points measured
on the clock different than the system one (since this clock is the only that map time points
into the C-style time.

While using the duration_cast to seconds and count() get the value and making sure that
the system clock is used, I see no reason why we don't improve the current function since
it's been advertied as the entry point for C-style time conversion.


Best,
Nemanja

[1] https://en.cppreference.com/w/cpp/chrono/system_clock/to_time_t
[2] https://en.cppreference.com/w/cpp/chrono/system_clock
[3] http://eel.is/c++draft/time.clock.system