我有一个服务器在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()
是否返回tm == 1998-12-31T23:59:60
表示time_t = 915148800
,一旦超出闰秒,是否返回tm == 1999-01-01T00:00:00
表示相同的time_t
? 最佳答案
简短的回答是,不,实际上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
之间不可能存在1483228799
值。我知道
1483228800
变量返回以gmtime
结尾的时间的两种方法:您可以在非UTC(通常是TAI或TAI-10)上运行操作系统时钟,并使用所谓的“正确”时区转换为UTC(或本地时间)进行显示。请参见this web page了解有关此的一些讨论。
您可以使用
:60
并定义一个新的clkid值,可能是clock_gettime()
,这可以在必要时通过故意使用非规范化的CLOCK_UTC
值来解决time_t
问题。例如,获取struct timespec
和1483228799
之间的时间值的方法是将1483228800
设置为tv_sec
和1483228799
设置为tv_nsec
。有关详细信息,请参见this web page。way 1工作得很好,但是没有人使用它,因为没有人想在除了它应该是的UTC以外的任何东西上运行内核时钟。(最终会遇到文件系统时间戳之类的问题,以及嵌入这些时间戳的
1000000000
之类的程序的问题。)Way 2是一个很好的想法,IMO,但据我所知,它从未在发布的操作系统中实现过。(碰巧,我有一个Linux的工作实现,但我还没有发布我的工作。)要想让Way 2工作,您需要一个新的
tar
变体,可能是gmtime
,它接受一个gmtime_ts_r
而不是一个struct timespec
。补遗:我刚刚重读了你的题目。您问:“当服务器处于闰秒时,
time_t
会报告60秒吗?”我们可以通过说“是的,但是”来回答这个问题,并声明由于大多数服务器不能正确地表示闰秒期间的时间,它们永远不会“在”闰秒。附录2:我忘了提到Scheme 1在本地时间(也就是说,当您调用
gmtime()
变体之一时)的效果似乎比在UTC时间和localtime
更好。显然gmtime
执行的转换受localtime
环境变量设置的影响,但是还不清楚TZ
是否对TZ
有任何影响。我观察到,有些gmtime
实现受gmtime
的影响,因此可以根据“正确”区域执行闰秒,而有些则不能。特别地,GNU glibc中的TZ
似乎注意到“右”区域中的闰秒信息,如果gmtime
指定了一个,而IANA tzcode distribution中的TZ
则不注意。