我有两个字符串2017-03-15
(date
)和12:26
(time
)。我想从中创建一个本地化的日期对象,而不使用库。
现在请记住:Tue Mar 14 2017 12:26:33 GMT+0800 (AWST)
,如果我这样做:
new Date( date + 'T' + time )
我得到了错误的结果,因为日期被认为是UTC:
Wed Mar 15 2017 20:26:00 GMT+0800 (AWST)
如果我使用空格:
new Date( date + ' ' + time )
结果是正确的:
Wed Mar 15 2017 12:26:00 GMT+0800 (AWST)
然而,这不适用于Safari(不是没有T)。 Safari实际上会抛出一个错误(!)。
我意识到将字符串解析为日期取决于实现。因此,“正确”的唯一方法是:
var timeSplit = time.split(':');
var dateSplit = date.split('-');
new Date( dateSplit[0], dateSplit[1] - 1, dateSplit[2], timeSplit[ 0 ], timeSplit[ 1 ] )
但它只是。所以。丑陋。 有没有更好的解决方案适用于各种浏览器?
答案 0 :(得分:3)
我得到了错误的结果,因为日期被认为是UTC:
这实际上是ES5规范中的一个错误(它表示没有时区指示符表示UTC,它与ISO-8601 standard不一致,它本身就是其子集。 ES2015更正了它,说没有时区指示符意味着本地时间(与ISO-8601保持一致),但是当在仅限日期的字符串(如"2018-01-17"
)上使用时,这会导致现有代码的兼容性问题。因此,ES2016必须再次更新它,并且从那时起它一直保持稳定。如果没有时区指标,那么:
"2019-05-20"
)以UTC格式解析"2019-05-20T10:00"
)在当地时间解析由于这种规范混淆,我们有一段时间混合使用旧的ES5行为,ES2015行为或ES2016行为的JavaScript引擎。一个重要的平台仍有不正确的行为:iOS。
截至2019年5月20日的最新答案:
您可以在此处查看当前的浏览器:
var may20 = new Date("2019-05-20");
// UTC hours should be 0 if that was parsed as UTC
console.log(may20.getUTCHours() === 0 ? "OK:" : "Error:", may20.toLocaleString());
var may20At10 = new Date("2019-05-20T10:00");
// Local hours should be 10 if that was parsed in local time
console.log(may20At10.getHours() === 10 ? "OK:" : "Error:", may20At10.toLocaleString());

(除非你是全年使用GMT的几个西非国家之一,否则该检查有效。它依赖于UTC和当地时间在2019年5月20日彼此不同。所以它适用于英国,因为虽然英国大部分时间都使用GMT,但是在支票使用日期它是英国夏令时[GMT + 0100];它在纽约有效,因为纽约从未使用GMT;但是它因为Timbuktu uses GMT year-round而没有在廷巴克图工作。)
但是,这不适用于Safari(不是没有T)。
右。 JavaScript引擎需要支持的唯一日期/时间格式是ISO-8601子集defined here(以及它从toString
返回的任何内容,但不是&#39 ; t在规范中定义;它只需要是双向的)。如上所述,至少在2019年5月20日撰写本文时,Safari并未正确实施该规范。
但它只是。所以。丑陋。有没有更好的解决方案适用于各种浏览器?
它根本不丑陋。毕竟,Date
构造函数必须做些什么才能搞清楚。把它放在标准库中,你就可以了。
答案 1 :(得分:2)
我得到了错误的结果,因为日期被认为是UTC:
假设:
new Date('2017-03-15T12:26')
IE版本8将其视为无效字符串,IE 9+将其视为UTC。 Firefox 38将其视为本地。
如果我使用空格......结果是正确的
直到您尝试Safari并获得无效日期。
然而,这不适用于Safari(不是没有T)。 Safari实际上会抛出一个错误(!)。
是的,两个结果都与ECMAScript的所有版本一致。 Safari说“这不是有效的ISO 8601字符串”,因此返回无效日期。其他人也这么说,但后来又回到了实现特定的启发式方法(他们被允许这样做)。
底线是不使用Date构造函数解析字符串(或Date.parse,它们等同于解析)。
所以,“正确”的唯一方法就是......
是的,手动解析这些位。为方便起见,您可以使用库,但它们可以完全相同。
是否有更好的解决方案适用于各种浏览器?
没有。获取ECMA TC39 committee并将其击败,直到他们决定定义具有合适解析器和格式化程序的Date对象。有很多非常好的现有实现可供选择,包括现有的javascript库和其他语言。
不幸的是,解析几乎被忽略了,并且格式化的责任已经传递给ECMA-402,这对于日期格式化非常普遍,并且实际上不适合。