日期 - 无法返回超过 115 年或无法进入未来 5879565 年

Bog*_*Bog 16 date timestamps command date-utility

    \n
  • 时区 = CEST
  • \n
  • 日期(GNU coreutils)8.32
  • \n
\n
date -d "115 years ago"\nDi 11. Aug 13:37:54 CET 1908\n
Run Code Online (Sandbox Code Playgroud)\n
date -d "116 years ago"\ndate: invalid date \xe2\x80\x98116 years ago\xe2\x80\x99\n
Run Code Online (Sandbox Code Playgroud)\n
\n

问题

\n
    \n
  1. 是否有可能回到115 years过去或未来5879565 years
  2. \n
  3. 为什么会发生这种情况并引发错误?这些奇数从何而来?
  4. \n
  5. 为什么date -d "200 years ago 14 Mar "突然就可以工作了呢?
  6. \n
\n

Pop*_*pup 20

有许多几乎兼容的计算时间和日期的方法。

“传统”unix 时间从 1970 年(又名“纪元”)开始计算秒数。这在 32 位表示中存在一个巨大的问题,它将在 2038 年 1 月 19 日星期二 ( ) 遇到整数溢出date -d "@$((0x7fffffff))"

更“现代”的方法是在 64 位计数器中计算纳秒。

GNU coreutils 'date' 将日期解析委托给parse-datetime2.y,这是 2500 行 bison 代码。该行为还取决于环境。例如,使用 coreutils 8.32,我在 Cygwin 和 Ubuntu 下得到不同的行为,即使它们都是从相同的源编译的。我还在coreutils 8.2264 位 CentOS7 上运行,它接受从“20000000000 年前”到“20000000000 年”的日期

总之 - 这取决于您的实施date

编辑添加:

菲利普·库林(Philip Couling)有一些发现。时区很难正确处理。

另外,请阅读《程序员关于时间的谎言》。时间似乎是一个简单的话题,但要正确处理它却很困难。

  • 您指的是Y2.038K问题吗?:) (3认同)
  • Unix 时间和 UTC 之间的关系……很复杂。请参阅 https://unix.stackexchange.com/q/283​​164/88378 另请参阅 https://www.ucolick.org/~sla/leapsecs/epochtime.html 和 [时间尺度简史](https:// www.ucolick.org/~sla/leapsecs/timescales.html) (3认同)

Phi*_*ing 13

我强烈怀疑这里的最小限制115 years ago(1908)是由您的时区引起的。但由于您没有提到您所在的时区,我无法确定。

大多数计算机系统要么设置为 UTC,要么设置为指定的地理时区,通常引用城市,例如Europe/London。地理时区考虑到政府更改某个地方的时区,并且需要特定日期/时间特定位置的时区数据库。这允许日期/时间在夏令时变化和大多数政治愚蠢行为中发挥作用。

因此,最有可能的情况是,您所在的时区仅记录了 1908 年左右的时区偏移量。另一方面,UTC 计算将无限期地回溯,因为时区数据库使用 UTC(以及 1960 年之前的 UT [GMT])作为参考时间。

时区的概念确实是一个令人惊讶的新概念,第一次同步发生在1840 年。在此之前的任何时区计算都将是混乱的猜测,并且可能涉及大陆漂移的调整。


未来 5879565 年的计算很可能是系统性的,并且与 Unix 时间相关(自 1970 年 1 月 1 日 GMT 以来的秒数,不考虑 UTC 闰秒)。

但也应该小心相信未来的计算。您不知道 100 年后某个地区的时区是什么。而且该代码当然没有考虑到 580 万年来相对于格林威治的巨大漂移。

  • (在 Debian 测试系统上 `TZ=Europe/London date -d '@-6857654325'` 返回 1752-09-09 日期,尽管[伦敦从来没有这样的日期,因为他们从儒略历切换到公历历法那次](https://www.history.co.uk/article/the-calendar-riots-of-1752-when-britain-lost-11-days) (2认同)
  • 正确的。`for f (/usr/share/zoneinfo*/*/*(.:t2)) TZ=$f date -d '116 年前' >& /dev/null || 在 Ubuntu 22.04(和 zsh 中)上 echo $f` 返回相当多的内容(包括我在欧洲和美国测试过的所有内容),但不是全部。在 Debian 测试中, `for f (/usr/share/zoneinfo*/*/*(.:t2)) TZ=$f date -d '20000 年前' >& /dev/null || echo $f` 不会失败。 (2认同)

Áng*_*gel 6

这实际上取决于您正在使用的实现:

\n

在我的版本中,没有这样的限制:

\n
$ date -d "120 years ago"\nWed 12 Aug 14:20:26 UTC 1903\n\n$ date -d "5000 years ago"\nTue 12 Aug 14:21:26 UTC -2977\n
Run Code Online (Sandbox Code Playgroud)\n

(当然,对于如此早的日期,所使用的预产历必须持保留态度)

\n
$ date -d "+9879566 years"\nSat 12 Aug 14:24:17 UTC 9881589\n\n$ date -d "+1000000000 years"\nSat 12 Aug 14:23:39 UTC 1000002023\n
Run Code Online (Sandbox Code Playgroud)\n

它让我可以上下移动超过 200 万年:

\n
$ date -d "+2147483524 years"\nTue 12 Aug 14:29:19 UTC 2147485547\n\n$ date -d "+2147483525 years"\ndate: invalid date \'+2147483525 years\'\n
Run Code Online (Sandbox Code Playgroud)\n

(124年小于2\xc2\xb3\xc2\xb9 = 2147483648)

\n
$ date -d "2147483772 years ago"\ndate: invalid date \'2147483772 years ago\'\n\n$ date -d "2147483771 years ago"\nThu 12 Aug 14:32:23 UTC -2147481748\n
Run Code Online (Sandbox Code Playgroud)\n

(123年小于2\xc2\xb3\xc2\xb9 = 2147483648)

\n

struct tm这表明在最初计算要添加或减去的年数时,它在内部使用 tm_year (从 1900 年开始)的 32 位有符号值。

\n