`gmtime()`会在闰秒时报告秒为60?

Yuk*_*uki 14 c time posix utc unix-timestamp

我有一台运行的服务器TZ=UTC,我有这样的代码:

time_t t = time(NULL);
struct tm tm;
gmtime_r(&t, &tm);
Run Code Online (Sandbox Code Playgroud)

问题是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
Run Code Online (Sandbox Code Playgroud)

gmtime()返回tm == 1998-12-31T23:59:60time_t = 915148800,一旦出了闰秒,回归tm == 1999-01-01T00:00:00为同time_t

Ste*_*mit 11

简短的回答是,不,实际上说gmtime_r永远不会填写tm_sec60.这是不幸的,但不可避免.

根据time_tPosix标准,基本问题是自1970-01-01 UTC以来的秒数,假设没有闰秒.

在最近的闰秒期间,进展如下:

1483228799    2016-12-31 23:59:59
1483228800    2017-01-01 00:00:00
Run Code Online (Sandbox Code Playgroud)

是的,那里应该有一个闰秒23:59:60.但有没有可能time_t在两者之间价值14832287991483228800.

我知道gmtime变体返回时间的两种方式:60:

  1. 您可以在UTC以外的其他设备上运行OS时钟,通常是TAI或TAI-10,并使用所谓的"正确"时区转换为UTC(或本地时间)进行显示.有关此问题的一些讨论,请参阅此网页.

  2. 您可以使用clock_gettime()和定义一个新的clkid值,CLOCK_UTC它可以在必要时time_t使用故意非标准化值来解决问题struct timespec.例如,方式之间得到一个时间值14832287991483228800是设置tv_sec1483228799tv_nsec1000000000.有关详细信息,请参阅此网页.

方式#1运行良好,但是没有人使用它,因为没有人想要在除了它应该是的UTC之外的任何东西上运行它们的内核时钟.(你最终遇到文件系统时间戳等问题,以及tar嵌入这些时间戳的程序.)

方式#2是一个美丽的想法,IMO,但据我所知,它从未在已发布的操作系统中实现.(碰巧,我有一个适用于Linux的工作实现,但我还没有发布我的工作.)为了使#2工作,你需要一个新的gmtime变体gmtime_ts_r,它可以接受一个struct timespec而不是一个time_t.


附录:我刚读过你的问题标题.你问," gmtime()当服务器处于闰秒时,会报告60秒吗?" 我们可以通过说"是的,但是"来回答这个问题,并且免责声明由于大多数服务器在闰秒期间无法正常表示时间,因此它们永远不会 "on"闰秒.


附录2:我忘了提到方案#1似乎在本地时间更好 - 也就是说,当你调用其中一个localtime变种时 - 而不是UTC时间和gmtime.很明显,执行的转换localtime会受到TZ环境变量设置的影响,但是不太清楚会对其TZ产生任何影响gmtime.我观察到一些gmtime实现受到影响,TZ因此可以根据"正确"区域执行闰秒,而有些则不能.尤其是gmtimeGNU glibc的似乎要注意闰秒信息在"正确"的区域,如果TZ指定一个,而gmtimeIANA tzcode分布没有.

  • 关于"gmtime_r永远不会用60填充tm_sec",这不是真的.请参阅http://coliru.stacked-crooked.com/a/622da23fd57dabca. (2认同)

dus*_*uff 5

问题是tm.tm_sec == 60服务器何时处于闰秒之内?

在典型的UNIX系统上,time_t计算自纪元以来的非闰秒数(1970-01-01 00:00:00 GMT).因此,将a转换time_t为a struct tm将始终产生tm_sec值为0到59之间的时间结构.

忽略time_t计算中的闰秒使得可以在time_t不完全了解该时间之前的所有闰秒的情况下将a转换为人类可读的日期/时间.它还可以time_t在将来明确地转换值; 包括闰秒会使这种情况变得不可能,因为未来6个月之后不知道闰秒的存在.

UNIX和类UNIX系统有几种方法可以处理闰秒.最典型的是:

  1. time_t闰秒重复一个值.(这是严格解释标准的结果,但会导致许多应用程序出现故障,因为时间似乎已经倒退了.)

  2. 在闰秒周围的一段时间内,系统时间稍微慢一些,以便在更长的时间内"涂抹"闰秒.(此解决方案已被许多大型云平台采用,包括谷歌亚马逊.它避免了任何本地时钟不一致,但代价是在受影响的系统长达半秒的时间内与UTC不同步.)

  3. 系统时间设置为TAI.由于这不包括闰秒,因此不需要闰秒处理.(这种情况很少见,因为它会使系统与UTC系统几秒钟不同步,这些系统构成了世界上大部分地区.但对于那些与外界几乎没有联系的系统来说,它可能是一个可行的选择,因此没有办法学习即将到来的闰秒.)

  4. 系统完全没有意识到闰秒,但是它的NTP客户端将在闰秒使系统的时钟从正确的时间离开一秒后纠正时钟.(这就是Windows所做的.)