【问题标题】:Node.js new Date does not reflect timezone TZ var from .envNode.js 新日期不反映来自 .env 的时区 TZ var
【发布时间】:2019-02-04 11:29:51
【问题描述】:

刚刚在 Node.js 和 MacOs 中偶然发现了一个有趣的问题 - 基本上,如果您在 .env 文件中运行具有设置时区变量的节点实例,变量 TZ,并且您的本地计算机位于不同的时区,则创建日期为 f* *d 尽可能以麦汁的方式,这样:

时区设置正确

但是当你创建一个新的日期时,时区并没有反映出来


看这个例子,(我的机器在 CET,时区欧洲/布拉格):

~/
11:13 (CET) $ node
new Date()
2019-02-04T10:30:23.053Z # Europe/Prague
new Date().getTimezoneOffset()
-60 # Europe/Prague
.exit

对比在 TZ 环境中设置时区

✔ ~/
11:30 (CET) $ TZ=America/New_York node
new Date()
2019-02-04T10:31:40.968Z # 10:31! :D
new Date().getTimezoneOffset()
300 # America/New_York!

因此不可能创建正确的日期,因为所有 JS 库(如 moment)都在 end Date 对象中使用。 我的看法是,你永远不应该在运行 Node.js 服务器时设置 TZ var,我错过了什么吗?

【问题讨论】:

    标签: node.js macos timezone-offset


    【解决方案1】:

    你的例子在我看来是正确的。我怀疑你对计算机跟踪和显示时间的方式的概念是颠倒的。您的 cmets 暗示您认为 TZ 用于从计算机的内部时钟导出 UTC。这不是它的工作原理。

    在内部,您的 Mac 使用的是 UTC 时间。您的 Mac 不是“在 CET 中”。它是“在 UTC 中,默认 TZ 设置为 CET”。 TZ 控制在需要本地时间戳或时区偏移时如何从基础 UTC 派生本地时间。如果您更改TZ,则本地时间戳将显示在新时区中,但计算机内部的UTC 计时不受影响。

    特别是对于您的示例,new Date() 为您获取一个代表当前时间的 Date 对象。 Date 对象的默认字符串表示是 UTC 时间。在您的示例中,您可以看到这一次,显示为new Date() 调用的结果:

        2019-02-04T10:30:23.053Z # Europe/Prague
    

    是 UTC 时间,因为它的时区显示为 Z,表示 UTC。 (记住这个含义的一种方法是“Z”代表“与 UTC 的零偏移”。这种格式有时被称为“Zulu”时间,因为“Zulu”是 ICAO 语音字母表中“Z”的代码字。)如果您的评论声称这是当地的欧洲/布拉格时间戳,则评论不正确。

    第二个new Date()的结果:

        2019-02-04T10:31:40.968Z # 10:31! :D
    

    也以 UTC 显示,比第一个结果晚大约一分钟。这个过程的TZ 不同没关系,因为TZ 不影响UTC 时间戳。

    要查看通过将TZ 设置应用于从计算机时钟获得的UTC 时间计算的本地时间,请对Date 对象使用toLocaleString 方法。如果您使用该方法重复测试,您将看到如下内容:

        $ env TZ=Europe/Prague node 
        > now = new Date()
        2019-02-04T20:26:40.408Z
        > now.toLocaleString()
        'Mon Feb 04 2019 21:26:40 GMT+0100 (CET)'
    
        $ env TZ=America/New_York node 
        > now = new Date()
        2019-02-04T20:27:12.438Z
        > now.toLocaleString()
        'Mon Feb 04 2019 15:27:12 GMT-0500 (EST)'
    

    这看起来完全合理。

    顺便说一句,Node 或 JavaScript 在这里并没有做任何不寻常的事情。这是它适用于一切的方式。例如date 命令:

        $ env TZ=Europe/Prague date
        Mon Feb  4 21:54:49 CET 2019
    
        $ env TZ=America/New_York date
        Mon Feb  4 15:54:51 EST 2019
    

    【讨论】:

      【解决方案2】:

      您可以使用moment-timezone 节点包解决您的问题。下面的代码可以帮助您解决问题。

      const moment = require('moment-timezone')
      
      function convertDate(dateInUTCFormat) { 
          return new Promise((resolve, reject) => { 
              var dec = moment(dateInUTCFormat);
              var normalDate = dec.tz('Asia/Kolkata').format('YYYY-MM-DD');  // GMT +5:30 (India)
              resolve(normalDate);
          }) 
      }
      

      您还需要将您以UTC格式获得的日期格式(例如2019-02-04T10:30:23.053Z)传递给convertDate函数,并在我通过我的时区Asia/Kolkata时传递您的时区。希望这将帮助您找到解决方案。

      【讨论】:

      • 嗨,谢谢 - 当我需要 string 值时,这肯定会有所帮助,但是当我执行 moment().toDate() 时它将失败,这将再次使用 Date 对象我也破解了这个不同的方式: const getDepartureIgnoringTimezone = (departureAtInMS: number, timezone: string): Date => { const m = moment(departureAtInMS).tz(timezone); // 正确的时区 const msOfDate = new Date(m.format()).getTime(); // 正确的 UTC 时间戳 const offset = ( m.utcOffset() * 60 * 1000 ); // 正确的偏移量 return new Date(msOfDate + offset); }
      • 你可以像这样创建“正确的”日期对象 ^ 但要明白这在团队环境中是不可能的,新开发人员会来做 new Date 并期待正确的日期:)跨度>
      猜你喜欢
      • 1970-01-01
      • 2014-12-02
      • 1970-01-01
      • 2020-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-04
      相关资源
      最近更新 更多