代码之家  ›  专栏  ›  技术社区  ›  Andrey Savov Steve Summit

在Ubuntu C/C中,如何将IANA时区名称转换为UTC偏移量++

  •  1
  • Andrey Savov Steve Summit  · 技术社区  · 8 年前

    Get UTC offset from time zone name in python 例如

    如何在Ubuntu 14.04上使用C/C++实现同样的功能?

    :最好以线程安全的方式(无环境变量)。

    3 回复  |  直到 7 年前
        1
  •  2
  •   Andrey Savov Steve Summit    8 年前

    您提到了这一事实,但重要的是要注意,UTC和时区时间之间的偏移量不一定是恒定的。如果时区执行夏时制(夏季)时间调整,则偏移将根据一年中的时间而变化。

    找到偏移量的一种方法是利用您感兴趣的时间,将其交给 localtime() tm_gmtoff 领域用 TZ 环境变量设置为您感兴趣的区域名称。下面是一个当前的例子:

    #include <time.h>
    #include <stdio.h>
    
    int main()
    {
        setenv("TZ", "America/Los_Angeles", 1);
        time_t t = time(NULL);
        struct tm *tmp = localtime(&t);
        printf("%ld\n", tmp->tm_gmtoff);
    }
    

    目前这张照片显示的是-25200,表明洛杉矶在格林威治以西25200秒,或420分钟,或7小时。但下周(实际上是明天)美国将停止DST,届时该代码将开始打印-28800。

    这不能保证有效,因为 tm_gmtoff 字段不可移动。但我相信所有版本的Linux都会有它。(您可能需要使用 -D_BSD_SOURCE 或其他,或将字段称为 __tm_gmtoff .但根据我的经验,它在默认情况下会起作用 tm_gmtoff .)

    另一种方法是与 gmtime mktime 如Sam Varshavchik的回答中所述。


    附录:您被问及不使用环境变量的问题。有一种方法,但不幸的是,它更不标准。有BSD功能 tzalloc localtime_rz 它们可以完成这项工作,但在Linux上不存在。下面是代码的外观:

        timezone_t tz = tzalloc("America/Los_Angeles");
        if(tz == NULL) return 1;
        time_t t = time(NULL);
        struct tm tm, *tmp = localtime_rz(tz, &t, &tm);
        printf("%ld\n", tmp->tm_gmtoff);
    

    对我来说,这打印-28800(因为PDT在几分钟前回到了PST)。

    如果你有它,你也可以使用 localtime_rz 随着 mktime 在萨姆·瓦沙夫契克的回答中。当然,Howard Hinnant的库很明显是线程安全的,不需要处理 TZ 完全

    编辑(OP):用于 localtime_rz 扎洛克 可从 https://www.iana.org/time-zones 在Ubuntu 14.04上工作。

        2
  •  2
  •   Howard Hinnant    8 年前

    你可以用这个 free open source C++11/14 library 要这样做:

    #include "chrono_io.h"
    #include "tz.h"
    #include <iostream>
    
    int
    main()
    {
        using namespace date;
        using namespace std::chrono;
        auto zt = make_zoned("America/Los_Angeles", system_clock::now());
        std::cout << zt.get_info().offset << '\n';
    }
    

    这目前输出:

    -25200s
    

    或者您可以将其格式化为不同的格式,如下所示:

        std::cout << make_time(zt.get_info().offset) << '\n';
    

    其当前输出:

    -07:00:00
    

    工厂功能 make_zoned 创建 zoned_time 使用IANA名称“美国/洛杉矶”和当前时间 std::chrono::system_clock A. member getter to get the information 关于时区 当时 .该信息是一种称为 sys_info 它包含各种有用的信息,包括当前UTC偏移。

    UTC偏移量存储为 std::chrono::seconds .标题 "chrono_io.h" 将格式化 durations 用于流式传输。或 make_time 实用程序可用于将持续时间格式化为 hh:mm:ss .

    上面的程序是线程安全的。您不必担心其他过程将TZ从您下面更改出来,或者以任何其他方式更改计算机的当前时区。如果你 希望 有关当前时区的信息,也可用,只需使用 current_zone() 代替 "America/Los_Angeles" .

    如果你想探索其他时间,那也很容易。例如,从2016年11月6日当地时间凌晨2点开始:

        auto zt = make_zoned("America/Los_Angeles", local_days{nov/6/2016} + 2h);
    

    输出变为:

    -28800s
    -08:00:00
    

    有关该库的更多信息在2016年Cppcon上展示,可在此处查看:

    https://www.youtube.com/watch?v=Vwd3pduVGKY

        3
  •  1
  •   Steve Summit    8 年前

    使用 gmtime() ,首先,将当前纪元时间转换为UTC时间,然后使用 mktime() 重新计算历元时间,然后将结果与实际历元时间进行比较。

    gmtime() 计算 struct tm 在UTC中,而 mktime() 假设 将时间 表示当前本地日历时间。因此,通过进行这轮计算,您可以间接计算出当前时区偏移。

    注意 mktime() 如果出现以下情况,则可以返回错误: 将时间 无法转换为纪元时间,这将在标准时间和备用时间之间的某些转换期间发生。在你的情况下,这取决于你去弄清楚这意味着什么。

    食谱看起来像这样:

    time_t t = time(NULL);
    struct tm *tmp = gmtime(&t);
    time_t t2 = mktime(tmp);
    int offset = t - t2;
    

    看见 the documentation of these library functions

    要使用特定时区,请设置 TZ 环境变量,或者您可以尝试使用 localtime_rz 正如史蒂夫·苏米特的回答。如前所述,注意 mktime