Mendes Mendes - 3 months ago 43
C++ Question

std::chrono::system_clock::now() considering the OS configured time zone

I´m programming a C++ code that is running on a BusyBox embedded linux. My code and its libraries has several calls to

std::chrono::system_clock::now()
to get the current time.

Since now my box was configured as dafault time zone (UTC) and everything works fine, processes running and results ok.

Now I had to set my linux to stay in a different timezone. Then I did it by configuring in the box
/etc/profile
:

export TZ=UTC+3


When I issue
date
command and the console I get the correct time, but my calls to
std::chrono::system_clock::now()
I´m still getting the UTC time, not the time that is shown in the
date
command (the correct time).

I don´t want to change all my
now()
calls - there are hundreds on them... And that is causing my processes to work with different time than the correct time, set on the console.

IS there any way to solve that without changing my code ? Anything I´m missing here ?

Thanks for helping.

Answer

Though unspecified by the standard, every implementation of std::chrono::system_clock::now() is tracking Unix Time, which is a very close approximation to UTC.

If you want to translate std::chrono::system_clock::now() to local time, you can either translate system_clock::time_point to time_t via system_clock::to_time_t, and then work your way through the C API (e.g. localtime), or you might try this modern timezone library which is built on top of <chrono>:

https://howardhinnant.github.io/date/tz.html

You would use this to get the current local time like this:

#include "tz.h"
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    auto t = make_zoned(current_zone(), system_clock::now());
    std::cout << t << '\n';
}

make_zoned is a factory function which returns the type zoned_time with whatever precision your system_clock supports (e.g. nanoseconds). It is a pairing of a time_zone and a system_clock::time_point.

You can get a local_time<Duration> which is a std::chrono::time_point like this:

    auto t = make_zoned(current_zone(), system_clock::now());
    auto lt = t.get_local_time();
    std::cout << lt.time_since_epoch().count() << '\n';

Though the library has a remote API to download the IANA timezone database automatically, that API can be disabled by compiling with -DHAS_REMOTE_API=0. This is all detailed in the installation instructions. With the remote API disabled, you would have to manually download the database from IANA timezone database (it's just a tar.gz).