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

时间:2016-11-05 22:00:50

标签: c++ c c++11 ubuntu-14.04 timezone-offset

在Python或Java中,您可以根据时区的IANA名称(例如“America / Los_Angeles”)获取UTC偏移量(当前时间)。例如,请参阅Get UTC offset from time zone name in python

如何在Ubuntu 14.04上使用C / C ++做同样的事情?

编辑:最好以线程安全的方式(没有环境变量)。

3 个答案:

答案 0 :(得分:2)

您提到了这个事实,但重要的是要注意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。)

另一种方式是使用gmtimemktime来回,如Sam Varshavchik的回答所述。

附录:您询问了不使用环境变量的问题。有一种方法,但遗憾的是它的标准更低。有BSD函数tzalloclocaltime_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)。

如果你有,你也可以在Sam Varshavchik的回答中使用localtime_rzmktime。当然,Howard Hinnant的图书馆显然是线程安全的,根本不需要使用TZ

编辑(OP):localtime_rztzalloc的代码可以从https://www.iana.org/time-zones下载,适用于Ubuntu 14.04。

答案 1 :(得分:2)

您可以使用此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使用IANA名称&#34; America / Los_Angeles&#34;创建zoned_time。以及std::chrono::system_clock的当前时间。 zoned_time当时的时区有<{3}} 。该信息是一种名为member getter to get the information的类型,它包含各种有用信息,包括当前的UTC偏移量。

UTC偏移量存储为std::chrono::seconds。标头"chrono_io.h"将格式化durations以进行流式传输。或者sys_info实用程序可用于将持续时间格式化为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

有关此图书馆的更多信息已在Cppcon 2016上展示,可在此处查看:

make_time

答案 2 :(得分:1)

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

gmtime()以UTC计算struct tm,而mktime()则假定struct tm代表当前的本地日历时间。因此,通过进行此循环计算,您可以间接计算当前时区偏移量。

请注意,如果mktime()无法转换为纪元时间,则struct tm会返回错误,这将在标准时间和备用时间之间的某些转换期间发生。在你的情况下,由你决定这意味着什么。

配方看起来像这样:

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,如Steve Summit的答案。如上所述,请注意mktime有时会在不可逆转的时间内返回-1。