Javascript日期解析在Chrome中返回奇怪的结果 [英] Javascript Date parsing returning strange results in Chrome
问题描述
我在Chrome浏览器中发现了一些奇怪的Date行为(版本74.0.3729.131(官方内部版本)(64位)). 在Chrome开发者控制台中执行了以下javascript:
I observed some strange Date behaviour in Chrome (Version 74.0.3729.131 (Official Build) (64-bit)). Following javascript was executed in the Chrome Dev Console:
new Date('1894-01-01T00:00:00+01:00')
// result: Mon Jan 01 1894 00:00:00 GMT+0100 (Central European Standard Time)
new Date('1893-01-01T00:00:00+01:00')
// result: Sat Dec 31 1892 23:53:28 GMT+0053 (Central European Standard Time)
尽管提供了有效的ISO8601值,但我已经在不同的浏览器中通过Date ctor了解了有关非标准日期解析的信息. 但这不仅仅是奇怪的o_o
I have already read about non standard date parsing via the Date ctor in different browsers, although providing valid ISO8601 values. But this is more than strange o_o
在Firefox(Quantum 66.0.3(64位))中,相同的调用会导致预期的Date对象:
In Firefox (Quantum 66.0.3 (64-Bit)) the same calls result in expected Date objects:
new Date('1894-01-01T00:00:00+01:00')
// result: > Date 1892-12-31T23:00:00.000Z
new Date('1893-01-01T00:00:00+01:00')
// result: > Date 1893-12-31T23:00:00.000Z
- 这是Chrome中的错误吗?
- 我输入的内容是有效的ISO8601吗?
- 最重要的问题是,我该如何解决? (希望自己不解析输入字符串)
推荐答案
好的,似乎无法避免这种现象,因此您应该手动解析日期.但是解析它的方法非常简单.
Okay, seems like this behaviour cannot be avoided, so you should parse dates manually. But the way to parse it is pretty simple.
如果我们以ISO 8601格式解析日期,则日期字符串的掩码如下所示:
If we are parsing date in ISO 8601 format, the mask of date string looks like this:
<yyyy>-<mm>-<dd>T<hh>:<mm>:<ss>(.<ms>)?(Z|(+|-)<hh>:<mm>)?
1.分别获取日期和时间
字符串中的T
将日期与时间分开.因此,我们可以将ISO字符串除以T
1. Getting date and time separately
The T
in string separates date from time. So, we can just split ISO string by T
var isoString = `2019-05-09T13:26:10.979Z`
var [dateString, timeString] = isoString.split("T")
2.从日期字符串中提取日期参数
因此,我们有dateString == "2019-05-09"
.现在,分别获取此参数非常简单
2. Extracting date parameters from date string
So, we have dateString == "2019-05-09"
. This is pretty simple now to get this parameters separately
var [year, month, date] = dateString.split("-").map(Number)
3.处理时间字符串
对于时间字符串,由于其可变性,我们应该执行更复杂的操作.
我们有timeString == "13:26:10Z"
还有可能timeString == "13:26:10"
和timeString == "13:26:10+01:00
3. Handling time string
With time string we should make more complex actions due to its variability.
We have timeString == "13:26:10Z"
Also it's possible timeString == "13:26:10"
and timeString == "13:26:10+01:00
var clearTimeString = timeString.split(/[Z+-]/)[0]
var [hours, minutes, seconds] = clearTimeString.split(":").map(Number)
var offset = 0 // we will store offset in minutes, but in negation of native JS Date getTimezoneOffset
if (timeString.includes("Z")) {
// then clearTimeString references the UTC time
offset = new Date().getTimezoneOffset() * -1
} else {
var clearOffset = timeString.split(/[+-]/)[1]
if (clearOffset) {
// then we have offset tail
var negation = timeString.includes("+") ? 1 : -1 // detecting is offset positive or negative
var [offsetHours, offsetMinutes] = clearOffset.split(":").map(Number)
offset = (offsetMinutes + offsetHours * 60) * negation
} // otherwise we do nothing because there is no offset marker
}
这时,我们的数据以数字格式表示:
year
,month
,date
,hours
,minutes
,seconds
和offset
的分钟数.
At this point we have our data representation in numeric format:
year
, month
, date
, hours
, minutes
, seconds
and offset
in minutes.
是的,我们无法避免,因为它太酷了. JS Date
自动为所有负值和太大的值匹配日期.这样我们就可以以原始格式传递所有参数,并且JS Date
构造函数将自动为我们创建正确的日期!
Yes, we cannot avoid it, because it is too cool. JS Date
automatically match date for all negative and too big values. So we can just pass all parameters in raw format, and the JS Date
constructor will create the right date for us automatically!
new Date(year, month - 1, date, hours, minutes + offset, seconds)
Voila!这是一个完整的示例.
Voila! Here is fully working example.
function convertHistoricalDate(isoString) {
var [dateString, timeString] = isoString.split("T")
var [year, month, date] = dateString.split("-").map(Number)
var clearTimeString = timeString.split(/[Z+-]/)[0]
var [hours, minutes, seconds] = clearTimeString.split(":").map(Number)
var offset = 0 // we will store offset in minutes, but in negation of native JS Date getTimezoneOffset
if (timeString.includes("Z")) {
// then clearTimeString references the UTC time
offset = new Date().getTimezoneOffset() * -1
} else {
var clearOffset = timeString.split(/[+-]/)[1]
if (clearOffset) {
// then we have offset tail
var negation = timeString.includes("+") ? 1 : -1 // detecting is offset positive or negative
var [offsetHours, offsetMinutes] = clearOffset.split(":").map(Number)
offset = (offsetMinutes + offsetHours * 60) * negation
} // otherwise we do nothing because there is no offset marker
}
return new Date(year, month - 1, date, hours, minutes + offset, seconds)
}
var testDate1 = convertHistoricalDate("1894-01-01T00:00:00+01:00")
var testDate2 = convertHistoricalDate("1893-01-01T00:00:00+01:00")
var testDate3 = convertHistoricalDate("1894-01-01T00:00:00-01:00")
var testDate4 = convertHistoricalDate("1893-01-01T00:00:00-01:00")
console.log(testDate1.toLocaleDateString(), testDate1.toLocaleTimeString())
console.log(testDate2.toLocaleDateString(), testDate2.toLocaleTimeString())
console.log(testDate3.toLocaleDateString(), testDate3.toLocaleTimeString())
console.log(testDate4.toLocaleDateString(), testDate4.toLocaleTimeString())
在这种情况下,我们得到的Date
实例具有归一化的所有自身值(如.getHours()
),包括时区偏移量. testDate1.toISOString
仍将返回奇怪的结果.但是,如果您正在使用这个日期,它可能会100%满足您的需求.
In this case we are getting Date
instance with all its own values (like .getHours()
) being normalized, including timezone offset. The testDate1.toISOString
will still return weird result. But if you are working with this date, it will probably 100% fit your needings.
希望有所帮助:)
这篇关于Javascript日期解析在Chrome中返回奇怪的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!