我正在使用标准的mktime
函数将struct tm
转换为时期时间值。 tm
字段本地填充,我需要将时期时间作为格林威治标准时间获得。
tm
有一个gmtoff
字段,可以让您设置本地GMT偏移量(以秒为单位)以实现此目的。
但是我无法找到如何获取此信息。一定有标准函数可以返回偏移量吧?localtime
是如何做到的呢?
只需执行以下步骤:
#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()
返回的自纪元以来的秒数是按格林威治时间计算的。struct tm = {0};
应该改成 struct tm result = {0};
,然后在代码的其余部分可以使用 result
代替 tm
。如果你能改变那个,我会点赞的。 - Serranotm_gmtoff
和tm_zone
是非C标准的扩展。 - chux - Reinstate Monica%lds
是什么意思。结果是 %ld
和 s
:D - Zhangextern long timezone;
....
tzset();
printf("%ld\n", timezone);
localtime_r()
,请注意不需要设置那些变量,您需要先调用 tzset()
来设置 timezone
:localtime()
必须表现得好像已经调用了 tzset()
,而 localtime_r()
没有这个要求。对于可移植的代码,在调用 localtime_r()
之前应该先调用 tzset()
。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);
}
timegm
函数,它可以做与gmtime
相反的操作。它被GNU和BSD支持,这对我的需求来说足够好了。更具可移植性的解决方案是将TZ
环境变量的值暂时设置为“UTC”,然后使用mktime
,最后再设置TZ
回来。timegm
很适合。这是一种便携式解决方案,应该在所有标准的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::
命名空间。结果在范围[-11,12]小时内。tm
结构 - 使用本地时区和GMT。结果是小时部分的差异。// DO NOT DO THAT!!
int timezonez_diff = localtime(&epoch_plus_11h)->tm_hour -
gmtime(&epoch_plus_11h)->tm_hour;
这可能不起作用,因为从localtime
和gmtime
返回的指向 tm
对象的指针可能是共享的(在 Windows/msvc 上确实如此)。这就是我引入计算临时变量的原因。
UTC-12
到UTC+14
。 - aafulei以下是受@Hill和@friedo答案启发的两行代码:
#include <time.h>
...
time_t rawtime = time(0);
timeofs = timegm(localtime(&rawtime)) - rawtime;
我相信在Linux中以下内容是正确的:时区信息来自于/usr/share/zoneinfo/。localtime读取/etc/localtime,它应该是来自zoneinfo的适当文件的副本。您可以通过对时区文件执行zdump -v
来看到其中的内容(zdump可能在sbin中,但您无需获取权限即可使用它读取时区文件)。这里是一个片段:
这里是一个线程安全的方法,取自我对此帖子的回答:
什么是在UTC / GMT中获取一天的开始的正确方法?
::time_t GetTimeZoneOffset ()
{ // This method is to be called only once per execution
static const seconds = 0; // any arbitrary value works!
::tm tmGMT = {}, tmLocal = {};
::gmtime_r(&seconds, &tmGMT); // ::gmtime_s() for WINDOWS
::localtime_r(&seconds, &tmLocal); // ::localtime_s() for WINDOWS
return ::mktime(&tmGMT) - ::mktime(&tmLocal);
};
这是我的方法:
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之间的偏差:
LocalST + tzlag = UTC
如果您还想考虑“夏令时”的影响,请从tzlag
中减去tm_isdst
,其中tm_isdst
是特定本地时间struct tm
的一部分,在应用mktime
(或使用localtime
)后获得。
它为什么有效:
设置的struct tm
是“纪元”时刻,即1970年1月1日,对应于time_t
为0。
在该日期上调用mktime()
将其转换为time_t
,就好像它是UTC(因此获得0),然后从中减去UTC偏移量,以产生输出time_t
。因此,它生成了UTC_offset的负值。
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;
}
tm
具有gmtoff
字段”--> 这是一个非标准的C库扩展。 - chux - Reinstate Monica