问题描述
我有一个服务器在TZ=UTC
中运行,代码如下:
time_t t = time(NULL);
struct tm tm;
gmtime_r(&t, &tm);
问题是,当服务器在闰秒内时,tm.tm_sec == 60
会吗?
例如,如果我处于以下时间跨度:
1998-12-31T23:59:60.00 - 915 148 800.00
1998-12-31T23:59:60.25 - 915 148 800.25
1998-12-31T23:59:60.50 - 915 148 800.50
1998-12-31T23:59:60.75 - 915 148 800.75
1999-01-01T00:00:00.00 - 915 148 800.00
gmtime()
是否为time_t = 915148800
返回tm == 1998-12-31T23:59:60
,一旦超出闰秒,是否为相同的time_t
返回tm == 1999-01-01T00:00:00
?
推荐答案
简短的答案是,不,实际上gmtime_r
永远不会用60填充tm_sec
。这很不幸,但无法避免。
基本问题是,根据POSIX标准,time_t
是自1970-01-01 UTC假设没有闰秒以来的秒数。
在最近的闰秒期间,进程如下:
1483228799 2016-12-31 23:59:59
1483228800 2017-01-01 00:00:00
是的,里面应该有闰秒,23:59:60
。但是time_t
和1483228800
之间没有可能的time_t
值。我知道gmtime
变量返回以:60
结尾的时间的两种方式:
您可以在UTC以外的时间运行操作系统时钟,通常是TAI或TAI-10,并使用所谓的"正确"时区将其转换为UTC(或本地时间)进行显示。有关此问题的某些讨论,请参阅this web page。
您可以使用
clock_gettime()
并定义一个新的CLKID值,可能是CLOCK_UTC
,它可以在必要时故意使用非规范化的struct timespec
值来绕过time_t
问题。例如,获取1483228799
和1483228800
之间时间值的方法是将tv_sec
设置为1483228799
,将tv_nsec
设置为1000000000
。有关详细信息,请参阅this web page。
tar
)会出现问题。)方法2是一个很好的想法,IMO,但据我所知,它从未在发布的操作系统中实现过。(碰巧的是,我有一个可以工作的Linux实现,但是我还没有发布我的工作。)要使方法#2工作,您需要一个新的gmtime
变体,可能是gmtime_ts_r
,它接受struct timespec
而不是time_t
。
附录:我刚刚重读了您的问题标题。您问,"当服务器处于Leap秒时,
gmtime()
会报告60秒吗?"我们可以通过回答"是,但是"来回答这个问题,但要声明的是,由于大多数服务器不能正确表示闰秒内的时间,它们从不"在"闰秒。附录2:我忘了提一下,方案1似乎更适合本地时间--也就是当您调用
localtime
变体时--比在UTC时间和gmtime
下更好。很明显,localtime
执行的转换受TZ
环境变量设置的影响,但TZ
对gmtime
是否有影响还不是很清楚。我观察到一些gmtime
实现受到TZ
的影响,因此可以按照"正确"区域进行闰秒,而有些则不能。具体地说,如果TZ
指定了闰秒信息,则GNU glibc中的gmtime
似乎会注意"右"区域中的闰秒信息,而IANA tzcode distribution中的gmtime
则不会。 这篇关于当处于闰秒时,`gmtime()`会报告为60秒吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!