V8日期解析器已损坏:
> new Date('asd qw 101')
Sat Jan 01 101 00:00:00 GMT+0100 (CET)
我可以像这样使用脆弱的正则表达式:
\d{1,2} (jan|feb|mar|may|jun|jul|aug|sep|oct|nov|dec) \d{1,4}
但它太脆弱了。我不能依赖new Date
(issue in V8)而且也无法帮助我,因为时刻是getting rid off date detection (github issue-thread)。
是否存在破解v8日期解析器的任何解决方法?
要清楚。我们有Gecko和V8,都有Date
。 V8破坏了日期,Gecko已经工作了。我需要Gecko(Firefox)中的Date
。
更新:它肯定是破解了解析器https://code.google.com/p/v8/issues/detail?id=2602
nope, Status: WorkingAsIntended
答案 0 :(得分:27)
Date
个对象基于时间值,即自UTC时间1970年1月1日以来的毫秒数,并具有以下构造函数
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
来自docs,
new Date(dateString)
中的dateString 是表示日期的字符串值。字符串应该在一个 格式通过 Date.parse()方法识别( 符合IETF的RFC 2822 时间戳 以及 ISO8601 的版本。)
现在查看date.js中的v8 sourcecode:
function DateConstructor(year, month, date, hours, minutes, seconds, ms) {
if (!%_IsConstructCall()) {
// ECMA 262 - 15.9.2
return (new $Date()).toString();
}
// ECMA 262 - 15.9.3
var argc = %_ArgumentsLength();
var value;
if (argc == 0) {
value = %DateCurrentTime();
SET_UTC_DATE_VALUE(this, value);
} else if (argc == 1) {
if (IS_NUMBER(year)) {
value = year;
} else if (IS_STRING(year)) {
// Probe the Date cache. If we already have a time value for the
// given time, we re-use that instead of parsing the string again.
var cache = Date_cache;
if (cache.string === year) {
value = cache.time;
} else {
value = DateParse(year); <- DOES NOT RETURN NaN
if (!NUMBER_IS_NAN(value)) {
cache.time = value;
cache.string = year;
}
}
}
...
看起来DateParse()
没有为'asd qw 101'
之类的字符串返回NaN,因此错误。您可以在 Chrome(v8) [返回Date.parse('asd qw 101')
]和 Gecko(Firefox) [返回]中与-58979943000000
进行交叉核对一个NaN]。 Sat Jan 01 101 00:00:00
种子new Date()
的时间戳为-58979943000000(在两种浏览器中)
是否存在破解v8日期解析器的任何解决方法?
我不会说V8日期解析器坏了。它只是试图以最好的方式满足RFC 2822 standard的字符串,但gecko也是如此,并且 break 在某些情况下会给出不同的结果。
在Chrome(V8)和Firefox(Gecko)中尝试 new Date('Sun Ma 10 2015')
以解决另一个此类异常情况。
在这里,铬无法决定天气和马克。代表三月&#39;或者&#39;五月&#39;并且在Firefox不执行时提供无效日期。
解决方法:强>
您可以围绕Date()
创建自己的包装器,以过滤V8自己的解析器无法使用的字符串。但是,在ECMA-5中对内置函数进行子类化是不可行的。在ECMA-6中,可以子类化内置构造函数(数组,日期和错误) - reference
但是,您可以使用更强大的正则表达式来验证 RFC 2822 / ISO 8601
的字符串^(?:(?:31(\/|-|\. |\s)(?:0?[13578]|1[02]|(?:Jan|Mar|May|Jul|Aug|Oct|Dec)))\1|(?:(?:29|30)(\/|-|\.|\s)(?:0?[1,3-9]|1[0-2]|(?:Jan|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.|\s)(?:0?2|(?:Feb))\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.|\s)(?:(?:0?[1-9]|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep))|(?:1[0-2]|(?:Oct|Nov|Dec)))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$
生成的图片
所以,似乎v8打破了,它的工作方式不同。
希望它有所帮助!
答案 1 :(得分:11)
您似乎要求一种方法来解析可能采用任何特定格式的字符串并确定表示哪些数据。一般来说,这是一个坏主意的原因有很多。
你说moment.js是“摆脱日期检测”,但实际上它从来没有这个功能。人们只是假设它可以做到这一点,并且在某些情况下它起作用,并且在许多情况下它没有。
这是一个说明问题的例子。
var s = "01.02.03";
那是约会吗?也许。也许不吧。它可以是文档中的部分标题。即使我们说这是一个约会,它的日期是什么时候?它可以解释为以下任何一种:
消除歧义的唯一方法是了解当前的文化日期设置。 Javascript的Date
对象就是这样 - 这意味着您将获得不同的值,具体取决于运行代码的计算机的设置。但是,moment.js是关于所有环境的稳定性。文化设置是明确的,通过时刻自己的区域设置功能。依赖浏览器的文化设置会导致解释错误。
最好的办法是明确你正在使用的格式。不允许随机垃圾输入。期望您以特定格式输入,并使用正则表达式提前验证该格式,而不是仅仅尝试构造Date
并查看它是否在事后有效。
如果您无法这样做,您必须找到其他背景来帮助您做出决定。例如,如果您从后端进程中抓取Web的一些随机位,并且您想从文本中提取日期,则必须了解每个特定网页的语言和区域设置。你可以猜到,但是你可能错了很多时间。
答案 2 :(得分:10)
ES5 15.9.4.2 Date.parse: /.../如果String不符合 该函数的格式可能会回退到任何特定于实现的 启发式或特定于实现的日期格式。无法识别 包含格式中非法元素值的字符串或日期 String应使Date.parse返回NaN。
所以没关系,根据上面引用的v8日期解析器的结果:
new Date('asd qw 101')
:1月01日101 00:00:00 GMT + 0100
(CET)new Date('asd qw')
:无效日期