我有一个服务器在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:60time_t之间不可能存在1483228799值。
我知道1483228800变量返回以gmtime结尾的时间的两种方法:
您可以在非UTC(通常是TAI或TAI-10)上运行操作系统时钟,并使用所谓的“正确”时区转换为UTC(或本地时间)进行显示。请参见this web page了解有关此的一些讨论。
您可以使用:60并定义一个新的clkid值,可能是clock_gettime(),这可以在必要时通过故意使用非规范化的CLOCK_UTC值来解决time_t问题。例如,获取struct timespec1483228799之间的时间值的方法是将1483228800设置为tv_sec1483228799设置为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则不注意。

10-08 09:45