我有time_t
表示自纪元以来的秒数。这些秒是指当地时间。
我想将它们转换为UTC。
有没有办法在C ++中执行此操作?
答案 0 :(得分:10)
我将展示两种方法:
<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(<);
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(<);
在您离开之前(我个人第一次将这部分搞砸了)您必须增加此字段类型,以表明您不知道它是否是当前夏令时。这会导致后续步骤为您解决这个问题:
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中没有设施来执行此操作。但是,您可以使用此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
(比输入晚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时间是不同的类型,这使我更有可能在编译时意外混合这两个概念(而不是创建运行时错误)。
答案 1 :(得分:1)
您可以使用gmtime:
将time_t转换为tm作为UTC时间使用timer指向的值 使用表示相应值的值填充tm结构 时间,以UTC时间(即GMT时区的时间)表示。
答案 2 :(得分:0)
如果您可以使用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()));
(也许库中有一组简单的调用可以做到这一点,但是我没有进一步探讨。:))