簡體   English   中英

用於匹配 ISO 8601 日期時間字符串的正則表達式

[英]Regex to match an ISO 8601 datetime string

有沒有人有一個很好的正則表達式模式來匹配 iso 日期時間?

即:2010-06-15T00:00:00

對於嚴格的、完整的日期時間,包括毫秒,根據W3C 對規范的看法。:

//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/

//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/

//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)/

//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/

.
實際ISO 8601:2004(E) 文檔允許的其他變化:

/********************************************
**    No time-zone varients:
*/
//-- Complete precision:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+/

//-- No milliseconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d/

//-- No Seconds:
/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d/

//-- Putting it all together:
/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d)/

警告:這一切很快就會變得混亂,它仍然允許某些廢話,例如第 14 個月。 此外,ISO 8601:2004(E) 允許多種其他變體。

.
"2010-06-15T00:00:00" 不合法,因為它沒有時區指定。

為了匹配 ISO 日期,比如 2017-09-22,你可以使用這個正則表達式:

^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])$

它將匹配任何數字年份、由 00-12 范圍內的兩位數字指定的任何月份以及由 00-31 范圍內的兩位數字指定的任何日期

我將最佳答案改寫為更簡潔的內容。 不是寫出三個可選模式中的每一個,而是將元素嵌套為可選語句。

/[+-]?\\d{4}(-[01]\\d(-[0-3]\\d(T[0-2]\\d:[0-5]\\d:?([0-5]\\d(\\.\\d+)?)?[+-][0-2]\\d:[0-5]\\dZ?)?)?)?/

我很好奇這種方法是否有缺點?

你可以在這里找到我建議的答案的測試: http : //regexr.com/3e0lh

這是檢查 ISO 8601日期格式的正則表達式,包括閏年和短長月。 要運行它,您需要“忽略空白”。 regexlib 上有一個沒有空格的壓縮版本: http: //regexlib.com/REDetails.aspx?regexp_id=3344

ISO 8601 還有更多內容 - 這個正則表達式只關心日期,但您可以輕松擴展它以支持時間驗證,這並不那么棘手。

更新:這現在適用於 javascript(沒有lookbehinds)

  ^(?:
      (?=
            [02468][048]00
            |[13579][26]00
            |[0-9][0-9]0[48]
            |[0-9][0-9][2468][048]
            |[0-9][0-9][13579][26]              
      )

      \d{4}

      (?:

        (-|)

        (?:

            (?:
                00[1-9]
                |0[1-9][0-9]
                |[1-2][0-9][0-9]
                |3[0-5][0-9]
                |36[0-6]
            )
            |
                (?:01|03|05|07|08|10|12)
                (?:
                  \1
                  (?:0[1-9]|[12][0-9]|3[01])
                )?            
            |
                (?:04|06|09|11)
                (?:
                  \1
                  (?:0[1-9]|[12][0-9]|30)
                )?            
            |
                02
                (?:
                  \1
                  (?:0[1-9]|[12][0-9])
                )?

            |
                W(?:0[1-9]|[1-4][0-9]|5[0-3])
                (?:
                  \1
                  [1-7]
                )?

        )            
      )?
  )$
  |
  ^(?:
      (?!
            [02468][048]00
            |[13579][26]00
            |[0-9][0-9]0[48]
            |[0-9][0-9][2468][048]
            |[0-9][0-9][13579][26]              
      )

      \d{4}

      (?:

        (-|)

        (?:

            (?:
                00[1-9]
                |0[1-9][0-9]
                |[1-2][0-9][0-9]
                |3[0-5][0-9]
                |36[0-5]
            )
            |
                (?:01|03|05|07|08|10|12)
                (?:
                  \2
                  (?:0[1-9]|[12][0-9]|3[01])
                )?

            |
                (?:04|06|09|11)
                (?:
                  \2
                  (?:0[1-9]|[12][0-9]|30)
                )?
            |
                (?:02)
                (?:
                  \2
                  (?:0[1-9]|1[0-9]|2[0-8])
                )?
            |
                W(?:0[1-9]|[1-4][0-9]|5[0-3])
                (?:
                  \2
                  [1-7]
                )?
       ) 
    )?
)$

為了滿足時間,在混合物中添加類似的東西(來自: http : //underground.infovark.com/2008/07/22/iso-date-validation-regex/ ):

([T\s](([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)?(\15([0-5]\d))?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?

ISO 8601規范允許使用多種日期格式。 這里有一個關於如何做到這一點的平庸解釋。 Javascript 的日期輸入格式與不指定時區的簡單日期的 ISO 格式之間存在相當小的差異,並且可以使用字符串替換輕松緩解。 完全支持 ISO-8601 規范並非易事。

這是一個參考示例,我不保證它是完整的,盡管它解析了上述 Wikipedia 頁面中的非持續時間。

下面是一個示例,您還可以在 ideone 上看到它的輸出 不幸的是,它不符合規范,因為它沒有正確實施幾周。 ISO-8601 中周數 01 的定義非常重要,需要瀏覽日歷來確定第一周從哪里開始,以及它在指定年份的天數方面的確切含義。 這可能很容易糾正(我只是厭倦了玩它)。

function parseISODate (input) {
    var iso = /^(\d{4})(?:-?W(\d+)(?:-?(\d+)D?)?|(?:-(\d+))?-(\d+))(?:[T ](\d+):(\d+)(?::(\d+)(?:\.(\d+))?)?)?(?:Z(-?\d*))?$/;

    var parts = input.match(iso);

    if (parts == null) {
        throw new Error("Invalid Date");
    }

    var year = Number(parts[1]);

    if (typeof parts[2] != "undefined") {
        /* Convert weeks to days, months 0 */
        var weeks = Number(parts[2]) - 1;
        var days  = Number(parts[3]);

        if (typeof days == "undefined") {
            days = 0;
        }

        days += weeks * 7;

        var months = 0;
    }
    else {
        if (typeof parts[4] != "undefined") {
            var months = Number(parts[4]) - 1;
        }
        else {
            /* it's an ordinal date... */
            var months = 0;
        }

        var days   = Number(parts[5]);
    }

    if (typeof parts[6] != "undefined" &&
        typeof parts[7] != "undefined")
    {
        var hours        = Number(parts[6]);
        var minutes      = Number(parts[7]);

        if (typeof parts[8] != "undefined") {
            var seconds      = Number(parts[8]);

            if (typeof parts[9] != "undefined") {
                var fractional   = Number(parts[9]);
                var milliseconds = fractional / 100;
            }
            else {
                var milliseconds = 0
            }
        }
        else {
            var seconds      = 0;
            var milliseconds = 0;
        }
    }
    else {
        var hours        = 0;
        var minutes      = 0;
        var seconds      = 0;
        var fractional   = 0;
        var milliseconds = 0;
    }

    if (typeof parts[10] != "undefined") {
        /* Timezone adjustment, offset the minutes appropriately */
        var localzone = -(new Date().getTimezoneOffset());
        var timezone  = parts[10] * 60;

        minutes = Number(minutes) + (timezone - localzone);
    }

    return new Date(year, months, days, hours, minutes, seconds, milliseconds);
}

print(parseISODate("2010-06-29T15:33:00Z-7"))
print(parseISODate("2010-06-29 06:14Z"))
print(parseISODate("2010-06-29T06:14Z"))
print(parseISODate("2010-06-29T06:14:30.2034Z"))
print(parseISODate("2010-W26-2"))
print(parseISODate("2010-180"))

我已經制作了這個正則表達式並解決了日期驗證,因為它們來自 Javascript 的.toISOString()方法。

^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|(02)-(0[1-9]|[12][0-9]))T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9])\\.[0-9]{3}Z$

考慮:

  • 在適當的位置使用適當的符號('-'、'T'、':'、'.'、'Z')。
  • 與 29、30 或 31 天的月份保持一致。
  • 小時從 00 到 23。
  • 從 00 到 59 的分和秒。
  • 從 000 到 999 的毫秒數。

未考慮:

  • 閏年。

示例日期: 2019-11-15T13:34:22.178Z

直接在 Chrome 控制台中運行的示例: /^[0-9]{4}-((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01])|(0[469]|11)-(0[1-9]|[12][0-9]|30)|(02)-(0[1-9]|[12][0-9]))T(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9]):(0[0-9]|[1-5][0-9])\\.[0-9]{3}Z$/.test("2019-11-15T13:34:22.178Z");

正則表達式流程圖( Regexper ): 正則表達式流程圖

yyyy-MM-dd

對這里的大多數答案的解釋太多,這是@Sergey答案的簡短變體,用於解決一些奇怪的情況(如2020-00-00 ),這個RegExp只關心yyyy-MM-dd日期:

// yyyy-MM-dd
^\d{4}-([0][1-9]|1[0-2])-([0-2][1-9]|[1-3]0|3[01])$

此外,這個也不關心每月的天數,例如2020-11-31 (因為 11 月只有 30 天)。

我的用例是將String轉換為Date (來自API參數),我只需要知道輸入字符串不包含奇怪的東西,我對實際的Date對象進行下一次驗證。

從 1900 年到 2999 年的 02/29 驗證

 (((2000|2400|2800|((19|2[0-9])(0[48]|[2468][048]|[13579][26])))-02-29)|(((19|2[0-9])[0-9]{2})-02-(0[1-9]|1[0-9]|2[0-8]))|(((19|2[0-9])[0-9]{2})-(0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01]))|(((19|2[0-9])[0-9]{2})-(0[469]|11)-(0[1-9]|[12][0-9]|30)))T([01][0-9]|[2][0-3]):[0-5][0-9]:[0-5][0-9]\.[0-9]{3}Z

Brocks 的答案很好,但應該以 ^ 開頭並以 $ 結尾,以便在您嘗試匹配的只是日期字符串時不允許使用前綴/后綴字符。

在將 QRegExp 與 IsoDateWithMs 一起使用時,這里的毫秒數不起作用。 相反,以下挽救了這一天。

\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d{1,3}

(我知道這是一個 JS 條目,但它首先彈出,對 c++ 開發人員有幫助)

這是我對此的看法:

^\d{4}-(?:0[1-9]|1[0-2])-(?:[0-2][1-9]|[1-3]0|3[01])T(?:[0-1][0-9]|2[0-3])(?::[0-6]\d)(?::[0-6]\d)?(?:\.\d{3})?(?:[+-][0-2]\d:[0-5]\d|Z)?$

匹配示例:

2016-12-31T23:59:60+12:30
2021-05-10T09:05:12.000Z
3015-01-01T23:00+02:00
1001-01-31T23:59:59Z
2023-12-20T20:20

分鍾和秒部分可以更細化,但這對我來說已經足夠了。

正則表達式

在此處輸入圖像描述

不確定它是否與您嘗試解決的潛在問題相關,但是您可以將 ISO 日期字符串作為構造函數 arg 傳遞給 Date() 並從中獲取一個對象。 構造函數實際上在將字符串強制轉換為日期方面非常靈活。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM