我需要用正则表达式验证格式为dd/mm/yyyy的日期字符串。

这个正则表达式验证dd/mm/yyyy,但不验证像31/02/4500这样的无效日期:

^(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}$

什么是有效的正则表达式来验证支持闰年的dd/mm/yyyy格式?


当前回答

我怀疑,在不知道用户的地区何时从儒略历切换到格里高利历的情况下,以下内容是尽可能准确的。

它接受'-','/',或者什么都不作为年,月和日之间的分隔符,不管顺序如何。

MMddyyyy:

^(((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))[-/]?[0-9]{4}|02[-/]?29[-/]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00))$

ddMMyyyy:

^(((0[1-9]|[12][0-9]|30)[-/]?(0[13-9]|1[012])|31[-/]?(0[13578]|1[02])|(0[1-9]|1[0-9]|2[0-8])[-/]?02)[-/]?[0-9]{4}|29[-/]?02[-/]?([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00))$

yyyyMMdd:

^([0-9]{4}[-/]?((0[13-9]|1[012])[-/]?(0[1-9]|[12][0-9]|30)|(0[13578]|1[02])[-/]?31|02[-/]?(0[1-9]|1[0-9]|2[0-8]))|([0-9]{2}(([2468][048]|[02468][48])|[13579][26])|([13579][26]|[02468][048]|0[0-9]|1[0-6])00)[-/]?02[-/]?29)$

除了顺序,这些都精确到儒略历(每四年闰年),直到1700年,当公历与儒略历背离。它有两个问题:

It accepts the year 0000, which doesn't exist in many, but not all, standards. Note that ISO 8601 does accept year 0000 (equivalent to 1 BCE). It doesn't skip the 10-13 days which were lost when the Gregorian Calendar came into use. This varies by locality though. For example, the Roman Catholic Church skipped 10 days, October 5th through October 14th, 1582, but Greece (the last to switch) skipped February 16th through the 28th of 1923, 13 days, having to take into account the leap years of 1700, 1800, and 1900.

从0001年到9999年的Java日历实现已经测试了这一点,唯一的差异是上面提到的1582年的10天。

其他回答

((((0[13578]|1[02])\/(0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)\/(0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)(\/(0[1-9]|1[0-9]|2[0-8]))))\/(19([6-9][0-9])|20([0-9][0-9])))|((02)\/(29)\/(19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

从1960年到2028年是否会验证MM/DD/YYYY格式

如果您需要扩展闰年支持,请添加

19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048]|3[26]|4[048])))

这也是功

^((((0[13578]|1[02])[/](0[1-9]|1[0-9]|2[0-9]|3[01]))|((0[469]|11)[/](0[1-9]|1[0-9]|2[0-9]|3[0]))|((02)([/](0[1-9]|1[0-9]|2[0-8]))))[/](19([6-9][0-9])|20([0-9][0-9])))|((02)[/](29)[/](19(6[048]|7[26]|8[048]|9[26])|20(0[048]|1[26]|2[048])))

如果可以更改格式mm-dd-yyyy,则将[/]替换为[-] 也可以在线查询http://regexr.com/

对于那些看到这些并感到完全困惑的人,这里是我剧本的一段摘录。不幸的是,它所做的只是匹配日期时间输入中的有效数字,31 Feb将被标记为有效,但正如许多人所说,regex真的不是做这个测试的最佳工具。

以'yyyy-MM-dd hh:mm'格式匹配日期(实际上可以按您喜欢的任何顺序匹配)

var dateerrors = false;
var yearReg = '(201[4-9]|202[0-9])';            ///< Allows a number between 2014 and 2029
var monthReg = '(0[1-9]|1[0-2])';               ///< Allows a number between 00 and 12
var dayReg = '(0[1-9]|1[0-9]|2[0-9]|3[0-1])';   ///< Allows a number between 00 and 31
var hourReg = '([0-1][0-9]|2[0-3])';            ///< Allows a number between 00 and 24
var minReg = '([0-5][0-9])';                    ///< Allows a number between 00 and 59
var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');
$('input').filter(function () {return this.id.match(/myhtml_element_with_id_\d+_datetime/);}).each(function (e) {
    if (e > 0) {
        // Don't test the first input. This will use the default
        var val = $(this).val();
        if (val && !val.trim().match(reg)) {
            dateerrors = true;
            return false;
        }
    }
});
if (dateerrors) {
    alert('You must enter a validate date in the format "yyyy-mm-dd HH:MM", e.g. 2019-12-31 19:30');
    return false;
}

上面的脚本首先构建一个正则表达式对象。然后它会找到id与某个模式匹配的所有输入,然后循环遍历这些输入。我没有测试我找到的第一个输入(if (e > 0))。

稍微解释一下:

var reg = new RegExp('^' + yearReg + '-' + monthReg + '-' + dayReg + ' ' + hourReg + ':' + minReg + '$', 'g');

^表示匹配的开始,而$表示匹配的结束。

return this.id.match(/myhtml_element_with_id_\d+_datetime/);

\d+表示匹配单个或连续的整数序列,因此myhtml_element_with_id_56_datetime和myhtml_element_with_id_2_datetime将匹配,但myhtml_element_with_id_5a_datetime将不匹配

import re
expression = "Nov 05 20:10:09 2020"
reg_ex = r'((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-2][0-9]|(3)[0-1]) (([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])) (\d{4}))'
assert re.fullmatch(reg_ex, expression), True

对给定例子的解释

11月=一组可能的月份,即(Jan|Feb|Mar|Apr|五月|六月|七月|八月|九月|十月|十一月|十二月) 05年=天即一组有效。([0 - 9][0]| (3)(0 - 1)) 20:10:09 =获得有效时间:一组([0 - 9][0 - 1]| 2(0 - 3)),分钟:([0 - 9][0 - 5])和秒:([0 - 9][0 - 5]) 2020 =获取年份的一组,即(\d{4}))

仅限当天使用:

<input placeholder="day" maxlength="2" minlength="1" formControlName="birthDay" 
   name="birthDay"pattern="(0[1-9]|1[0-9]|2[0-9]|3[0-1])" >/

仅供当月使用:

 <input placeholder="month" maxlength="2" minlength="1" 
  formControlName="month" name="month" formControlName="month" name="month" pattern="(0[1- 
  9]|1[0-2])">/

我认为最好的方法是使用Moment.js的isValid()方法,指定格式并使用严格的解析。

正如moment.js文档所说

从2.3.0版本开始,您可以为最后一个参数指定一个布尔值 使Moment使用严格解析。严格解析要求 格式和输入完全匹配,包括分隔符。

value = '2020-05-25';
format = 'YYYY-MM-DD';
moment(value, format, true).isValid() // true