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())
为什么此方法使用 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())