【问题标题】:JavaScript Date time different once deployed to Heroku部署到 Heroku 后,JavaScript 日期时间不同
【发布时间】:2021-10-12 19:16:22
【问题描述】:

在本地,一切都是精确的。一旦部署到 Heroku,时间差大约 6 小时。我不希望转换 Heroku 时区(希望它保持 UTC)。我已经尝试了从 getTimezoneOffset() 转换到不同日期格式的所有方法,但我仍然得到相同的结果。我怎样才能让这两个日期时间相互匹配,而不是在部署时被小时数抵消?当格式完全相同时,为什么它们会有所不同?

// Used to calculate current date time

const currentDate = new Date();
// ^ Production - (2021-10-12T19:12:41.081Z)
const time = `${currentDate.getHours()}:${currentDate.getMinutes()}`;
const fullDate = `${currentDate.getMonth()}/${currentDate.getDate()}/${currentDate.getFullYear()}`;
const currentDateFormatted = new Date(`${fullDate} ${time}`);
// ^ Production - (2021-10-12T19:12:00.000Z)

const currentParsedDateToUTC = Date.parse(currentDateFormatted.toUTCString());

// Used to calculate an event date time

const eventDate = new Date(`${event.date} ${event.endTime}`); // same exact format as above
// ^ Production - (2021-10-12T13:12:00.000Z)
const eventParsedDateToUTC = Date.parse(eventDate.toUTCString());

const isExpired = (currentParsedDateToUTC > eventParsedDateToUTC); // works locally, but not in production

在此示例中,事件日期和开始时间与当前日期时间相同。我怎样才能防止它们大不相同?

【问题讨论】:

  • 这段代码是否在客户端运行(在浏览器中)?还是服务器端(在node.js进程中)?
  • 所有运行的服务器端,Node.js @DeclanMcKelvey-Hembree
  • event.date和event.endTime的来源是什么?事件对象来自哪里?
  • 它直接来自数据库。 event.date = 10/12/2021 和 event.endTime = 13:12。这就像它将当前的新日期对象转换为 UTC,而不是使用事件创建的日期对象。 @DeclanMcKelvey-Hembree
  • 我已经更新了我的帖子,以展示最初的新日期在生产中的样子。会不会和结束时区有关? (081Z) @DeclanMcKelvey-Hembree

标签: javascript date heroku time


【解决方案1】:

这是因为 Heroku 服务器与您的时区不同,您可以通过从前端转换时间格式来处理它,我建议您使用 moment.js 例如在您的前端您可以这样转换:

npm install moment --save

然后你可以创建一个函数来改变显示的格式:

const formatDatetime = (
  datetime = "N/A",
  format = 'LLL' // here is your format
) => {
  return moment(datetime).isValid()
    ? moment(datetime).format(format)
    : datetime;
};

【讨论】:

  • datetime = "N/A" 没有意义。如果没有传递任何值,它将是未定义的,moment(datetime).isValid() 将失败。返回无效的 datetime 值也没有意义,调用者如何检测错误?强烈建议不要在不提供格式的情况下解析字符串。两次解析同一个字符串也是低效的,考虑let d = moment(datetime, 'M/D/Y H:m'); return d.isValid()? d.format(...) : undefined
  • “N/A”只是一个标签,如果值为 null,则函数将返回“N/A”,您决定是否要删除或添加任何其他默认值。
【解决方案2】:

所以——Heroku 正在返回正确的 UTC 当地时间,在撰写本文时它是 2021-10-12T19:36:00.000Z

您要求 Heroku 将 2012-10-12 13:12 解释为日期,但您没有指定它应该使用哪个时区,因此它默认为自己的本地 UTC 时间。

这里的一切都按预期工作。

我认为您隐含的要求是您希望它将 13:12 解释为您的当地时间。但是,Heroku 无法知道您的当地时间,因此您需要跟踪数据库中事件的时区。

这在本地工作的唯一原因是因为您的本地服务器恰好与您在同一个时区 - 如果我要从我的时区连接到您的本地服务器,我会遇到同样的问题。

【讨论】:

    【解决方案3】:

    前四行代码似乎是试图创建一个 Date 并将秒和毫秒设置为零。可以这样做:

    let d = new Date();
    d.setSeconds(0,0);
    

    这会将秒和毫秒设置为零。

    我不知道您认为以下内容有什么作用:

    const currentParsedDateToUTC = Date.parse(currentDateFormatted.toUTCString());
    

    但相同的结果由下式给出:

    d.getTime();
    

    这实际上是上一次调用 setSeconds 时返回的值。所以前 5 行代码简化为:

    let currentParsedDateToUTC = new Date().setSeconds(0,0);
    

    然后在:

    const eventDate = new Date(`${event.date} ${event.endTime}`);
    

    使用内置解析器解析格式为 d/m/y H:m 的时间戳,这是一个坏主意,请参阅Why does Date.parse give incorrect results?。您可以使用库来代替,或者只编写一个 2 行函数来完成这项工作。

    然后又是:

    const eventParsedDateToUTC = Date.parse(eventDate.toUTCString());
    

    这很简单:

    const eventParsedDateToUTC = eventDate.getTime();
    

    终于有:

    const isExpired = (currentParsedDateToUTC > eventParsedDateToUTC);
    

    比较运算符将强制日期为您编号,因此您可以将值保留为日期。

    完成这项工作的功能是:

    // eventDate is UTC timestamp in m/d/y H:m format
    function isExpired(eventDate) {
      // Parse eventDate as UTC
      let [M,D,Y,H,m] = eventDate.split(/\W/);
      let eventD = new Date(Date.UTC(Y, M-1, D, H, m));
      // return true if has passed (minute precision)
      return eventD < new Date().setSeconds(0,0);
    }
    
    // Event dates (UTC)
    ['10/12/2021 12:00', // 12 Oct 2021 12:00
     '10/13/2021 12:00', // 13 Oct 2021 12:00
     '10/13/2022 12:00', // 13 Oct 2022 12:00
     ].forEach(d => 
       console.log(d + ' has' + (isExpired(d)? '':' not') + ' Expired')   
    );

    您可以使用Date.UTC(Y, M-1, D, H, m) 返回的值而不转换为日期,因此最后两行可能是:

      return Date.UTC(Y, M-1, D, H, m) < new Date().setSeconds(0,0);
    

    但使用日期会更符合语义(如果不需要的话)。 :-)

    【讨论】:

      猜你喜欢
      • 2013-12-31
      • 1970-01-01
      • 2018-12-20
      • 2022-07-11
      • 2011-07-30
      • 2012-01-01
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      相关资源
      最近更新 更多