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


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

Thu Jan 9 12:35:34 2014

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

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

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

我正在使用g ++ - 4.8.1,但可能答案应该只针对C ++ 11规范。


31
2018-01-09 13:18


起源


POSIX系统(如Linux或OSX)有一个 strptime 将字符串解析为 tm 结构体。不幸的是,Windows不存在,但是 还有其他选择。 - Some programmer dude
@JoachimPileborg它是否支持 +0000 但最后呢?
@remyabel,其实我错了。那个后缀不存在。我已经更新了这个问题。 - Drew Noakes
这很好,因为似乎不支持时区后缀。 :) - Some programmer dude
请注意,chrono的设计并未考虑日历功能,因此请关联 time_point 实际日期不是其功能的核心。 Boost试图解决这个问题 约会时间 早于Chrono的图书馆。不幸的是,那两个库 不要一起去 尽可能顺利。 - ComicSansMS


答案:


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));

版本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));

56
2018-01-09 13:41



但 GET_TIME() 还没有在gcc上实现? - SChepurin
根据 错误54354 在gcc中,这是在gcc 5中解决的。对于C ++ 11功能来说有点晚了。 - jpyllman
@Xaqq std :: tm t {}; // 应该做 - nurettin
#include <iomanip> 对于 std::get_time。 - Jonny
@einpoklum,应该从gcc 5.0开始工作。我已经在gcc 5.4(即目前稳定的Ubuntu 16.04)上进行了测试。 - Velkan


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

我不是想放下接受的答案。这是一个很好的答案。这就是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);
}

这个图书馆 能够 解析 %z。和 date::sys_seconds 只是一个typedef:

std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>

这个问题还要求:

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

那部分仍未得到答复。这是你如何做到的 这个图书馆。对于这部分,我也将使用一秒钟 标题库 "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';
}

floor<days> 截断秒精度 time_point 到了 天精  time_point。如果你减去天数 - 精度 time_point 从 tp,你留下了 duration 表示自午夜(UTC)以来的时间。

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

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

Number of days    = 16079[86400]s
Number of hours   = 12h
Number of minutes = 35min
Number of seconds = 34s

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


6
2018-01-12 12:56





这是C-ish,并不像Simple的答案那样优雅,但我认为它可能有用。 这个答案可能是错的,但我会把它留下来,以便有人可以发布更正。

#include <iostream>
#include <ctime>

int main ()
{
  struct tm timeinfo;
  std::string buffer = "Thu, 9 Jan 2014 12:35:00";

  if (!strptime(buffer.c_str(), "%a, %d %b %Y %T", &timeinfo))
    std::cout << "Error.";

  time_t now;
  struct tm timeinfo2;
  time(&now);
  timeinfo2 = *gmtime(&now);

  time_t seconds = difftime(mktime(&timeinfo2), mktime(&timeinfo));
  time(&seconds);
  struct tm result;
  result = *gmtime ( &seconds );
  std::cout << result.tm_sec << " " << result.tm_min << " "
            << result.tm_hour << " " << result.tm_mday;
  return 0;
}

2