2015-06-21 57 views
17

V8日期解析器被打破:是否有任何解決方法破碎的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(Firefox)中的Date

更新:這肯定打破解析器https://code.google.com/p/v8/issues/detail?id=2602
nope, Status: WorkingAsIntended

+0

你想檢測哪些日期? – Bergi

+3

爲什麼這會被投票? – Rishav

+0

@Bergi添加預計日期 –

回答

25

Date對象基於即毫秒的自1970年1月1日UTC的數量和時間值有以下構造

new Date(); 
new Date(value); 
new Date(dateString); 
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]); 

docs

dateStringnew Date(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()沒有爲返回NaN的像'asd qw 101'一個字符串,因此錯誤。您可以與Date.parse('asd qw 101')Chrome(v8) [返回-58979943000000]和Gecko(Firefox) [返回NaN]進行交叉檢查。Sat Jan 01 101 00:00:00來的時候,你的種子new Date()與-58979943000000時間戳(兩個瀏覽器)

是有破V8日期解析器什麼解決辦法?

我不會說V8日期解析器壞了。它只是試圖以最好的方式滿足字符串RFC 2822 standard,但壁虎和 中斷 在某些情況下給出了不同的結果

嘗試在這兩個瀏覽器(V8)和Firefox(壁虎)new Date('Sun Ma 10 2015')不爲其他異常。 這裏鉻不能決定天氣'馬'代表'三月'或'五月',並給出一個無效日期而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})$ 

Image-regex 圖片來自debuggex

因此產生的,好像V8 AINT壞了,它只是工作方式不同。

希望它有幫助!

+2

它有很大的幫助。順便說一句,今天我發現從2013年3月的問題,V8解析器應該返回'NaN'順便說一句,我仍然認爲它的破解https://code.google.com/p/v8/issues/detail?id=2602,所以可能是正式打破 –

+2

或可能不是「狀態:WorkingAsIntended」 –

+0

正是!恕我直言,這取決於解析器如何支持標準(RFC/ISO)。他們大多覆蓋他們應該按預期工作的場景,但在某些使用情況下會丟棄垃圾。舉個例子,V8確實在'new Date('asd qw 21')'上拋出了一個TypeError(與預期的一樣),但是將一個類似結構化的字符串'new Date('asd qw 121')'作爲一個日期(它不應該) T)。人們總是可以提供更好的正則表達式/解析技術以獲得更廣泛的支持,但仍不能保證它適用於每種有效格式和垃圾字符串。在這種情況下進行徹底測試既不現實也不可能:) – nalinc

10

ES5 15.9.4.2 Date.parse: /.../如果String不符合 該格式的功能可能回落到任何實現特定的 啓發式或實現特定的日期格式。無法識別 字符串或日期包含格式爲 的非法元素值字符串應使Date.parse返回NaN。

所以這是所有權利,並根據上文V8日期解析器的結果引文:

  1. new Date('asd qw 101'):星期六1月1 101 00:00:00 GMT + 0100 (CET)
  2. new Date('asd qw') :無效的日期
+0

抱歉,我沒有明白爲什麼它是'Sat Jan 01 101'而不是'NaN NaN 101' –

+0

@VladimirStarkov,因爲'NaN'不是日期的有效部分。 – royhowie

+1

@VladimirStarkov:因爲日期不包含部分,他們只是時間戳。並且'asd qw 101'被解析爲表示第101年第二個零的那個。 – Bergi

11

您似乎在要求一種方法來解析可能以任何特定格式的字符串並確定表示哪些數據。總的來說,這是一個糟糕的主意,原因有很多。

你說moment.js是「擺脫日期檢測」,但實際上它從來沒有這個功能擺在首位。人們只是假設它可以做到這一點,而且在某些情況下它可以工作,而且在很多情況下它沒有。

下面是一個說明問題的例子。

var s = "01.02.03"; 

這是約會嗎?也許。也許不會。它可能是文檔中的標題。即使我們說這是一個約會,約會是幾號?它可以被解釋爲以下任何一項:

  • 2003年1月2日
  • 1月2日,0003
  • 2003年2月1日
  • 2月1日,0003
  • 2001年2月3日
  • 二月3rd,0001

消除歧義的唯一方法是知道th當前培養日期設置。 Javascript的Date對象就是這麼做的 - 這意味着您將獲得不同的值,具體取決於代碼正在運行的機器的設置。然而,moment.js關乎所有環境的穩定性。通過時刻自己的語言環境功能,文化設置是明確的。依靠瀏覽器的文化設置會導致解釋錯誤。

要做的最好的事情是明確你正在使用的格式。不要允許隨機垃圾輸入。預計你的輸入格式爲特定格式,並使用正則表達式提前驗證該格式,而不是僅僅試圖構建一個Date並在事實之後查看它是否有效。

如果你不能這樣做,你將不得不尋找額外的上下文來幫助決定。例如,如果您從後端進程中抓取網絡的一些隨機位,並且想要從文本中提取日期,則必須具有關於每個特定網頁的語言和語言環境的一些知識。你可以猜到,但你可能會錯過相當長的時間。

參見:Garbage in, garbage out

+0

感謝您的迴應,基本上我根本不需要依賴momentjs。我可以使用日期,並會很高興。關鍵在於Firefox的實施工作正在進行,Chrome的一個已經破產。 –

+0

@VladimirStarkov我不會說鉻是壞的,它只是試圖解析輸入字符串 – maioman

+0

@maioman可能它沒有壞,但它的工作不夠好 –

相關問題