繁体   English   中英

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

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

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

因为现在我的盒子被配置为 dafault 时区 (UTC) 并且一切正常,进程正在运行并且结果正常。

现在我不得不设置我的 linux 以保持在不同的时区。 然后我通过在框中配置/etc/profile做到这一点:

export TZ=UTC+3

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

我不想更改我所有的now()调用 - 它们有数百个......这导致我的进程使用与控制台上设置的正确时间不同的时间。

有没有办法在不改变我的代码的情况下解决这个问题? 我在这里遗漏了什么?

谢谢你的帮助。

尽管标准未指定,但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是一个工厂函数,它以system_clock支持的任何精度(例如纳秒)返回zoned_time类型。 它是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';

虽然库有一个远程 API 来自动下载IANA 时区数据库,但可以通过编译-DHAS_REMOTE_API=0来禁用该 API。 这在安装说明中都有详细说明 在禁用远程 API 的情况下,您必须从IANA 时区数据库(它只是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"来打印offset offset类型为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

4年后更新

这个库现在是 C++20 的一部分,有以下修改:

  • "tz.h"的内容在<chrono> "tz.h" <chrono>
  • namespace date中名称的内容在namespace date namespace std::chrono
  • make_zoned不是 C++20 的一部分,因为CTAD使它变得不必要。 您可以在它的位置使用zoned_time并推导出模板参数。

此外,自定义(用户编写的) time_zone现在可以与https://howardhinnant.github.io/date/tz.html或新的 C++20 <chrono> 此处编写了一个自定义time_zone的好示例来模拟 POSIX 时区 这可以用来更准确地回答原始问题:

#include "date/ptz.h"
#include <cstdlib>
#include <iostream>

int
main()
{
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    const char* tz = getenv("TZ");
    if (tz == nullptr)
        tz = "UTC0";
    zoned_time now{Posix::time_zone{tz}, system_clock::now()};
    cout << format("%F %T%z", now) << '\n';
}

将我的TZ环境变量设置为UTC+3这只是为我输出:

2020-09-17 10:28:06.343050-0300

注意事项:

  • 尽管依赖于tz.h ,但ptz.h是一个只有头文件的库。 无需安装 IANA tz 数据库,也tz.cpp编译tz.cpp

  • POSIX 指定UTC 偏移量的符号与其他所有使用的符号相反(包括 POSIX 的其他部分)。 正偏移位于本初子午线以西而不是 这反映在输出中,该输出在本示例中将 UTC 偏移量格式化为负数,这与POSIX strftime规范一致。

  • 如果用C ++ 11或C ++编译14本,你没有CTAD在toobox。 在这种情况下:

`

zoned_time now{Posix::time_zone{tz}, system_clock::now()};

变成:

zoned_time<system_clock::duration, Posix::time_zone> now{Posix::time_zone{tz}, system_clock::now()};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM