【问题标题】:Why can JavaScript handle timestamps beyond 2038?为什么 JavaScript 可以处理超过 2038 的时间戳?
【发布时间】:2013-11-14 14:42:42
【问题描述】:

我们知道,所有使用 Javascript Date 构造函数的日期都是从 1970 年 1 月 1 日 00:00:00 世界标准时间 (UTC) 开始以毫秒为单位计算的,其中一天包含 86,400,000 毫秒。这意味着 JS 使用 UNIX 时间戳。我将计时器设置为 2038 年之后的日期(比如 2039 年 11 月 14 日)并运行脚本:

    <script>
      var d = new Date();
      alert(d.getFullYear()+" "+d.getMonth()+" "+d.getDate());
    </script>

它成功提醒 2039 10 14,不像 PHP 打印“9 Oct, 1903 07:45:59”

JS 是如何处理这个问题的?由于我很困惑,因此感谢您的解释!

【问题讨论】:

    标签: javascript php


    【解决方案1】:

    32 位 PHP 使用 32 位整数,其最大值将它们表示的最后一个 UNIX 时间戳放在 2038 年。这被广泛称为Y2K38 problem,并且几乎影响所有使用 UNIX 时间戳的 32 位软件。迁移到 64 位或使用其他时间戳表示的库(在 PHP 的情况下为 DateTime 类)解决了这个问题。

    Javascript 没有整数,只有 floats,它没有固有的最大值(但精度较低)。

    【讨论】:

    • 我不明白为什么 PHP 不会只使用无符号整数。这实际上会使日期范围翻倍,对吧?
    • @Alex 因为那时你不能表示任何日期before 1970,因为 PHP 试图保持类型简单并且不想让程序员担心签名和无符号整数,因为使用 only 无符号整数意味着您不能在 PHP 中表示 any 负数,因为这只会将截止日期延长大约 70 年,而不是解决它完全。
    • @AlexW 这是为了保存 1970 年之前的日期,这在 UNIX 时间戳中被视为一个纪元,对吧?
    • 还有一件事要问@deceze,因为 long int 是 4 个字节,float 也是 4 个字节(尽管在 C 中),那么 JS 使用 float 而不是 int 会怎样......?
    • @rosemary 怎么样?不知道你在问什么。
    【解决方案2】:

    Javascript 没有整数,只有浮点数(详见the standards document)。

    这意味着您可以表示一些非常大的数字,但要以精度为代价。一个简单的测试是这样的:

    i = 1384440291042
     => 1384440291042
    i = 13844402910429
     => 13844402910429
    i = 138444029104299
     => 138444029104299
    i = 1384440291042999
     => 1384440291042999
    i = 13844402910429999
     => 13844402910430000
    i = 138444029104299999
     => 138444029104300000
    i = 1384440291042999999
     => 1384440291043000000
    i = 13844402910429999999
     => 13844402910430000000
    

    如您所见,不能保证该数字准确无误。 The outer limits of integer precision in javascript(你实际上会得到你输入的相同值)是 9007199254740992。根据我的转换测试,这在 285428751-11-12T07:36:32+00:00 之前都很好:)

    简单的答案是 Javascript 在内部使用比用于 C 风格 epoc 的 longint(4 字节,32 位)更大的数据类型...

    【讨论】:

    • 有趣的事实,Number.MAX_SAFE_INTEGER 报告 9007199254740991 现在在 chrome 中。所以这个问题似乎已经解决了。
    【解决方案3】:

    可以。试试new Date(8640000000000000)

    9 月 13 日星期六 275760 03:00:00 GMT+0300(东欧夏令时间)

    275760 年比 2038 年略远 :)

    阅读规范部分 15.9.1.1

    http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1

    一个 Date 对象包含一个数字,表示一个特定的瞬间 时间在一毫秒内。这样的数字称为时间值。一种 time 值也可能是 NaN,表示 Date 对象没有 代表一个特定的时刻。

    自 1970 年 1 月 1 日以来,时间在 ECMAScript 中以毫秒为单位测量 世界标准时间。在时间值中,闰秒被忽略。假设有 正好是每天 86,400,000 毫秒。 ECMAScript 数值 可以表示从 –9,007,199,254,740,992 到的所有整数 9,007,199,254,740,992;这个范围足以测量时间 任何瞬间的毫秒精度,大约在 从 1970 年 1 月 1 日 UTC 起,向前或向后 285,616 年。

    ECMAScript Date 对象支持的实际时间范围是 稍微小一点:正好 –100,000,000 天到 100,000,000 天 相对于 1970 年 1 月 1 日开始时的午夜测量 世界标准时间。这给出了 8,640,000,000,000,000 毫秒的范围 UTC 时间 1970 年 1 月 1 日的任一侧。

    UTC 时间 1970 年 1 月 1 日开始的午夜的确切时刻 由值 +0 表示。

    【讨论】:

    • 值得注意的是,new Date(Number.MAX_SAFE_INTEGER) 产生“无效日期”。但是你绝对可以使用Number.MAX_SAFE_INTEGER / 2,它可以让你度过公元 144,683 年。希望这对于大多数用例来说已经足够好了,尽管我想你永远不知道。如果有任何语言会在公元 144k 年出现,那就是 JavaScript! ☢️?️?‍?
    • @mikermcneil 是的,但你的回答也不准确,更新了我的以表示真正的限制:) 谢谢你让我这样做:D
    【解决方案4】:

    2038 年问题仅适用于 PHP 和其他一些系统使用的签名 32 位时间戳。带符号的 32 位时间戳的范围用完 2038 年的秒数。

    来自Wikipedia article(强调我的):

    2038 年问题可能会导致某些计算机软件在 2038 年附近的某个时间点出现故障。该问题会影响所有将系统时间存储为有符号 32 位整数的软件和系统,以及将此数字解释为自 1970 年 1 月 1 日星期四 00:00:00 UTC 以来的秒数。1 可以这种方式表示的最远时间是 2038 年 1 月 19 日星期二 03:14:07 UTC。[2 ] ... 这是由整数溢出引起的。 计数器“用尽”可用数字,而是“增加”符号位,并报告最大负数(继续向上计数,趋向于零) .由于计算错误,这可能会给这些系统的用户带来问题。

    将时间戳存储在具有更大范围的变量中可以解决问题。

    【讨论】:

      【解决方案5】:

      这意味着 JS 使用 UNIX 时间戳。

      旁注:Unix 时间戳是自 1970 年以来的秒数。JS 时间是自 1970 年以来的毫秒数。所以 JS 时间戳不适合更早的 32 位 int(但 JS 不为此使用 32 位 int)

      【讨论】:

        猜你喜欢
        • 2011-08-18
        • 2017-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-17
        相关资源
        最近更新 更多