jgoenetxea
1/8/2020 - 8:30 AM

Manage chrono timestamps

Manage std::chrono::system_clock::time_point as timestamp

This text shows how to transform the system clock type to an integral type (long) and back. The original idea is extracted from a post written by Howard Hinnant in StackOverflow.

From time_point to long

using time_point = std::chrono::system_clock::time_point;
int64_t fromSystemTimePointToMillis(const time_point &_tp) {
    // Get the time_point with the precission of milliseconds
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(_tp);
    // Transform the reference epoch
    auto value = now_ms.time_since_epoch();
    // Get the time value from epoch in milliseconds
    int64_t ts_millis = value.count();

    return ts_millis;
}

From long to time_point

using time_point = std::chrono::system_clock::time_point;
time_point fromMillisToSystemTimePoint(const int64_t &_ts) {
//    system_clock::time_point dt{std::chrono::milliseconds{_ts}};
    // Define the integral _ts as millisecond value
    std::chrono::milliseconds dur(_ts);
    // Create a time_point object using the casted time
    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    return dt;
}

Serialize time_point using milliseconds

std::string serializeTimePoint(const time_point& _time,
                               const std::string& _format) {
    const std::time_t tt = std::chrono::system_clock::to_time_t(_time);

    const std::tm tm = *std::gmtime(&tt);  // GMT (UTC)
    std::stringstream ss;
    ss << std::put_time(&tm, _format.c_str());

    // Compute the milliseconds
    int64_t ts = fromSystemTimePointToMillis(_time);
    int64_t ts_tt = static_cast<int64_t>(tt) * 1000;
    int64_t millis = ts - ts_tt;
    std::string millis_str = std::to_string(millis);

    std::string ser = ss.str();
    // Replace the milliseconds format element (%Em)
    std::size_t pos;
    std::string millis_tag("%Em");
    std::size_t millis_tag_size = millis_tag.size();
    pos = ser.find(millis_tag, 0);
    while (pos != std::string::npos) {
        ser = ser.replace(pos, millis_tag_size, millis_str);
        pos = ser.find(millis_tag, pos);
    }

    return ser;
}

Final example

    auto input = std::chrono::high_resolution_clock::now();
    std::cout << serializeTimePoint(input, "UTC(original): %Y-%m-%d %H:%M:%S+%Em")
              << std::endl;

    long ts = fromTimePointToLongMillis(input);
    time_point tp = fromLongToTimePointMillis(ts);

    std::cout << serializeTimePoint(tp, "UTC(trans): %Y-%m-%d %H:%M:%S+%Em")
              << std::endl;

    return 0;
}