将 ISO8601 字符串转换为自纪元以来的毫秒数

Posted

技术标签:

【中文标题】将 ISO8601 字符串转换为自纪元以来的毫秒数【英文标题】:Converting ISO8601 string to milliseconds since epoch 【发布时间】:2018-11-13 21:13:57 【问题描述】:

示例字符串:

2018-10-31T14:45:21.778952-07:00

我想将它转换为 int64_t 表示自纪元以来的毫秒(甚至微秒)。时区可能会有所不同。代码将在 linux 机器上执行,但我只能访问 std 和 folly(不能使用任意 3P 库)。

我对此进行了搜索,发现了一些对我不起作用的不同方法:

    strptime() 和 std::get_time() 失去毫秒精度 更重要的是,它们都不能处理时区偏移 其他一些解决方案依赖于 3P 库

有没有一些简单的方法可以做到这一点?

【问题讨论】:

我找到了以下链接。我希望它会有所帮助。 ***.com/questions/4137748/… @MJK 对不起,应该提到我也看过。由于 std::get_time 使用 tm 结构,它也失去了毫秒精度。 一旦你分解了每个元素,你可能想看看操作系统如何将 RTC 转换为 unix epoch。这些算法是众所周知的,通常可以复制和粘贴。 这里可以找到一个例子,重要的部分是将日期转换为自 1970 年以来的天数,我不记得最初在哪里找到此信息:forum.osdev.org/viewtopic.php?t=13635&p=93464 这个特殊问题不需要了解时区,因为 UTC 偏移量是格式的一部分。如果你改变主意使用Howard Hinnant's library,这个问题只需要包含一个标题,并且只需要几行代码。该库也已被投票加入 C++20 工作草案。对于样本输入,结果为 1541022321778952µs。 【参考方案1】:

来自上面的cmets:

我正在研究使用霍华德的图书馆。但是,它拨打网络电话让我停下来。我假设如果调用失败它只会使用本地存储的时区名称数据?我们不会处理时区名称,所以我不在乎那些。但是,进行网络调用可能是个问题。

Howard's library 分层:

    foundational layer 不需要 IANA 时区数据库,因此从不进行网络调用。这是一个单头,只有头的库。

    知道 IANA 时区数据库的 time zone layer。该层可以配置为是否进行网络调用(取决于构建标志),甚至可以使用您操作系统的时区数据库(Windows 除外)。

您的应用程序不需要 time zone layer,因为它只处理 UTC 偏移量,而不是时区名称或规则。

这是一个函数,可将您的示例格式的std::string 转换为std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>。这种类型对于system_clock::time_point 来说是一个非常冗长的内容,除非保证具有microseconds 精度。 foundational layer 具有此类型的类型别名,称为 date::sys_time<std::chrono::microseconds>

#include "date/date.h"
#include <chrono>
#include <iostream>
#include <sstream>

auto
to_sys_time(std::string s)

    using namespace date;
    using namespace std;
    using namespace std::chrono;
    istringstream inmove(s);
    in.exceptions(ios::failbit);
    sys_time<microseconds> tp;
    in >> parse("%FT%T%z", tp);
    return tp;

string 放入istringstream。 (可选)设置 istringstream 以在解析失败时抛出异常(您可以选择以不同方式处理错误)。 以所需的精度声明您的time_point。 用你想要的格式解析它。 退货。

你可以像这样行使这个功能:

int
main()

    auto tp = to_sys_time("2018-10-31T14:45:21.778952-07:00");
    using date::operator<<;
    std::cout << tp << " UTC\n";
    std::cout << tp.time_since_epoch() << '\n';

使用所需的输入字符串调用to_sys_time。 使namespace date 中的流式操作符可用。 打印出time_point(这是一个UTC time_point)。 提取并打印出durationtime_point

这个程序的输出是:

2018-10-31 21:45:21.778952 UTC
1541022321778952µs

该程序将通过删除#include "date/date.h"using namespace date;using date::operator&lt;&lt;; 移植到C++20。

【讨论】:

谢谢,霍华德!正确的答案是 C++14 标准库没有解析时区偏移的方法,所以我唯一的选择是自己编写该逻辑或使用 3P 库。您的图书馆是最佳选择。

以上是关于将 ISO8601 字符串转换为自纪元以来的毫秒数的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中将日期时间对象转换为自纪元(unix 时间)以来的毫秒数?

在Java中将ISO 8601时间戳字符串转换为纪元秒[重复]

php:将毫秒转换为日期

如何将 ISO8601 格式转换为毫秒?

将 Unix 纪元时间转换为扩展的 ISO8601

python iso8601日期格式与unix纪元日期时间之间的转换