如何将日期字符串解析为c ++ 11 std :: chrono time_point或类似的?

Dre*_*kes 41 c++ date-parsing datetime-parsing c++11

考虑格式的历史日期字符串:

Thu Jan 9 12:35:34 2014
Run Code Online (Sandbox Code Playgroud)

我想将这样的字符串解析为某种C++日期表示,然后计算从那时起经过的时间量.

从结果持续时间我需要访问秒数,分钟数,小时数和天数.

这可以用新的C++ 11 std::chrono命名空间来完成吗?如果没有,我今天该怎么办呢?

我正在使用g ++ - 4.8.1,但据推测答案应该只针对C++ 11规范.

Sim*_*ple 64

std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
Run Code Online (Sandbox Code Playgroud)

版本5之前的GCC没有实现std::get_time.你也应该写:

std::tm tm = {};
strptime("Thu Jan 9 2014 12:35:34", "%a %b %d %Y %H:%M:%S", &tm);
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
Run Code Online (Sandbox Code Playgroud)

  • `#include <iomanip>`for`std :: get_time`. (4认同)
  • @Xaqq std::tm t{}; // 应该做 (3认同)

How*_*ant 13

旧问题的新答案.新答案的基本原理:问题是从原始形式编辑的,因为当时的工具无法准确处理所要求的内容.由此产生的接受答案给出了与原始问题所要求的略有不同的行为.

我不是想放下接受的答案.这是一个很好的答案.只是C API 如此令人困惑,以至于不可避免会出现这样的错误.

最初的问题是解析"Thu, 9 Jan 2014 12:35:34 +0000".很明显,目的是解析表示UTC时间的时间戳.但是strptime(它不是标准的C或C++,但是POSIX)不会解析尾随的UTC偏移量,表明这是一个UTC时间戳(它将格式化%z,但不解析它).

然后编辑这个问题来询问"Thu Jan 9 12:35:34 2014".但是没有编辑这个问题来澄清这是一个UTC时间戳,还是计算机当前本地时区的时间戳.接受的答案隐含地假设时间戳代表计算机的当前本地时区,因为使用了std::mktime.

std::mktime不仅可以将字段类型tm转换为串行类型time_t,还可以执行从计算机本地时区到UTC的偏移调整.

但是,如果我们想要解析UTC时间戳作为原始(未编辑的)问题,该怎么办?

今天可以使用这个更新的免费开源库来完成.

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

int
main()
{
    using namespace std;
    using namespace date;
    istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
    sys_seconds tp;
    in >> parse("%a, %d %b %Y %T %z", tp);
}
Run Code Online (Sandbox Code Playgroud)

这个库可以解析%z.并且date::sys_seconds只是一个typedef:

std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
Run Code Online (Sandbox Code Playgroud)

这个问题还要求:

从结果持续时间我需要访问秒数,分钟数,小时数和天数.

那部分仍未得到答复.以下是使用此库的方法.对于这部分,我还将使用第二个仅限标题的库"chrono_io.h":

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

int
main()
{
    using namespace std;
    using namespace date;
    istringstream in{"Thu, 9 Jan 2014 12:35:34 +0000"};
    sys_seconds tp;
    in >> parse("%a, %d %b %Y %T %z", tp);
    auto tp_days = floor<days>(tp);
    auto hms = make_time(tp - tp_days);
    std::cout << "Number of days    = " << tp_days.time_since_epoch() << '\n';
    std::cout << "Number of hours   = " << hms.hours() << '\n';
    std::cout << "Number of minutes = " << hms.minutes() << '\n';
    std::cout << "Number of seconds = " << hms.seconds() << '\n';
}
Run Code Online (Sandbox Code Playgroud)

floor<days>将秒精度截断time_point天精度 time_point.如果time_point从中减去天数精度tp,则会留下一个duration表示自午夜(UTC)以来的时间.

工厂函数make_time接受任何duration(在这种情况下是从午夜开始的时间)并创建一个{hours, minutes, seconds}字段类型,每个字段都有getter.如果持续时间的精度小于秒,则此字段类型也将具有亚秒的getter.

最后,使用"chrono_io.h",可以打印出所有这些持续时间.此示例输出:

Number of days    = 16079[86400]s
Number of hours   = 12h
Number of minutes = 35min
Number of seconds = 34s
Run Code Online (Sandbox Code Playgroud)

[86400]s代表的单位duration有天精度.所以2014-01-09是1970-01-01之后的16079天.

  • 抱歉@BillGale。我无意**掩盖**我的作者身份。事实上,与许多其他人(不是你自己)不同,我使用我的全名作为我的 Stack Overflow ID 和我的 github ID。如果我试图掩盖自己的作者身份,人们会认为我会比这更聪明一点。此外,人们可以解释为添加“我写了它!” 作为吹牛。我既不想吹牛,也不想掩饰。我没有从这个软件中赚到一分钱,我也不想赚到一分钱。我的主要目标是寻求 C++ 标准提案的现场经验。任务完成。使用 C++20 标准化的库。 (10认同)
  • @BillGale 认真的吗?只是对这个人表示感谢,他用伟大的“std::chrono”库标准化了 C++ 编码中最令人揪心的方面之一,然后为我们编写了另一个帮助程序库。无论如何,@HowardHinnant 我衷心感谢您! (2认同)