考虑操作系统配置的时区,std :: chrono :: system_clock :: now()

时间:2016-09-01 14:28:34

标签: c++ linux date c++11 timezone

我正在编写一个在BusyBox嵌入式Linux上运行的C ++代码。我的代码及其库有几次调用std::chrono::system_clock::now()来获取当前时间。

从现在开始我的盒子配置为dafault时区(UTC),一切正常,进程正常运行,结果还可以。

现在我必须设置我的linux以保持不同的时区。然后我通过在/etc/profile框中配置来完成它:

export TZ=UTC+3

当我发出date命令和控制台时,我得到了正确的时间,但我对std::chrono::system_clock::now()的调用仍然是UTC时间,而不是{{1命令(正确的时间)。

我不想更改所有date次呼叫 - 其中有数百次呼叫...这导致我的进程工作的时间与控制台上设置的正确时间不同。

有没有办法解决这个问题而不改变我的代码?我在这里找不到任何东西?

感谢您的帮助。

1 个答案:

答案 0 :(得分:13)

虽然标准未指定,但std::chrono::system_clock::now()的每个实施都在跟踪Unix Time,这与UTC非常接近。

如果您想将std::chrono::system_clock::now()翻译为当地时间,可以通过system_clock::time_pointtime_t翻译为system_clock::to_time_t,然后通过C API(例如localtime),或者您可以尝试在<chrono>之上构建的现代时区库:

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

您可以使用它来获取当前的当地时间:

#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是一个工厂函数,它以zoned_time支持的精度(例如纳秒)返回类型system_clock。它是time_zonesystem_clock::time_point的配对。

你可以得到local_time<Duration>这样的std::chrono::time_point

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

虽然该库具有自动下载IANA timezone database的远程API,但可以通过使用-DHAS_REMOTE_API=0进行编译来禁用该API。这一点在installation instructions中有详细说明。禁用远程API后,您必须从IANA timezone database手动下载数据库(它只是tar.gz)。

如果您需要当前的UTC偏移量,可以这样获得:

    auto t = make_zoned(current_zone(), system_clock::now());
    auto offset = t.get_info().offset;
    std::cout << offset << '\n';

在上面的代码段中,我利用在同一个github存储库中找到的"chrono_io.h"来打印offsetoffset的类型为std::chrono::seconds。这只是输出给我:

-14400s

( - 0400)

最后,如果您想要发现当前时区的IANA名称,那就是:

std::cout << current_zone()->name() << '\n';

对我来说只输出:

America/New_York

name()返回的类型为std::string。如果需要,可以记录该字符串,然后使用具有该名称的time_zone,即使这不是计算机的当前时区:

auto tz_name = current_zone()->name();
// ...
auto t = make_zoned(tz_name, system_clock::now()); // current local time in tz_name