我正在使用标准mktime
函数将struct tm
转换为纪元时间值。 tm
字段在本地填充,我需要将纪元时间作为GMT。 tm
有一个gmtoff
字段,允许您为此目的设置本地GMT偏移量(以秒为单位)。
但我无法弄明白如何获取这些信息。当然必须有某个标准函数来返回偏移量? localtime
如何做到这一点?
答案 0 :(得分:20)
请执行以下操作:
#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, <);
printf("Offset to GMT is %lds.\n", lt.tm_gmtoff);
printf("The time zone is '%s'.\n", lt.tm_zone);
return 0;
}
注意:time()
返回的纪元以来的秒数就像在格林威治一样。
答案 1 :(得分:6)
本地时间如何做到这一点?
根据localtime
手册页
localtime()函数就好像它调用了tzset(3)并设置了 外部变量tzname包含有关当前时区的信息, timezone 与Coordinated Universal之间的差异 时间(UTC)和本地标准时间(秒)
因此,您可以致电localtime()
,但timezone
或tzset()
会有所不同:
extern long timezone;
....
tzset();
printf("%ld\n", timezone);
注意:如果您选择localtime_r()
,请注意不需要设置这些变量,您需要先调用tzset()
来设置timezone
:
根据POSIX.1-2004,localtime()需要表现得像 调用tzset(),,而localtime_r()没有这个 需求。对于可移植代码,应该先调用tzset() 则localtime_r()强>
答案 2 :(得分:6)
我想在问之前我应该多做一些搜索。事实证明,有一个鲜为人知的timegm
函数与gmtime
相反。它支持GNU和BSD,这对我的目的来说已经足够了。更便携的解决方案是暂时将TZ
环境变量的值设置为“UTC”,然后使用mktime
,然后再设置TZ
。
但timegm
对我有用。
答案 3 :(得分:4)
获取本地时间偏移功能的通用版本在这里 我从statckoverflow中的the answer借了一些代码
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);
}
答案 4 :(得分:0)
我认为至少在Linux中存在以下情况:时区信息来自/ usr / share / zoneinfo /。 localtime读取/ etc / localtime,它应该是zoneinfo中相应文件的副本。您可以通过在时区文件上执行zdump -v
来查看内部情况(zdump可能位于sbin中,但您不需要提升权限来读取时区文件)。这是一个剪辑:
/usr/share/zoneinfo/EST5EDT Sun Nov 6 05:59:59 2033 UTC = Sun Nov 6 01:59:59 2033 EDT isdst=1 gmtoff=-14400 /usr/share/zoneinfo/EST5EDT Sun Nov 6 06:00:00 2033 UTC = Sun Nov 6 01:00:00 2033 EST isdst=0 gmtoff=-18000 /usr/share/zoneinfo/EST5EDT Sun Mar 12 06:59:59 2034 UTC = Sun Mar 12 01:59:59 2034 EST isdst=0 gmtoff=-18000 /usr/share/zoneinfo/EST5EDT Sun Mar 12 07:00:00 2034 UTC = Sun Mar 12 03:00:00 2034 EDT isdst=1 gmtoff=-14400 /usr/share/zoneinfo/EST5EDT Sun Nov 5 05:59:59 2034 UTC = Sun Nov 5 01:59:59 2034 EDT
我想你可以自己解析这个问题。我不确定是否有一个stdlib函数只返回gmtoff(可能会有,但我不知道......)
编辑: man tzfile描述了zoneinfo文件的格式。您应该能够简单地映射到适当类型的结构。它似乎是zdump基于其所做的事情。
答案 5 :(得分:0)
这里有两条线,灵感来自@Hill和@friedo的答案:
#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;
以秒为单位返回UTC的偏移量。
不需要定义_GNU_SOURCE
,但是请注意,timegm
不是POSIX标准,在GNU和BSD之外可能不可用。
答案 6 :(得分:0)
这是可移植的解决方案,可以在所有标准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;
使用C ++时添加std::
命名空间。结果以小时为单位,范围为[-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上)。这就是我介绍临时计算的原因。
答案 7 :(得分: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;
}