将time_t从localtime zone转换为UTC

时间:2016-07-31 17:03:19

标签: c++

我有time_t表示自纪元以来的秒数。这些秒是指当地时间。

我想将它们转换为UTC。

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

3 个答案:

答案 0 :(得分:10)

我将展示两种方法:

  1. 使用C API。
  2. 使用基于<chrono>
  3. 之上的现代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格式)。所以第一步是谎言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中没有设施来执行此操作。但是,您可以使用此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时区的时间)表示。

(c)http://www.cplusplus.com/reference/ctime/gmtime/

答案 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()));

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