user997112
user997112

Reputation: 30605

C++ print chrono::time_point<chrono::high_resolution_clock> to be readable

I have the number of nanoseconds since Epoch and I'd like to print this to be readable.

The examples I found online printing time_point were using system_clock and then converting to a std::time_t. However, I am using high_resolution_clock (because of the nanoseconds), hence struggling to understand how I can print this.

What is the best technique, given I am dealing with nanoseconds? I'd prefer to stick with standard libraries if possible.

I'm stuck with C++17 for now, but please do mention if C++20 makes this much easier to do.

#include <chrono>
#include <iostream>

using Clock = std::chrono::high_resolution_clock;
using TimePoint = std::chrono::time_point<Clock>;

int main()
{
    const uint64_t nanosSinceEpoch = 1517812763001883383;
    const Clock::duration duration_ns_since_epoch = std::chrono::nanoseconds(nanosSinceEpoch);

    const TimePoint tp(duration_ns_since_epoch);

    // Would like to print tp in readable format
}

Upvotes: 4

Views: 2337

Answers (1)

Howard Hinnant
Howard Hinnant

Reputation: 218700

high_resolution_clock does not have a portable epoch. It might be 1970. It might be whenever your device booted up. Thus when printing its time_point, the best that can be done is to print the underlying duration.

system_clock can represent nanoseconds even if system_clock::time_point does not. The trick is to use the more generic form of time_point which is:

template <class Clock, class Duration>
class time_point;

You can specify a clock and a duration, for example:

time_point<system_clock, nanoseconds> tp;

I like to set up a templated type-alias to do this:

template <class Duration>
    using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;

And now I can use this simpler syntax:

sys_time<nanoseconds> tp;

In C++20, sys_time is provided for you by <chrono>. And C++20 allows you to simply print out system_clock-based time_points.

Unfortunately I don't believe anyone is shipping this part of C++20 yet. However there's a header-only, open source, free preview of C++20 <chrono> that works with C++11/14/17:

#include "date/date.h"

#include <chrono>
#include <iostream>

int main()
{
    const uint64_t nanosSinceEpoch = 1517812763001883383;

    const std::chrono::nanoseconds d(nanosSinceEpoch);
    using date::operator<<;
    std::cout << date::sys_time<std::chrono::nanoseconds>{d} << '\n';
}

Output:

2018-02-05 06:39:23.001883383

Update to address time zones

There is a second <chrono> preview library at the same link in the header tz.h which deals with time zones. This library is not header-only. There's a single source file associated with it, tz.cpp. Here are directions for compiling it.

This library can be used to translate sys_time (aka Unix Time / UTC) into any IANA time zone.

For example if you need to display the above output in "America/Chicago" (even if your computer isn't in Chicago), then it can be done like this:

#include "date/tz.h"

#include <chrono>
#include <iostream>

int main()
{
    const uint64_t nanosSinceEpoch = 1517812763001883383;

    using namespace std::chrono;
    date::sys_time<nanoseconds> tp{nanoseconds(nanosSinceEpoch)};
    std::cout << date::zoned_time{"America/Chicago", tp} << '\n';
}

Output:

2018-02-05 00:39:23.001883383 CST

This is also part of C++20 <chrono>. zoned_time is a pairing of a time zone and a sys_time, of any precision as long as it is seconds or finer. Its streaming operator includes the time zone abbreviation. There is also a format function (std::format in C++20, date::format in the library) that can be used to customize the output. For example:

date::zoned_time zt{"America/Chicago", tp};
std::cout << date::format("%F %T%z", zt) << '\n';

Output:

2018-02-05 00:39:23.001883383-0600

Upvotes: 3

Related Questions