16

我正在使用标准mktime函数将 astruct tm转换为纪元时间值。这些tm字段在本地填充,我需要将纪元时间设为 GMT。tm有一个gmtoff字段允许您为此目的以秒为单位设置本地 GMT 偏移量。

但我不知道如何获取这些信息。当然一定有一个标准函数可以返回偏移量吗?怎么localtime做?

4

9 回答 9

23

只需执行以下操作:

#define _GNU_SOURCE /* for tm_gmtoff and tm_zone */

#include <stdio.h>
#include <time.h>

/* Checking errors returned by system calls was omitted for the sake of readability. */
int main(void)
{
  time_t t = time(NULL);
  struct tm lt = {0};

  localtime_r(&t, &lt);

  printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
  printf("The time zone is '%s'.\n", lt.tm_zone);

  return 0;
}

注意:自 epoch 返回的秒数按time()格林威治标准测量。

于 2012-12-10T16:21:19.600 回答
8

localtime 是怎么做的?

根据localtime手册页

localtime() 函数的行为就像它调用 tzset(3) 并设置外部变量 tzname 与有关当前时区的信息, 时区 与协调世界时 (UTC) 和本地标准时间之间的差异(以秒为单位)

所以你可以打电话localtime(),你会有所不同timezone或打电话tzset()

extern long timezone;
....
tzset();
printf("%ld\n", timezone);

注意:如果您选择localtime_r()注意不需要设置这些变量,则需要先调用tzset()set timezone

根据 POSIX.1-2004,localtime() 的行为就像调用了 tzset() 一样,而 localtime_r() 没有这个要求。对于可移植代码 tzset() 应该在 localtime_r() 之前调用

于 2012-12-10T16:32:25.943 回答
6

我想我应该在问之前做更多的搜索。事实证明,有一个鲜为人知的timegm功能与gmtime. 它在 GNU 和 BSD 上受支持,这对我的目的来说已经足够了。更便携的解决方案是将TZ环境变量的值临时设置为“UTC”,然后使用mktime,然后再设置TZ回去。

timegm对我有用。

于 2012-12-10T17:27:59.090 回答
6

获取本地时间偏移功能的通用版本在这里。我从stackoverflow中的这个答案
中 借用了一些代码。

int time_offset()
{
    time_t gmt, rawtime = time(NULL);
    struct tm *ptm;

#if !defined(WIN32)
    struct tm gbuf;
    ptm = gmtime_r(&rawtime, &gbuf);
#else
    ptm = gmtime(&rawtime);
#endif
    // Request that mktime() looksup dst in timezone database
    ptm->tm_isdst = -1;
    gmt = mktime(ptm);

    return (int)difftime(rawtime, gmt);
}
于 2017-05-19T07:07:34.997 回答
2

这是适用于所有标准 C(和 C++)平台的可移植解决方案:

const std::time_t epoch_plus_11h = 60 * 60 * 11;
const int local_time = localtime(&epoch_plus_11h)->tm_hour;
const int gm_time = gmtime(&epoch_plus_11h)->tm_hour;
const int tz_diff = local_time - gm_time;

std::使用 C++ 时添加命名空间。结果以小时为单位,范围为 [-11, 12];

说明: 我们只是将日期时间“1970-01-01 11:00:00”转换为tm两次结构 - 使用本地时区和 GMT。结果是小时部分之间的差异。

选择“11:00::00”是因为这是我们在全球范围内拥有相同日期的唯一时间点(考虑到格林威治标准时间)。由于这个事实,我们不必在计算中考虑随着日期变化而产生的额外魔力。

警告

我的答案的先前版本仅适用于 linux:

// DO NOT DO THAT!!
int timezonez_diff = localtime(&epoch_plus_11h)->tm_hour -
                     gmtime(&epoch_plus_11h)->tm_hour;

这可能不起作用,因为结果tm对象的存储作为指针返回localtime并且gmtime可能是共享的(并且它位于 windows/msvc 上)。这就是我引入临时计算的原因。

于 2020-07-30T14:35:56.213 回答
1

我相信至少在 linux 中是这样的:时区信息来自 /usr/share/zoneinfo/。localtime 读取 /etc/localtime,它应该是 zoneinfo 中相应文件的副本。您可以通过zdump -v对时区文件执行操作来查看里面的内容(zdump 可能在 sbin 中,但您不需要提升权限来读取时区文件)。这是其中的一个片段:

/usr/share/zoneinfo/EST5EDT 2033 年 11 月 6 日星期日 05:59:59 UTC = 2033 年 11 月 6 日星期日 01:59:59 EDT isdst=1 gmtoff=-14400
/usr/share/zoneinfo/EST5EDT 2033 年 11 月 6 日星期日 06:00:00 UTC = 2033 年 11 月 6 日星期日 01:00:00 EST isdst=0 gmtoff=-18000
/usr/share/zoneinfo/EST5EDT 2034 年 3 月 12 日星期日 06:59:59 UTC = 2034 年 3 月 12 日星期日 01:59:59 EST isdst=0 gmtoff=-18000
/usr/share/zoneinfo/EST5EDT 2034 年 3 月 12 日星期日 07:00:00 UTC = 2034 年 3 月 12 日星期日 03:00:00 EDT isdst=1 gmtoff=-14400
/usr/share/zoneinfo/EST5EDT 2034 年 11 月 5 日星期日 05:59:59 UTC = 2034 年 11 月 5 日星期日 01:59:59 EDT

如果你愿意,我想你可以自己解析这个。我不确定是否有一个只返回 gmtoff 的 stdlib 函数(很可能有,但我不知道......)

编辑: man tzfile 描述了 zoneinfo 文件的格式。您应该能够简单地映射到适当类型的结构中。这似乎是 zdump 基于它所做的事情。

于 2012-12-10T16:00:23.090 回答
1

这是受@Hill 和@friedo 答案启发的两条线:

#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;

以秒为单位返回与 UTC 的偏移量。

不需要_GNU_SOURCE定义,但请注意,这timegm不是 POSIX 标准,可能在 GNU 和 BSD 之外不可用。

于 2019-06-11T01:43:19.973 回答
0

就这样结束了。当然 tm_secs 是多余的,只是为了保持一致性。

int timezone_offset() {
    time_t zero = 0;
    const tm* lt = localtime( &zero );
    int unaligned = lt->tm_sec + ( lt->tm_min + ( lt->tm_hour * 60 ) ) * 60;
    return lt->tm_mon ? unaligned - 24*60*60 : unaligned;
}
于 2020-08-25T10:00:24.947 回答
0

这是我的方式:

time_t z = 0;
struct tm * pdt = gmtime(&z);
time_t tzlag = mktime(pdt);

替代自动本地存储struct tm

struct tm dt;
memset(&dt, 0, sizeof(struct tm));
dt.tm_mday=1; dt.tm_year=70;
time_t tzlag = mktime(&dt);

tzlag,以秒为单位,将是 UTC 偏移量的负数;与 UTC 相比,您的时区标准时间滞后:

LocalST + tzlag = UTC

如果您还想考虑“夏令时” ,请在申请后(或使用 获得后)减去特定本地时间tm_isdsttzlag位置。tm_isdststruct tmmktimelocaltime

工作原理:
该集合struct tm用于“纪元”时刻,即 1970 年 1 月 1 日,对应于0。在该日期time_t调用会将其转换为 UTC(因此得到 0),然后从中减去 UTC 偏移量为了产生输出。因此它产生 UTC_offset 的负数。mktime()time_ttime_t

于 2021-11-13T00:17:21.603 回答