【问题标题】:javascript regex iso datetimejavascript 正则表达式 iso 日期时间
【发布时间】:2011-03-09 18:07:45
【问题描述】:

有没有人有一个好的正则表达式模式来匹配 iso 日期时间?

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

【问题讨论】:

  • 我使用/^(\d{4})-0?(\d+)-0?(\d+)[T ]0?(\d+):0?(\d+):0?(\d+)$/,(但这不是最严格的).. 转换为 Date 是另一回事 :)

标签: javascript regex datetime iso


【解决方案1】:

Brocks 的答案很好,但应该以 ^ 开头并以 $ 结尾,以便在您尝试匹配的只是日期字符串时不允许使用前缀/后缀字符。

【讨论】:

    【解决方案2】:

    yyyy-MM-dd

    这里对大多数答案的解释太多了,这是@Sergey answer 的简短变体,解决了一些奇怪的情况(例如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 对象。

    【讨论】:

      【解决方案3】:

      从 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
      

      【讨论】:

      • 此正则表达式允许无效日期为:19-02-29T20:59:39.217Z 其中年份不遵守 ISO 格式 yyyy 您可以在 Chrome 控制台中尝试检查它:/((( 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/.test("19-02-29T20:59:39.217Z");
      【解决方案4】:

      我已经制作了这个正则表达式,并解决了 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):

      【讨论】:

      • 如果不验证闰年,为什么要使用如此复杂的正则表达式?既不是leap second
      • @Toto 因为是之前发布的最好的。它尊重我在“考虑”部分中指出的每个项目。试试这个答案中的正则表达式和之前使用this site 发布的另一个,你会看到我在说什么。 (我还评论了发布的其他每个正则表达式中的问题,说明了它们为什么存在缺陷)
      • 抱歉,这并没有更好,因为它不处理闰年。
      • 这样会更好,因为其他人不会兑现他们的承诺。请使用我在上一条评论中建议的页面尝试来自这个不同答案的其他正则表达式,您将看到我要解释的内容。
      【解决方案5】:

      要匹配 ISO 日期,例如 2017-09-22,您可以使用此正则表达式:

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

      它将匹配任何数字年份、00-12 范围内两位数指定的任何月份以及 00-31 范围内两位数指定的任何日期

      【讨论】:

      • 00 对月或日如何有效?
      【解决方案6】:

      我将最佳答案改写为更简洁的内容。不是写出三个可选模式中的每一个,而是将元素嵌套为可选语句。

      /[+-]?\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

      【讨论】:

      • 这不适用于:2016-09-05T15:22:26.286Z 使[+-][0-2]\d:[0-5]\d 可选使其工作:[+-]?\d{4}(-[01]\d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?([+-][0-2]\d:[0-5]\d)?Z?)?)?)?
      • 这允许奇怪的事情有效为:28T09:5220.5690463826472487295963210360122513980205942+01:53 在 Chrome 控制台中尝试此操作以检查它:/[+-]?\d{4}(-[01]\ d(-[0-3]\d(T[0-2]\d:[0-5]\d:?([0-5]\d(\.\d+)?)?[+-] [0-2]\d:[0-5]\dZ?)?)?)?/.test("28T09:5220.5690463826472487295963210360122513980205942+01:53");
      • 这导致我的身份验证令牌被捕获,因为它具有与\d{4} 部分匹配的匹配部分。
      【解决方案7】:

      这是一个检查 ISO 8601 日期格式的正则表达式,包括闰年和短长月。要运行它,您需要“忽略空白”。没有空格的压缩版本在 regexlib 上:http://regexlib.com/REDetails.aspx?regexp_id=3344

      ISO 8601 还有更多内容 - 此正则表达式只关心日期,但您可以轻松扩展它以支持时间验证,这并不难。

      更新:现在可以使用 javascript(没有后视)

        ^(?:
            (?=
                  [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)?)?)?
      

      【讨论】:

        【解决方案8】:

        对于严格的完整日期时间,包括毫秒,每个 the W3C's take on the spec。:

        //-- 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) doc 允许的其他变化:

        /********************************************
        **    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-8601 表示如果省略时区,则假定为 UTC,这包括“Z”。
        • 我完全同意维基百科不是一个确定的来源。但对于某些主题,它提供了合理的参考,关于 ISO-8601 的文章有可口的示例和易于理解的解释。 :-D
        • 哇。角度源代码中引用了这个答案! @BrockAdams
        • 感谢您的正则表达式。稍微调整一下,我们可以使用(?: ) 而不是( ) 来避免捕获一个组。例如\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+(?:[+-][0-2]\d:[0-5]\d|Z) 第一个正则表达式。
        • 这将在闰秒内失败,即偶尔出现的第 61 秒。
        【解决方案9】:

        ISO 8601 规范允许多种日期格式。关于如何做到这一点here 有一个平庸的解释。 Javascript 的日期输入格式与未指定时区的简单日期的 ISO 格式之间存在相当小的差异,可以使用string substitution 轻松缓解。完全支持 ISO-8601 规范并非易事。

        这是一个参考示例,我不保证它是完整的,尽管它从上述 Wikipedia 页面解析了非持续时间。

        下面是一个例子,你也可以看到它是output on 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"))
        

        【讨论】:

          【解决方案10】:

          不确定它是否与您要解决的潜在问题相关,但您可以将 ISO 日期字符串作为构造函数 arg 传递给 Date() 并从中获取对象。构造函数在将字符串强制转换为日期方面实际上非常灵活。

          【讨论】:

          • 确认,这种方法行不通。问题在于 IE。 2014-06-44 变为 2014-08-13,因为 IE 将溢出日期 (>30) 视为下个月的日期。我已经在 IE8 和 IE11 中尝试过。虽然在 Chrome 中工作。很烦人。
          猜你喜欢
          • 2019-02-26
          • 2011-02-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多