从字符串

时间:2017-03-14 04:53:08

标签: javascript date

我有两个字符串2017-03-15date)和12:26time)。我想从中创建一个本地化的日期对象,而不使用库。

现在请记住: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 ] )

但它只是。所以。丑陋。 有没有更好的解决方案适用于各种浏览器?

2 个答案:

答案 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日的最新答案:

  • 桌面版本的Chrome,Firefox,Edge甚至IE11都正确实现了ES2016 +规范。
  • Safari(桌面或iOS)错误地分析日期/时间字符串,而不使用UTC中的时区指示符。
  • 所有当前 iOS 浏览器(当然还有Safari,但Chrome,Firefox,Brave,Dolphin ......)也会错误地解析日期/时间字符串,而不使用UTC中的时区指示符。这是因为iOS JavaScript引擎JavaScriptCore(JSC)错误地实现了这一点,并且非Apple iOS应用程序无法分配可执行内存,因此浏览器无法使用他们通常使用的引擎(Chrome' s V8,Firefox的SpiderMonkey等)因为那些是优化需要在运行时创建可执行代码的引擎。所以他们使用JSC代替。 (Chrome的V8最近添加了一个" JIT-less"纯解释器版本,因此Chrome可能会也可能不会开始使用它而不是JSC。)

您可以在此处查看当前的浏览器:



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,这对于日期格式化非常普遍,并且实际上不适合。