JavaScript Date.prototype.toISOString() 丢失偏移量

JavaScript Date.prototype.toISOString() loses offset

为什么此方法使用 UTC 时区 (Z) 而不是包括本地时间偏移量 (+/-HH:SS)?方法名中的"ISO" refers to ISO 8601—which allows for "time zone designations" 表示为其格式的一部分。

换句话说,new Date() 告诉我日期和时间,以及时区偏移量(通过 getTimezoneOffset())。但是 toISOString() 只告诉我 一个 时区的日期和时间——它丢弃了 new Date() 起源的语言环境中的时间信息。

toISOString() 也包括起始时区与 UTC 的偏移量是否有意义? toISOString() 省略 +/-HH:SS 会丢失有关 来源 Date 的信息,如果它用于序列化的话。

我的所有 AJAX 调用(Angular、jQuery)都通过 toISOString() 序列化,因此在与服务器通信时会丢失序列化日期的本地时间。获取 JavaScript Date 以输出 ISO 格式的字符串 的任何方法,该字符串还包括 偏移量(除了使用像 Moment.js 这样的库),或者我需要自己写方法吗?

这是 "because that's what the language specification says" 答案之一(参见 ECMA-262 §20.3.4.36)。 ISO 8601 是一种格式,虽然它允许使用时区数据,但 ECMAScript 仅使用 UTC。如果您愿意,可以使用自己的 toLocalISOString 方法扩展 Date.prototype。顺便说一句,写这样的方法并不难。

// Format date as ISO 8601 long format with local timezone offset
if (!Date.prototype.toLocalISOString) {
  Date.prototype.toLocalISOString = function() {
  
  // Helper for padding
  function pad(n, len) {
    return ('000' + n).slice(-len);
  }

  // If not called on a Date instance, or timevalue is NaN, return undefined
  if (isNaN(this) || Object.prototype.toString.call(this) != '[object Date]') return;

  // Otherwise, return an ISO format string with the current system timezone offset
  var d = this;
  var os = d.getTimezoneOffset();
  var sign = (os > 0? '-' : '+');
  os = Math.abs(os);

  return pad(d.getFullYear(), 4) + '-' +
         pad(d.getMonth() + 1, 2) + '-' +
         pad(d.getDate(), 2) +
         'T' + 
         pad(d.getHours(), 2) + ':' +
         pad(d.getMinutes(), 2) + ':' +
         pad(d.getSeconds(), 2) + '.' +
         pad(d.getMilliseconds(), 3) + 
       
         // Note sign of ECMASCript offsets are opposite to ISO 8601
         sign +
         pad(os/60 | 0, 2) + ':' +
         pad(os%60, 2);
  }
}
document.write(new Date().toLocalISOString())

编辑

基于 post by DanDascalescu,这里有一个可能更有效的替代方案,因为它调用的函数更少,但它会创建两个额外的 Date 对象:

// Return a string in ISO 8601 extended format with the host timezone offset
Date.prototype.toLocalISOString = function() {

    // If not called on a Date instance, or timevalue is NaN, return undefined
    if (isNaN(this) || Object.prototype.toString.call(this) != '[object Date]') return;

    // Copy date so don't modify original
    var d = new Date(+this);
    var offset = d.getTimezoneOffset();
    var offSign = offset > 0? '-' : '+';
    offset = Math.abs(offset);
    var tz = offSign + ('0' + (offset/60|0)).slice(-2) + ':' + ('0' + offset%60).slice(-2)
    return new Date(d.setMinutes(d.getMinutes() - d.getTimezoneOffset())).toISOString().slice(0,-1) + tz; 
}

console.log(new Date().toLocalISOString())