c++ 将time_t从本地时区转换为UTC

hlswsv35  于 2022-12-24  发布在  其他
关注(0)|答案(4)|浏览(433)

我有一个time_t,它表示自epoch以来的时间(以秒为单位),这些秒指的是本地时间。
我想将它们转换为UTC。
在C++中有办法做到这一点吗?

oxcyiej7

oxcyiej71#

我将展示两种方法:
1.使用C API。
1.使用基于<chrono>的现代C ++11/14库。
出于本演示的目的,我假设本地时区的当前秒数为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)。因此,第一步是 * lie * to 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

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

2016-07-31 22:24:01 EDT
2016-08-01 02:24:01 UTC
    • 现代C++ API:**

在std::lib中不存在执行此操作的工具。但是,您可以使用free, open source (MIT license) library执行此操作。

#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

(4h要像我在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";
}
4ioopgfo

4ioopgfo2#

您可以使用gmtime:
将time_t转换为tm作为UTC时间使用timer指向的值用表示相应时间的值填充tm结构,表示为UTC时间(即GMT时区的时间)。
(c)http://www.cplusplus.com/reference/ctime/gmtime/

r1wp621o

r1wp621o3#

如果您可以使用Abseil's time library,另一种方法是:

auto civil_second =
  absl::LocalTimeZone().At(absl::FromTimeT(<your time_t>)).cs;

time_t time_in_utc = absl::ToTimeT(absl::FromCivil(civil_second, absl::UTCTimeZone()));

(也许库中有一组更简单的调用可以做到这一点,但我还没有进一步探索。:))

5lhxktic

5lhxktic4#

通常情况下,你会从time_t转换到struct tm,而且在不同的时区(在OP的问题中是UTC)从 time_t 转换到 time_t 的例子并不多。我写这两个函数就是为了这个目的。当你只需要在特定的时区使用 time_t 时,它们可能会很有用。

time_t TimeAsGMT(time_t t)
{
    tm *myTm = std::gmtime(&t);
    time_t result = mktime(myTm);
    return result;
}

或者如果您希望当前时间为time_t的UTC

time_t CurTimeAsGMT()
{
    time_t now = chrono::system_clock::to_time_t(chrono::system_clock::now());
    tm *myTm = std::gmtime(&now);
    time_t result = mktime(myTm);
    return result;
}

相关问题