我读过很多很多关于 Unix 时间的帖子,很多人说一天是 86400 秒。
但像这样的页面谈论的是闰秒。这让我很困惑。我读到Unix时间是基于UTC的,我所能理解的是UTC和TAI之间的区别是闰秒,所以Unix必须支持闰秒,否则为什么不说基于TAI而不是UTC呢?
为了让自己更加困惑,我试图看看 Windows 做了什么,我发现的答案是它不计算闰秒,但它说基于 UTC,再次令人困惑,如果不计算闰秒为什么要说 UTC?
不管怎样,我想问一下在 Unix 中如何将整数秒转换为精确日期?
ilk*_*chu 23
我读过很多很多关于 Unix 时间的帖子,很多人说一天是 86400 秒。
这就是定义,是的。
但像这样的页面谈论的是闰秒。这让我很困惑。
你并不是唯一的一个。这是一个搞笑的混乱。
我读到 Unix 时间是基于 UTC
是的,见下文。
我能理解的是UTC和TAI之间的区别是闰秒
是的。
那么Unix必须支持leap
事实并非如此。它实际上闭上了眼睛,拒绝听任何关于这种尴尬和不切实际的技术问题的讨论。
“自纪元以来的秒数”的 POSIX 定义基于细分的 UTC 时间,明确假设所有日期的长度均为 86400 秒:
自纪元以来 4.15 秒
一个近似自纪元以来经过的秒数的值。协调世界时[UTC]名称(以秒 ( tm_sec )、分钟 ( tm_min )、小时 ( tm_hour )、自当年 1 月 1 日起的天数 ( tm_yday ) 和日历年减去 1900 ( tm_year ) 指定)相关根据下面的表达式,以自纪元以来的秒数表示的时间。
如果年份 <1970 或值为负,则关系未定义。如果年份 >=1970 并且该值为非负,则根据 C 语言表达式,该值与协调世界时名称相关,其中tm_sec、tm_min、tm_hour、tm_yday和 tm_year都是整数类型:
Run Code Online (Sandbox Code Playgroud)tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400一天中的实际时间与自纪元以来的当前秒数之间的关系未指定。
如何对自纪元以来的秒值进行任何更改以与当前实际时间保持所需的关系是由实现定义的。按照自纪元以来的秒数表示,每一天应精确计算 86400 秒。
( 的奇数处理tm_year是为了考虑闰日;除法是截断整数除法。)
基本原理部分直接承认忽略闰秒:
协调世界时 (UTC) 包括闰秒。然而,在 POSIX 时间(自纪元以来的秒数)中,闰秒被忽略(不应用),以提供一种简单且兼容的计算时间差的方法。因此,尽管其外观如此,分解后的 POSIX 时间不一定是 UTC。
上面的表达式意味着当插入闰秒时,“自纪元以来的秒数”会重复一整秒:
UTC 1972-06-30 23:59:59 = 78796799 seconds since epoch
UTC 1972-06-30 23:59:60 = 78796800 seconds since epoch
UTC 1972-07-01 00:00:00 = 78796800 seconds since epoch
UTC 1972-07-01 00:00:01 = 78796801 seconds since epoch
Run Code Online (Sandbox Code Playgroud)
这意味着要么自纪元以来的那些“秒”的长度(物理上)并不相同,要么纪元本身实际上“移动”。随你挑选。
如上所述,一秒是两(物理,SI / UTC)秒长,所以显然它们的长度并不相同。
如果您采用“所有天都是 86400 秒”的定义,假设长度恒定的 SI 秒并对此进行回溯,则纪元“移动”如下所示。(也就是说,由于 UTC 1972-07-01 00:00:00 是 UTC 1970-00-01 00:00:01 之后的 78796800 SI 秒,因此它必须是当时的有效纪元。)
好吧,他们确实用“大约”来对冲。
此外,这是不存在简单但精确的解决方案的情况之一。你可以从三个好东西中选择任何两个,并且必须忍受其中一个
为了简化日期计算,POSIX 拒绝 (a),但在其他方面则匹配 UTC 以匹配民用时间,因此拒绝 (c) 并选择接受缺点 (b)。基本原理中明确提到了计算的简单性:
自纪元以来的秒数是否应考虑闰秒的话题已经在很多场合进行了争论,每次都达成共识(每次都承认不同意见):对大多数用户来说,最好对所有日期进行相同的处理。(也就是说,大多数应用程序被判定为假设所有天都采用单一长度(以自纪元以来的秒为单位进行测量)。因此,闰秒不适用于自纪元以来的秒数。)
(“一天中的实际时间与自纪元以来秒数的当前值之间的关系未指定。”这句话本身很奇怪,因为几乎所有实际目的 UTC 都是“一天中的实际时间”,并且定义上面依赖于 UTC。我不确定它指的是什么,但我认为这只是说系统时钟不需要准确。而且,如果没有外部同步,大多数计算机时钟都不需要。
同样,“因此,尽管出现了 POSIX 时间,但其具体时间并不一定是 UTC。” 基本原理部分看起来很奇怪,但适用于闰秒。否则,给定的等价似乎意味着分解的 POSIX 时间是UTC。)
但不要指望我能把它弄对,因为聪明的人已经写了足够多的文章了。
Alex Chan简要介绍了程序员对 Unix 时间的误解。
SE 帖子Unix 时间和闰秒包含一些讨论,并链接到 David Madore 发表的听起来令人信服的帖子“Unix 闰秒混乱”。
那个提到了在 NTP 中处理这个问题,红帽开发者博客中有五种不同的方法来使用 NTP 处理闰秒。
其中一种方法当然是谷歌在 2008 年开始使用的“leap smearing”。也就是说,用一个双倍长度的秒来替换大量的稍微偏离的秒。(强制XKCD)
Unix时间的维基百科页面有一个与上面类似的表格,显示了重复值,同时还包括 TAI 和 UTC。
不管怎样,我想问一下在 Unix 中如何将整数秒转换为精确日期?
取决于具体是哪几秒......
如果是 Unix 时间,除以 86400 即可得到天数,然后遵循有关可变长度月份、闰日和时区的通常规则。
或者更确切地说,打电话localtime()或gmtime()为您做这件事。
如果是其他时间,请使用一些可以处理您所拥有的内容的库。
Mar*_*ler 12
您混淆了多个概念。UNIX 时间(从足够的高度来看)是一个秒计数器,这只是一个本地概念。最后,有人拿着一个时钟给你说“根据这个漂亮的时钟,现在距离 1970 年 1 月 1 日已经过去了多少秒”,你就说“好吧,那么现在距离 1970 年 1 月 1 日已经过去了多少秒” ”并继续数秒。这对于许多“家庭”计时用途来说是可以的,例如,存储您上次更改日记文档的时间。TAI也只是一个秒计数器,但它是一个协调的计数器,这意味着它不仅仅是本地的时间计数,而是许多原子钟的平均值。
\nUTC 是完全不同的东西:它定义了\xe2\x80\x93的时间,而不仅仅是自某个常见事件以来的秒数。
\n例如,在许多情况下,“自纪元以来已有一千四百二十万二十六秒”不如说“这里是早上 9 点 12 分,今天是六月六号”有用。
\n需要明确的是:“UNIX 时间”只是自特定事件(纪元)以来经过的秒数。如果您有一个每秒滴答一次的完美节拍器,并且您计算了自该日期以来的滴答数,那就是 UNIX 时间。(如果不是因为这个计数器实际上是从 UTC 派生的,每次 UTC 插入闰秒时,该计数器都会有效地将纪元向前移动一秒。)
\n现在,您的困惑源于这样一个事实:例如 1697300527(这是几秒钟前的 UNIX 时间)对于人类来说并不是一个非常有用的时间。您需要将第二个计数转换为人类可读的日期时间(例如,2023 年 10 月 14 日星期六 18:22:01)。
\n时间转换当然必须考虑闰年、闰秒、时区和其他修正。这意味着从 UNIX 时间到 UTC 时间或任何其他时间表示形式的转换不一定是平滑、连续的,甚至是明确的。(例如:可能有多个 UNIX 时间戳对应于您所在时区夏令时结束当天的凌晨 3:15。)
\n就是这样。虽然您总是可以“轻松且明确地”说“自纪元以来现在已经有这么多秒了”,但只需计算从那时起的秒数(这就是 UNIX 时间),即可转换为本地时间(或协调时间)出于人类目的的表示可以是非单调的。
\n\n\n不管怎样,我想问一下在 Unix 中如何将整数秒转换为精确日期?
\n
通过使用您的平台拥有的时区信息。Chris Davies 建议使用date,我同意。任何合理的编程语言\xc2\xb9都可以访问tzinfo数据库。
\xc2\xb9 C: ctime(\xe2\x80\xa6)、C++:、std::chronoPython: python -c 'import datetime;print(datetime.datetime.now())'、Perl、Haskell、\xe2\x80\xa6)