使用标准库生成/解析UTC日期

Build/parse UTC date using standard library

本文关键字:解析 UTC 日期 标准      更新时间:2023-10-16

我在c++中使用标准库构建UTC日期时遇到问题。例如(任何都可以):

  • 从包含年月日的单独变量构建

或解析

  • 1970年1月1日00:00:00 UTC

  • 1970年1月1日00:00:00+0000

  • 1970年1月1日00:00:00#(隐含UTC)

条件:

  • 时区字符串不需要解释,但我需要确保日期被解释为UTC
  • 日期的格式总是正确的
  • 只要完成工作,任何格式都可以接受
  • 应该是可移植的(UNIX变体和Windows)
  • 尽可能避免使用外部库

到目前为止最好的候选者是:

  • std::time_get,但规范没有说明任何关于时区的内容(据我所知:-)
  • boost的date_time,但它是一个相当严重的依赖项(在C++库(unix)中提到解析日期/时间字符串包括时区,但答案早于C++11)
  • unix strptime在windows上不可移植
  • 直接使用std::tm,但在我的系统(glibc)上,它有非标准的未记录字段(即tm_zone…)。我想我可以用gmtime(0)初始化它,然后修改天、月、年字段

如何从UTC日期构建std::chrono::time_point::time_point

如何从UTC日期构建std::chrono::system_clock::time_point

就这一部分而言,这里有一个仅限标头的高性能C++11/14现代解决方案。它可以这样使用:

int y = 2016;
int m = 1;
int d = 14;
int h = 18;
int min = 2;
int sec = 15;
std::chrono::system_clock::time_point tp = 
    date::sys_days{date::year{y}/m/d} +
    std::chrono::hours{h} +
    std::chrono::minutes{m} +
    std::chrono::seconds{sec};

这是github上的一个开源免费库。这是图书馆的视频演示。此库可移植到C++11和C++14的所有最新实现(包括VS2013和VS2015)。它提供了比继承自C的tm更好的接口,并且具有更大的有效性范围。它还提供了更高的性能,以及C++14中大量的编译时能力。它被设计为<chrono>的简单扩展,因此可以与<chrono>完全互操作。

对于解析,请使用tz.h:

1970年1月1日00:00:00 UTC

#include "tz.h"
#include <iostream>
#include <sstream>
int
main()
{
    std::istringstream in{"01/01/1970 00:00:00 UTC"};
    date::sys_seconds tp;
    date::parse(in, "%d/%m/%Y %T %Z", tp);
    using namespace date;
    if (!in.fail())
        std::cout << tp << 'n';
}

在上述代码中,sys_secondsstd::chrono::time_point<system_clock, seconds>

1970年1月1日00:00:00+0000

将上面的%Z更改为%z

1970年1月1日00:00:00

卸下%Z/%z

  • 尽可能避免使用外部库

抱歉,否则您必须:

  • 直接摆弄std::tm

此库允许您解析%z%Z。你可以扔掉这个缩写,或者发现它,试着弄清楚它的意思(通常缩写是模棱两可的)。对于%z,偏移量将改变解析的值,从而为您提供UTC:

std::istringstream in{"01/01/1970 00:00:00 +0500"};
date::sys_seconds tp;
date::parse(in, "%d/%m/%Y %T %z", tp);
using namespace date;
if (!in.fail())
    std::cout << tp << 'n';

输出:

1969-12-31 19:00:00

如果你想获得当地时间,那也很容易:

std::istringstream in{"01/01/1970 00:00:00 +0500"};
date::local_seconds tp;
date::parse(in, "%d/%m/%Y %T %z", tp);
using namespace date;
if (!in.fail())
    std::cout << tp << 'n';

输出:

1970-01-01 00:00:00

local_secondsstd::chrono::time_point,但基于没有now()的"时钟"。

更好地使用std::tm。。。因为这是标准的。

不要担心tm_zone。这是一个可选字段,仅在Linux/NGNU或freeBSD等环境中可用。。。(实际上,正如你所指出的,它带有glibc)。

然而,它是NO功能效应。使用它的程序应该有一个#ifndef#ifdef指令来嵌入该语句,从而允许在没有结构中定义字段的系统上进行编译。

要回答您的最后一个问题。。。不确定您的需求,但起点可以是:

system_clock::time_point tp = system_clock::now();

如下所示:

http://www.cplusplus.com/reference/chrono/time_point/time_since_epoch/

希望有帮助,

PS:关注以下内容:steady_clock和system_clock之间的区别?