【问题标题】:Alternative to casting UTC Date in Javascript?在 Javascript 中转换 UTC 日期的替代方法?
【发布时间】:2019-03-11 18:40:05
【问题描述】:

我希望在 JS 中创建一个新的日期,但将其转换为 UTC 时间。例如,假设castAsUTC() 产生以下预期效果:

var x = new Date('2019-01-01T00:00:00') // In local time (PST)
castAsUTC(x).toISOString(); // => '2019-01-01T00:00:00Z'
// x.toISOString() gives us '2019-01-01T08:00:00Z', which is undesired

目前,我的函数如下所示:

function castAsUTC(date) {
  return new Date(x.toLocaleString() + '+00:00');
}

是否有更清洁/更好的方式来产生相同的效果?提前致谢!

编辑:更具体地说,我有兴趣转换日期的时区,而不用尽可能少的算术更改其实际值。所以调用.toISOString() 将产生与当地时间相同的日期。

我目前正在使用moment-timezone 库,但我似乎也无法使用它获得预期的效果。我肯定会接受使用 Moment.js 的答案

【问题讨论】:

  • .toGMTString() 怎么样? edit 哎呀,现在显然是.toUTCString(),男孩我老了
  • 问题是所有 Date 实例都已经基于内部基于 UTC 的时间戳值。
  • 如果您在创建日期时未指定时间,则它已经是 UTC:new Date('2019-01-01').toISOString() === '2019-01-01T00:00:00.000Z'。如果您确实指定了时间,只需指定时区当您创建日期时
  • 您现在所做的与此相反:“我有兴趣转换日期的时区,而不更改其实际值”。您正在创建日期 2018-12-31T16:00:00Z,然后将其值更改 8 小时以补偿最初创建不正确的情况。

标签: javascript date


【解决方案1】:

您可以使用 utc function 将 Moment 实例切换为 UTC。然后只需使用format 即可从中获取您想要的任何特定输出。

【讨论】:

    【解决方案2】:

    如果您拥有的字符串确实与显示的字符串一样,那么最简单的做法是附加一个Z 以指示UTC。

    var input = '2019-01-01T00:00:00';
    var date = new Date(input + 'Z');
    var output = date.toISOString();
    

    或者,如果您想使用 Moment.js,请执行以下操作:

    var input = '2019-01-01T00:00:00';
    var m = moment.utc(input);
    var output = m.format();
    

    为此,您不需要时刻时区。

    【讨论】:

      【解决方案3】:

      tl;博士;

      您的日期格式错误。将字母“Z”添加到日期字符串的末尾,它将被视为 UTC。

      var x = new Date('2019-01-01T00:00:00Z')    // Jan 1, 2019 12 AM UTC
      

      如其他答案中所述,使用诸如 momentjs(utcformat 函数)之类的库更容易管理这些格式问题。如果您想使用原版 javascript,则需要在调用 toISOString 之前减去时区偏移量(请参阅下面较长答案中的警告)。

      详情

      Date 在 javascript 中处理时区的方式有点反直觉。在内部,日期存储为自 Unix 纪元(1970 年 1 月 1 日)以来的毫秒数。这是您拨打getTime() 时得到的号码,它是用于数学和比较的号码。

      但是 - 当您使用标准字符串格式化函数(toStringtoTimeStringtoDateString 等)时,javascript 会在格式化之前自动应用本地计算机时区的时区偏移量。在浏览器中,这意味着它将为最终用户计算机应用偏移量,而不是服务器。 toISOStringtoUTCString 函数不会应用偏移量 - 它们打印存储在 Date 中的实际 UTC 值。这对您来说可能仍然看起来“错误”,因为它与您在控制台或调用 toString 时看到的值不匹配。

      这才是真正有趣的地方。您可以通过使用new Date(milliseconds) 或使用带有new Date(dateString) 的解析器指定自Unix 纪元以来的毫秒数,在javascript 中创建Date。使用毫秒方法,无需担心时区 - 它被定义为 UTC。问题是,使用 parse 方法,javascript 如何确定您想要的时区?在 ES5(2009 年发布)之前,答案是不同的取决于浏览器!发布 ES5,答案取决于你如何格式化字符串!如果您使用 ISO 8601 的简化版本(只有日期,没有时间),javascript 会将日期视为 UTC。否则,如果您以 ISO 8601 格式指定时间,或者使用“人类可读”格式,它会将日期视为本地时区。 Check out MDN 了解更多。

      一些例子。如果 javascript 将其视为 UTC 或本地日期,我已经指出了每个。在 UTC 中,该值将是 1970 年 1 月 1 日午夜。在本地,它取决于时区。对于太平洋时间 (UTC-8) 中的 OP,UTC 值为 1970 年 1 月 1 日上午 8 点。

      new Date(0)                    // UTC (milliseconds is always UTC)
      new Date("1/1/1970");          // Local - (human readable string)
      new Date("1970-1-1");          // Local (invalid ISO 8601 - missing leading zeros on the month and day)
      new Date("1970-01-01");        // UTC (valid simplified ISO 8601)
      new Date("1970-01-01T00:00");  // Local (valid ISO 8601 with time and no timezone)
      new Date("1970-01-01T00:00Z"); // UTC (valid ISO 8601 with UTC specified)
      

      不能更改此行为 - 但您可能对用于解析日期的格式持迂腐态度。在您的情况下,问题是您提供了一个带有时间组件但没有时区的 ISO-8601 字符串。将字母“Z”添加到字符串的末尾,或者删除时间都对你有用。

      或者,总是使用像 momentjs 这样的库来避免这些复杂性。

      Vanilla JS 解决方法

      如前所述,这里的真正问题是知道日期是被视为本地日期还是 UTC。您不能从本地“转换”为 UTC,因为所有 Date 已经是 UTC - 它只是格式化。但是,如果您确定日期被解析为本地日期并且它确实应该是 UTC,您可以通过手动调整时区偏移量来解决它。这被称为“时代转移”(感谢@MattJohnson 的这个词!)而且很危险。您实际上创建了一个指向不同时间点的全新日期!如果你在代码的其他部分使用它,你可能会得到不正确的值!

      这是一个时代偏移方法示例(为清楚起见,从castAsUtc 重命名)。首先从对象获取时区偏移量,然后减去它并使用新值创建一个新日期。如果您将其与toISOString 结合使用,您将获得所需格式的日期。

      function epochShiftToUtc(date) {
          var timezoneOffsetMinutes = date.getTimezoneOffset();
          var timezoneOffsetMill = timezoneOffsetMinutes * 1000 * 60;
          var buffer = new Date(date.getTime() - timezoneOffsetMill);
      
          return buffer;
      }
      
      epochShiftToUtc(date).toUTCString();
      

      【讨论】:

      • @MattJohnson 我试图让 OP 避免 js 日期的技术细节。更新为 tl;dr;为了清楚起见。
      猜你喜欢
      • 1970-01-01
      • 2019-12-05
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-30
      • 1970-01-01
      相关资源
      最近更新 更多