[英]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_point
到time_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_zone
和system_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
这个库现在是 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.