将time_t从localtime zone转换为UTC

MAT*_*000 7 c++

我有一个time_t表示自纪元以来秒数的时间.那些秒是指当地时间.

我想将它们转换为UTC.

有没有办法在C++中执行此操作?

How*_*ant 11

我将展示两种方法:

  1. 使用C API.
  2. 使用基于顶部的现代C++ 11/14库<chrono>.

出于本演示的目的,我假设当前时区的当前秒数为1,470,003,841.我当地的时区是America/New_York,所以我得到的结果反映了我们目前在-0400 UTC.

首先是C API:

此API不是类型安全的,并且非常容易出错.我在编写这个答案时犯了几个错误,但是我能够快速检测到这些错误,因为我正在检查第二种技术的答案.

#include <ctime>
#include <iostream>

int
main()
{
    std::time_t lt = 1470003841;
    auto local_field = *std::gmtime(&lt);
    local_field.tm_isdst = -1;
    auto utc = std::mktime(&local_field);
    std::cout << utc << '\n'; // 1470018241
    char buf[30];
    std::strftime(buf, sizeof(buf), "%F %T %Z\n", &local_field);
    std::cout << buf;
    auto utc_field = *std::gmtime(&utc);
    std::strftime(buf, sizeof(buf), "%F %T UTC\n", &utc_field);
    std::cout << buf;
}
Run Code Online (Sandbox Code Playgroud)

首先我初始化time_t.现在没有C API可以从本地time_t转到UTC time_t.但是,您可以使用gmtime从UTC time_t到UTC tm(从串行到字段类型,全部以UTC格式).所以第一步是gmtime,告诉它你已经有了一个UTC time_t.然后当你得到结果时,你只是假装你有一个本地tm而不是UTC tm.到目前为止清楚?这是:

auto local_field = *std::gmtime(&lt);
Run Code Online (Sandbox Code Playgroud)

在你离开之前(我个人第一次搞砸了这部分)你必须增加这个字段类型,说你不知道它是否是当前的夏令时.这会导致后续步骤为您解决这个问题:

local_field.tm_isdst = -1;
Run Code Online (Sandbox Code Playgroud)

接下来,您可以使用make_time将本地转换tm为UTC time_t:

auto utc = std::mktime(&local_field);
Run Code Online (Sandbox Code Playgroud)

你可以打印出来,对我来说它是:

1470018241
Run Code Online (Sandbox Code Playgroud)

这是4小时.该函数的其余部分是以人类可读的格式打印出这些时间,以便您可以调试这些东西.对我来说它输出:

2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC
Run Code Online (Sandbox Code Playgroud)

一个现代的C++ API:

std :: lib中没有设施来执行此操作.但是,您可以使用此免费的开源(MIT许可证)库.

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

int
main()
{
    using namespace date;
    using namespace std::chrono_literals;
    auto zt = make_zoned(current_zone(), local_seconds{1470003841s});
    std::cout << zt.get_sys_time().time_since_epoch() << '\n'; // 1470018241s
    std::cout << zt << '\n';
    std::cout << zt.get_sys_time() << " UTC\n";
}
Run Code Online (Sandbox Code Playgroud)

第一步是创建自纪元以来秒数的本地时间:

local_seconds{1470003841s}
Run Code Online (Sandbox Code Playgroud)

接下来要做的是创建一个zoned_time本地时间和当前时区的配对:

auto zt = make_zoned(current_zone(), local_seconds(1470003841s));
Run Code Online (Sandbox Code Playgroud)

然后你可以简单地打印出这个配对的UTC秒数:

std::cout << zt.get_sys_time().time_since_epoch() << '\n';
Run Code Online (Sandbox Code Playgroud)

这个输出对我来说:

1470018241s
Run Code Online (Sandbox Code Playgroud)

(比输入晚4小时).要像在C API中那样打印出这个结果:

std::cout << zt << '\n';
std::cout << zt.get_sys_time() << " UTC\n";
Run Code Online (Sandbox Code Playgroud)

哪个输出:

2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC
Run Code Online (Sandbox Code Playgroud)

在这种现代C++方法中,本地时间和UTC时间是不同的类型,这使我更有可能在编译时捕获这两个概念的意外混合(而不是创建运行时错误).