Search code examples
c++c++-chrono

std::chrono::system_clock and C time


I am using the following time point definition universally in my project:

using time_point = std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long, std::ratio<1,1000>>>

With this definition I get a reasonable tradeoff between precision and range, unfortunately the default with nanosecond resolution gives me a too short range.

Unfortunately it seems I can not use the chrono::system_clock::from_time_t() and chrono::system_clock::to_time_t functions to convert between std::time_t and the time point with non default resolution. Is there a way I can use the to_time_t and from_time_t functions with "my" time_point class?


Solution

  • If you assume that std::chrono::system_clock has the same epoch as time_t (it usually does) then to_time_t and from_time_t are essentially just a std::duration_cast.

    For example this code should print the same values twice (note that whether to_time_t rounds or truncates is unspecified and duration_cast always truncates so there might be a 1 second difference):

    const auto now = std::chrono::system_clock::now();
    time_t time = std::chrono::system_clock::to_time_t(now);
    std::cout << time << "\n";
    std::cout << std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() << "\n";
    std::cout << std::chrono::system_clock::from_time_t(time).time_since_epoch().count() << "\n";
    std::cout << std::chrono::system_clock::time_point(std::chrono::seconds(time)).time_since_epoch().count() << "\n";
    

    You can therefore write your own to/from_time_t functions fairly easily:

    constexpr time_point  my_point_from_time_t(time_t value)
    {
        return time_point(std::chrono::seconds(value));
    }
    
    constexpr time_t my_point_to_time_t(const time_point & value)
    {
        return std::chrono::duration_cast<std::chrono::seconds>(value.time_since_epoch()).count();
    }
    

    If system_clock doesn't use the same epoch as time_t then you can simply adjust the values:

    const time_t system_clock_epoch = std::chrono::system_clock::to_time_t({});
    
    time_point  my_point_from_time_t(time_t value)
    {
        return time_point(std::chrono::seconds(value - system_clock_epoch));
    }
    
    time_t my_point_to_time_t(const time_point & value)
    {
        return std::chrono::duration_cast<std::chrono::seconds>(value.time_since_epoch()).count() + system_clock_epoch;
    }