C++ 中的日期时间解析和格式化

Datetime parse and format in C++

我是第一次使用 time_point。 我想从字符串中解析日期时间,并在从 1 小时返回字符串时发现了差异。

std::chrono::system_clock::time_point timePoint;
std::stringstream ss("2021-01-01 00:00:09+01");
std::chrono::from_stream(ss, "%F %T%z", timePoint);  
  // timePoint == {_MyDur={_MyRep=16094556090000000 } }
std::string timePointStr = std::format("{:%Y/%m/%d %T}", floor<std::chrono::seconds>(timePoint));
  // timePointStr = "2020/12/31 23:00:09"

我不知道哪里出了问题:时间点和解析或格式化为字符串? 怎样才能得到和解析出来的一样的格式?

这是预期的行为。

解释:

system_clock::time_point,更一般地说,所有基于 system_clocktime_point 都具有 Unix Time 的语义。这是自 1970-01-01 00:00:00 UTC 以来的时间计数,不包括闰秒。

所以当“2021-01-01 00:00:09+01”被解析为system_clock::time_point时,“2021-01-01 00:00:09”被解释为local time,"+01" 用于将本地时间转换为 UTC。当格式化回退时,没有相应的转换回本地时间(尽管使用附加语法 1 是可能的)。格式语句只是打印出 UTC 时间(提前一小时)。

如果您希望在不转换为 UTC 的情况下解析“2021-01-01 00:00:09+01”,可以通过解析成您想要的任何精度的 std::chrono::local_time 来完成。例如:

std::chrono::local_seconds timePoint;
std::stringstream ss("2021-01-01 00:00:09+01");
from_stream(ss, "%F %T%z", timePoint);
...

现在当您打印出来时,您将得到“2021/01/01 00:00:09”。但是 rep 中的值现在是 1609459209(3600 秒后)。


1 要将 sys_time 处的格式输出为 local_time,UTC 偏移量为 1h,必须选择 time_zone在您格式化的 UTC 时间至少 的 UTC 偏移量 。例如,IANA 时区“Etc/GMT-1”always 的偏移量为 1h ... 是的,偏移量的符号是相反的。使用它将 2020-12-31 23:00:09 UTC 转换回 2021-01-01 00:00:09 看起来像:

std::chrono::sys_seconds timePoint;
std::stringstream ss("2021-01-01 00:00:09+01");
std::chrono::from_stream(ss, "%F %T%z", timePoint);
// timePoint == 2020-12-31 23:00:09 UTC
std::string timePointStr = std::format("{:%Y/%m/%d %T}",
                               std::chrono::zoned_time{"Etc/GMT-1", timePoint});
cout << timePointStr << '\n';  // 2021/01/01 00:00:09

免责声明:我目前没有办法验证 MSVC 是否支持“Etc/GMT-1”std::chrono::time_zone.

Fwiw,使用“Africa/Algiers”或“Europe/Amsterdam”代替“Etc/GMT-1”应该为此给出相同的结果具体时间戳。如果您的计算机将其本地时区设置为此时间戳具有 1 小时 UTC 偏移量,则 std::chrono::current_zone() 代替“Etc/GMT-1”也会给出相同的结果。