将 time_t 从本地时区转换为 UTC

新手上路,请多包涵

我有一个 time_t 表示自纪元以来的时间(以秒为单位)。这些秒是指当地时间。

我想将它们转换为 UTC。

有没有办法在 C++ 中做到这一点?

原文由 MATH000 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.8k
2 个回答

我将展示两种方法:

  1. 使用 C API。
  2. 使用基于 <chrono> 的现代 C++1114 库。

出于本演示的目的,我假设本地时区的当前秒数为 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;
}

首先我初始化 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);

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

 local_field.tm_isdst = -1;

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

 auto utc = std::mktime(&local_field);

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

 1470018241

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

 2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC

现代 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";
}

第一步是以秒为单位创建本地时间:

 local_seconds{1470003841s}

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

 auto zt = make_zoned(current_zone(), local_seconds(1470003841s));

然后您可以简单地打印出此配对的 UTC 秒数:

 std::cout << zt.get_sys_time().time_since_epoch() << '\n';

这个输出对我来说:

 1470018241s

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

 std::cout << zt << '\n';
std::cout << zt.get_sys_time() << " UTC\n";

输出:

 2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC

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

C++20 更新

第二种技术将在 C++20 中可用,语法如下:

 #include <chrono>
#include <iostream>

int
main()
{
    using namespace std::chrono;
    zoned_time zt{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";
}

原文由 Howard Hinnant 发布,翻译遵循 CC BY-SA 4.0 许可协议

您可以使用 gmtime:

将 time_t 转换为 tm 作为 UTC 时间 使用 timer 指向的值来填充 tm 结构,其中的值表示对应的时间,表示为 UTC 时间(即 GMT 时区的时间)。

© http://www.cplusplus.com/reference/ctime/gmtime/

原文由 AnatolyS 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题