Search code examples
c++c++11timesemanticsstd

Why does std::chrono::time_point not behave as expected?


#include <chrono>

int main()
{
    using clock = std::chrono::system_clock;
    using time_point = std::chrono::time_point<clock>;

    auto tp_now = clock::now();
    auto tp_min = time_point::min();

    bool b1 = tp_now > tp_min;
    bool b2 = (tp_now - tp_min) > std::chrono::seconds{ 0 };
    cout << boolalpha << b1 << endl << b2 << endl;
}

The expected output is:

true

true

But the actual output is:

true

false

Why does std::chrono::time_point not behave as expected?


Solution

  • With:

    using clock = std::chrono::system_clock;
    using time_point = std::chrono::time_point<clock>;
    

    time_point is implemented as if it stores a value of type Duration indicating the time interval from the start of the Clock's epoch. (See std::chrono::time_point)

    The duration member type of clock (and of time_point) is capable of representing negative durations.

    Thus duration in your implementation may be implemented with a back-end signed integer, (it can be implemented with unsigned integer but with a complicated comparison).

    In that particular implementation,

    time_point::min();
    time_point t(clock::duration::min());
    time_point t(clock::duration(std::numeric_limits<Rep>::lowest()));
    

    and tp_now is greater than zero, thus when you subtract them, you get an integer overflow because the result is larger than std::numeric_limits<Rep>::max(). In implementation with signed back-end, it's undefined behavior, in implementation with unsigned back-end, I don't know about it, but I guess its special comparison will make its false.

    In this example, tp_min is -9223372036854775808 ticks from its epoch, that number is the same with std::numeric_limits<duration::rep>::lowest()


    TL;DR; It's integer overflow. Don't use

    (tp1 - tp2) > std::chrono::duration<whatever_rep>::zero
    

    Instead, use

    tp1 > tp2