用于检查日期的 PHP 正则表达式采用 YYYY-MM-DD 格式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13194322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP Regex to check date is in YYYY-MM-DD format
提问by cosmicsafari
I'm trying to check that dates entered by end users are in the YYYY-MM-DD. Regex has never been my strong point, I keep getting a false return value for the preg_match() I have setup.
我正在尝试检查最终用户输入的日期是否在 YYYY-MM-DD 中。正则表达式从来都不是我的强项,我一直在为我设置的 preg_match() 得到一个错误的返回值。
So I'm assuming I have made a mess of the regex, detailed below.
所以我假设我把正则表达式弄得一团糟,下面详述。
$date="2012-09-12";
if (preg_match("^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$",$date))
{
return true;
}else{
return false;
}
Any thoughts?
有什么想法吗?
回答by Avin Varghese
Try this.
尝试这个。
$date="2012-09-12";
if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date)) {
return true;
} else {
return false;
}
回答by Jon
It's probably better to use another mechanism for this.
为此使用另一种机制可能会更好。
The modern solution, with DateTime:
现代解决方案,具有DateTime:
$dt = DateTime::createFromFormat("Y-m-d", $date);
return $dt !== false && !array_sum($dt::getLastErrors());
This validates the input too: $dt !== falseensures that the date can be parsed with the specified format and the array_sumtrick is a terse way of ensuring that PHP did not do "month shifting" (e.g. consider that January 32 is February 1). See DateTime::getLastErrors()for more information.
这也验证了输入:$dt !== false确保可以使用指定的格式解析日期,并且array_sum技巧是确保 PHP 没有进行“月份转换”的简洁方法(例如,考虑 1 月 32 日是 2 月 1 日)。有关DateTime::getLastErrors()更多信息,请参阅。
Old-school solution with explodeand checkdate:
list($y, $m, $d) = array_pad(explode('-', $date, 3), 3, 0);
return ctype_digit("$y$m$d") && checkdate($m, $d, $y);
This validates that the input is a valid date as well. You can do that with a regex of course, but it's going to be more fuss -- and February 29 cannot be validated with a regex at all.
这将验证输入也是有效日期。当然,您可以使用正则表达式来做到这一点,但这会更加麻烦——而且 2 月 29 日根本无法使用正则表达式进行验证。
The drawback of this approach is that you have to be very careful to reject all possible "bad" inputs while not emitting a notice under any circumstances. Here's how:
这种方法的缺点是您必须非常小心地拒绝所有可能的“坏”输入,同时在任何情况下都不发出通知。就是这样:
explodeis limited to return 3 tokens (so that if the input is "1-2-3-4",$dwill become "3-4")ctype_digitis used to make sure that the input does not contain any non-numeric characters (apart from the dashes)array_padis used (with a default value that will causecheckdateto fail) to make sure that enough elements are returned so that if the input is "1-2"list()will not emit a notice
explode仅限于返回 3 个标记(这样如果输入是“1-2-3-4”,$d就会变成“3-4”)ctype_digit用于确保输入不包含任何非数字字符(破折号除外)array_pad使用(使用会导致checkdate失败的默认值)来确保返回足够的元素,以便在输入为“1-2”list()时不会发出通知
回答by Shyju KP
yyyy-mm-dd :/^((((19|[2-9]\d)\d{2})\-(0[13578]|1[02])\-(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\-(0[13456789]|1[012])\-(0[1-9]|[12]\d|30))|(((19|[2-9]\d)\d{2})\-02\-(0[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\-02\-29))$/g
yyyy-mm-dd :/^((((19|[2-9]\d)\d{2})\-(0[13578]|1[02])\-(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\-(0[13456789]|1[012])\-(0[1-9]|[12]\d|30))|(((19|[2-9]\d)\d{2})\-02\-(0[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\-02\-29))$/g
yyyy/mm/dd :/^((((19|[2-9]\d)\d{2})\/(0[13578]|1[02])\/(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\/(0[13456789]|1[012])\/(0[1-9]|[12]\d|30))|(((19|[2-9]\d)\d{2})\/02\/(0[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\/02\/29))$/g
年/月/日:/^((((19|[2-9]\d)\d{2})\/(0[13578]|1[02])\/(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\/(0[13456789]|1[012])\/(0[1-9]|[12]\d|30))|(((19|[2-9]\d)\d{2})\/02\/(0[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\/02\/29))$/g
mm-dd-yyyy :/^(((0[13578]|1[02])\-(0[1-9]|[12]\d|3[01])\-((19|[2-9]\d)\d{2}))|((0[13456789]|1[012])\-(0[1-9]|[12]\d|30)\-((19|[2-9]\d)\d{2}))|(02\-(0[1-9]|1\d|2[0-8])\-((19|[2-9]\d)\d{2}))|(02\-29\-((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
mm-dd-yyyy :/^(((0[13578]|1[02])\-(0[1-9]|[12]\d|3[01])\-((19|[2-9]\d)\d{2}))|((0[13456789]|1[012])\-(0[1-9]|[12]\d|30)\-((19|[2-9]\d)\d{2}))|(02\-(0[1-9]|1\d|2[0-8])\-((19|[2-9]\d)\d{2}))|(02\-29\-((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
mm/dd/yyyy :/^(((0[13578]|1[02])\/(0[1-9]|[12]\d|3[01])\/((19|[2-9]\d)\d{2}))|((0[13456789]|1[012])\/(0[1-9]|[12]\d|30)\/((19|[2-9]\d)\d{2}))|(02\/(0[1-9]|1\d|2[0-8])\/((19|[2-9]\d)\d{2}))|(02\/29\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
毫米/日/年:/^(((0[13578]|1[02])\/(0[1-9]|[12]\d|3[01])\/((19|[2-9]\d)\d{2}))|((0[13456789]|1[012])\/(0[1-9]|[12]\d|30)\/((19|[2-9]\d)\d{2}))|(02\/(0[1-9]|1\d|2[0-8])\/((19|[2-9]\d)\d{2}))|(02\/29\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
dd/mm/yyyy :/^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
日/月/年:/^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
dd-mm-yyyy :/^(((0[1-9]|[12]\d|3[01])\-(0[13578]|1[02])\-((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\-(0[13456789]|1[012])\-((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\-02\-((19|[2-9]\d)\d{2}))|(29\-02\-((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
dd-mm-yyyy :/^(((0[1-9]|[12]\d|3[01])\-(0[13578]|1[02])\-((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\-(0[13456789]|1[012])\-((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\-02\-((19|[2-9]\d)\d{2}))|(29\-02\-((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g
回答by Graham
Criteria:
标准:
Every year divisible by 4 is a leap year, except when it is divisible by 100 unless it is divisible by 400. So:
能被 4 整除的每一年都是闰年,除非能被 100 整除,除非能被 400 整除。所以:
2004 - leap year - divisible by 4
1900 - not a leap year - divisible by 4, but also divisible by 100
2000 - leap year - divisible by 4, also divisible by 100, but divisible by 400
February has 29 days in a leap year and 28 when not a leap year
二月闰年有 29 天,非闰年有 28 天
30 days in April, June, September and November
四月、六月、九月和十一月的 30 天
31 days in January, March, May, July, August, October and December
一月、三月、五月、七月、八月、十月和十二月的 31 天
Test:
测试:
The following dates should all pass validation:
以下日期均应通过验证:
1976-02-29
2000-02-29
2004-02-29
1999-01-31
The following dates should all fail validation:
以下日期均应未通过验证:
2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00
Range:
范围:
We'll test for dates from 1st Jan 1000 to 31st Dec 2999. Technically the currently used Gregorian calendar only came into use in 1753 for the British Empire and at various years in the 1600s for countries in Europe, but I'm not going to worry about that.
我们将测试从 1000 年 1 月 1 日到 2999 年 12 月 31 日的日期。从 技术上讲,目前使用的公历只在 1753 年为大英帝国使用,在 1600 年代的不同年份为欧洲国家使用,但我不会担心那个。
Regex to test for a leap year:
正则表达式测试闰年:
The years divisible by 400:
能被 400 整除的年份:
1200|1600|2000|2400|2800
can be shortened to:
(1[26]|2[048])00
if you wanted all years from 1AD to 9999 then this would do it:
(0[48]|[13579][26]|[2468][048])00
if you're happy with accepting 0000 as a valid year then it can be shortened:
([13579][26]|[02468][048])00
The years divisible by 4:
能被 4 整除的年份:
[12]\d([02468][048]|[13579][26])
The years divisible by 100:
能被 100 整除的年份:
[12]\d00
Not divisible by 100:
不能被 100 整除:
[12]\d([1-9]\d|\d[1-9])
The years divisible by 100 but not by 400:
能被 100 整除但不能被 400 整除的年份:
((1[1345789])|(2[1235679]))00
Divisible by 4 but not by 100:
能被 4 整除但不能被 100 整除:
[12]\d([2468][048]|[13579][26]|0[48])
The leap years:
闰年:
divisible by 400 or (divisible by 4 and not divisible by 100)
((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48])
Not divisible by 4:
不能被 4 整除:
[12]\d([02468][1235679]|[13579][01345789])
Not a leap year:
不是闰年:
Not divisible by 4 OR is divisible by 100 but not by 400
([12]\d([02468][1235679]|[13579][01345789]))|(((1[1345789])|(2[1235679]))00)
Valid Month and day excluding February(MM-DD):
除二月(MM-DD)外的有效月份和日期:
((01|03|05|07|08|10|12)-(0[1-9]|[12]\d|3[01]))|((04|06|09|11)-(0[1-9]|[12]\d|30))
shortened to:
((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30))
February with 28 days:
2 月 28 天:
02-(0[1-9]|1\d|2[0-8])
February with 29 days:
2 月 29 天:
02-(0[1-9]|[12]\d)
Valid date:
有效日期:
(leap year followed by (valid month-day-excluding-february OR 29-day-february))
OR
(non leap year followed by (valid month-day-excluding-february OR 28-day-february))
((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8]))))
So there you have it a regex for dates between 1st Jan 1000 and 31st Dec 2999 in YYYY-MM-DD format.
因此,您可以使用 YYYY-MM-DD 格式的正则表达式来表示 1000 年 1 月 1 日到 2999 年 12 月 31 日之间的日期。
I suspect it can be shortened quite a bit, but I'll leave that up to somebody else.
我怀疑它可以缩短很多,但我会把它留给其他人。
That will match all valid dates. If you want it to only be valid when it contains just one date and nothing else, then wrap it in ^( )$like so:
这将匹配所有有效日期。如果您希望它仅在仅包含一个日期而没有其他内容时才有效,则将其包装^( )$如下:
^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$
If you want it for an optional date entry (ie. it can be blank or a valid date) then add ^$|at the beginning, like so:
如果您希望它用于可选日期条目(即它可以是空白或有效日期),则^$|在开头添加,如下所示:
^$|^(((((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48]))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|[12]\d))))|((([12]\d([02468][1235679]|[13579][01345789]))|((1[1345789]|2[1235679])00))-((((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30)))|(02-(0[1-9]|1\d|2[0-8])))))$
回答by k102
You can make it this way:
你可以这样做:
if (preg_match("/\d{4}\-\d{2}-\d{2}/", $date)) {
echo 'true';
} else {
echo 'false';
}
but you'd better use this one:
但你最好使用这个:
$date = DateTime::createFromFormat('Y-m-d', $date);
if ($date) {
echo $date -> format('Y-m-d');
}
in this case you'll get an object which is muck easier to use than just strings.
在这种情况下,你会得到一个比字符串更容易使用的对象。
回答by Jonathan Muller
You can use a preg_match with a checkdate php function
您可以将 preg_match 与 checkdate php 函数一起使用
$date = "2012-10-05";
$split = array();
if (preg_match ("/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/", $date, $split))
{
return checkdate($split[2], $split[3], $split[1]);
}
return false;
回答by Micha93
I know that this is a old question. But I think I have a good solution.
我知道这是一个老问题。但我想我有一个很好的解决方案。
$date = "2016-02-21";
$format = "Y-m-d";
if(date($format, strtotime($date)) == date($date)) {
echo "true";
} else {
echo "false";
}
You can try it. If you change the date to 21.02.2016 the echo is false. And if you change the format after that to d.m.Y the echo is true.
你可以试试看。如果您将日期更改为 21.02.2016,则回声为假。如果在此之后将格式更改为 dmY,则回声为真。
With this easy code you should be able to check which date-format is used without checking it by the regex.
使用这个简单的代码,您应该能够检查使用了哪种日期格式,而无需通过正则表达式进行检查。
Maybe there is a person who will test it on every case. But I think my idea is generally valid. For me it seems logical.
也许有人会在每种情况下对其进行测试。但我认为我的想法通常是有效的。对我来说,这似乎是合乎逻辑的。
回答by marianboda
preg_match needs a / or another char as delimiter.
preg_match 需要一个 / 或另一个字符作为分隔符。
preg_match("/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/",$date)
you also should check for validity of that date so you wouldn't end up with something like 9999-19-38
你还应该检查那个日期的有效性,这样你就不会得到像 9999-19-38 这样的结果
bool checkdate ( int $month , int $day , int $year )
回答by kasimir
You could also do it like this:
你也可以这样做:
if (DateTime::createFromFormat('Y-m-d', $date)->format('Y-m-d') === $date) {
// date is correctly formatted and valid, execute some code
}
This will not only check the format, but also the validity of the date self, since DateTimewill create only valid dates and this needs to match the input.
这不仅会检查格式,还会检查日期自身的有效性,因为DateTime只会创建有效日期并且这需要匹配输入。
回答by Hyman
you can use
您可以使用
function validateDate($date, $format = 'Y-m-d H:i:s')
{
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
$date="2012-09-12";
echo validateDate($date, 'Y-m-d'); // true or false

