Search code examples
c++datetimec++11stdc++-chrono

Error in comparing two std::chrono::time_point instances


I have two std::chrono::time_point instances in variables exp and time. exp has a time in the future and time is the current time. But when I compare them as in this snippet:

std::time_t t_exp = std::chrono::system_clock::to_time_t(exp);
std::time_t t_time = std::chrono::system_clock::to_time_t(time);
std::cout << std::ctime(&t_exp) << std::ctime(&t_time) << (time > exp) << std::endl;

I get output:

Sat Apr 26 01:39:43 4758
Fri May 29 18:11:59 2020
1

Which is wrong because exp is in the year 4758 and time is in the year 2020.

Where am I going wrong?


Solution

  • t_exp is -4243023785

    This value of time_t corresponds to 1835-07-18 22:16:55 (assuming the Unix epoch and a precision of seconds, neither of which are specified by the standard, but are common).

    Apparently the implementation of ctime on your platform can't handle dates this far in the past, which is a little surprising as 1835 is not very far in the past.

    The value of exp is -4243023785 times a million or a billion (depending on the precision of system_clock on your platform) and is stored with a signed 64 bit integer (there is no overflow). Thus time > exp == 1 is correct (time is 1590775919s converted to the precision of system_clock).

    Sat Apr 26 01:39:43 4758 corresponds to a time_t of 87990716383.

    I see nothing wrong with your use of the chrono library in the above code.

    Update

    The value 87990716383 is being converted to a time_point using from_time_t()

    Ah, this combined with the knowledge that on your platform the precision of system_clock is nanoseconds tells me that you are experiencing overflow on the construction of exp.

    This is not the code you have:

    std::time_t t_exp = std::chrono::system_clock::to_time_t(exp);
    std::time_t t_time = std::chrono::system_clock::to_time_t(time);
    std::cout << std::ctime(&t_exp) << std::ctime(&t_time) << (time > exp) << std::endl;
    

    The code you have looks something like:

    // ...
    std::time_t t_exp = 87990716383;
    auto exp = std::chrono::system_clock::from_time_t(t_exp);
    std::cout << std::ctime(&t_exp) << std::ctime(&t_time) << (time > exp) << std::endl;
    

    On your platform, system_clock stores nanoseconds since 1970-01-01 00:00:00 UTC in a signed 64 bit integer. The maximum storable date (system_clock::time_point::max()) on your platform is:

    2262-04-11 23:47:16.854775807
    

    Beyond this, the underlying storage of nanoseconds overflows.

    When 87990716383 (seconds) is converted in from_time_t, it is multiplied by a billion which overflows. The overflowed value is -4243003985547758080 which corresponds to the date 1835-07-19 03:46:54.452241920.

    You can get a larger range by using a coarser precision, for example:

    std::time_t t_exp = 87990716383;
    time_point<system_clock, microseconds> exp{seconds{t_exp}};
    // exp == 4758-04-26 01:39:43.000000