本文介绍了当处于闰秒时,`gmtime()`会报告为60秒吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个服务器在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_t1483228800之间没有可能的time_t值。

我知道gmtime变量返回以:60结尾的时间的两种方式:

  1. 您可以在UTC以外的时间运行操作系统时钟,通常是TAI或TAI-10,并使用所谓的"正确"时区将其转换为UTC(或本地时间)进行显示。有关此问题的某些讨论,请参阅this web page

  2. 您可以使用clock_gettime()并定义一个新的CLKID值,可能是CLOCK_UTC,它可以在必要时故意使用非规范化的struct timespec值来绕过time_t问题。例如,获取14832287991483228800之间时间值的方法是将tv_sec设置为1483228799,将tv_nsec设置为1000000000。有关详细信息,请参阅this web page

方法#1工作得很好,但是没有人使用它,因为没有人想在UTC之外的任何地方运行内核时钟。(最终文件系统时间戳和嵌入这些时间戳的程序(如tar)会出现问题。)

方法2是一个很好的想法,IMO,但据我所知,它从未在发布的操作系统中实现过。(碰巧的是,我有一个可以工作的Linux实现,但是我还没有发布我的工作。)要使方法#2工作,您需要一个新的gmtime变体,可能是gmtime_ts_r,它接受struct timespec而不是time_t


附录:我刚刚重读了您的问题标题。您问,"当服务器处于Leap秒时,gmtime()会报告60秒吗?"我们可以通过回答"是,但是"来回答这个问题,但要声明的是,由于大多数服务器不能正确表示闰秒内的时间,它们从不"在"闰秒。


附录2:我忘了提一下,方案1似乎更适合本地时间--也就是当您调用localtime变体时--比在UTC时间和gmtime下更好。很明显,localtime执行的转换受TZ环境变量设置的影响,但TZgmtime是否有影响还不是很清楚。我观察到一些gmtime实现受到TZ的影响,因此可以按照"正确"区域进行闰秒,而有些则不能。具体地说,如果TZ指定了闰秒信息,则GNU glibc中的gmtime似乎会注意"右"区域中的闰秒信息,而IANA tzcode distribution中的gmtime则不会。

这篇关于当处于闰秒时,`gmtime()`会报告为60秒吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-17 01:05