在C++11中解析毫秒日期时间的最佳方法是什么?

15

当我们有毫秒级别的日期时间字符串时,对于 strptime 来说下一个最好的选择是什么?

已知:

"30/03/09 16:31:32.121"

我们不能使用常规的strptime,因为struct tm不存储毫秒。是否有新的类可以实现这一点?


std::get_time 是 C++11 的函数,但它与 strptime 的规范相似。您需要存储毫秒吗?还是只需要显示它? - user3920237
我的目标是将此日期时间存储在chrono时间点中,因此我确实需要它被解析和存储。 - Nezquick
使用 .1214 不是在请求毫秒,而是请求 1/10 毫秒或 100 微秒。 - Johann Gerell
请提供待翻译的英文内容。 - Nezquick
1个回答

14

我会手动解析这些字段(将秒读入int和double),然后使用days_from_civil将年/月/日转换为chrono::system_clock::time_point

std::chrono::system_clock::time_point t(days(days_from_civil(y, m, d)));

其中 days 表示:

using days = std::chrono::duration<int, std::ratio<86400>>;

然后你可以加上小时、分钟和秒。为了处理小数秒,你需要进行一些微调:

double s;
your_stream >> s;  // 32.121
using namespace std::chrono;
duration<double> dsecs(s);
seconds sec = duration_cast<seconds>(dsecs);
milliseconds ms = duration_cast<milliseconds>(dsecs - sec);
t += sec + ms;

如果您喜欢,可以使用这里的round进行毫秒转换:
milliseconds ms = round<milliseconds>(dsecs - sec);

duration_cast 是向零舍入的。还有其他的舍入模式:floor,round,ceil,在此链接上可以查看。

将其封装在一个整洁的函数中以便于重复使用。:-)

上述代码都假定为UTC时间。如果您正在解析的日期/时间已知与UTC相差多少,您可以添加/减去该偏移量。所有已知的system_clock实现都跟踪Unix时间,即从1970-01-01起在UTC时区的秒数。

更新

自撰写本答案以来,我开发了一个更通用的库,似乎当时OP正在寻找。它可以直接将各种亚秒精度解析为std::chrono::system_clock::time_point,如下所示:

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

int
main()
{
    std::istringstream in{"30/03/09 16:31:32.121\n"
                          "30/03/09 16:31:32.1214"};
    std::chrono::system_clock::time_point tp;
    in >> date::parse("%d/%m/%y %T", tp);
    using namespace date;
    std::cout << tp << '\n';
    in >> date::parse(" %d/%m/%y %T", tp);
    std::cout << tp << '\n';
}

这将会输出:
2009-03-30 16:31:32.121000
2009-03-30 16:31:32.121400

这个库使用了我最初描述的相同技术和工具,但是已经打包成一个单一头文件库,可以直接使用。


我使用了常规的time_t来使日期部分工作,而不是使用days_from_civil(另一个外部库)。最终我使用了google:re2来读取模式,因为我想要更通用的东西。谢谢。 - Nezquick
嗨Howard,代码已更新但编译出错:错误:date.h:4324:9从初始化列表转换为“date :: weekday”将使用显式构造函数“constexpr date :: weekday :: weekday(unsigned int)” fields() = default; ^ - ZFY
1
@ZFY。感谢您的报告!这似乎是与pre-gcc-5平台有关的问题:https://github.com/HowardHinnant/date/issues/264 - Howard Hinnant
我们是否有一个接口可以将“30/03/09 16:31:32.121”解析为time_point,而不使用istringstream呢? - q0987
不好意思,如果你愿意做出简化假设,例如有限的错误处理、ASCII 和“C”语言环境,那么从任何字符缓冲区(如string)解析自己的整数值并不难:https://github.com/HowardHinnant/date/blob/master/include/date/ptz.h#L828-L838。然后将这些整数值转换为基于`system_clock`的`time_point`就很容易了:`auto tp = sys_days{day{d}/m/y} + hours{h} + minutes{M} + seconds{s} + milliseconds{ms};`。 - Howard Hinnant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接