用于检查日期的PHP Regex是YYYY-MM-DD格式

cos*_*ari 82 php regex date-format

我正在尝试检查最终用户输入的日期是否在YYYY-MM-DD中.正则表达式从来都不是我的强项,我不断为我设置的preg_match()获得错误的返回值.

所以我假设我弄乱了正则表达式,详情如下.

$date="2012-09-12";

if (preg_match("^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$",$date))
    {
        return true;
    }else{
        return false;
    }
Run Code Online (Sandbox Code Playgroud)

有什么想法吗?

Avi*_*ese 177

试试这个.

$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;
}
Run Code Online (Sandbox Code Playgroud)

  • `return(bool)preg_match("/ ^ [0-9] {4} - (0 [1-9] | 1 [0-2]) - (0 [1-9] | [1-2] [0 -9] | 3 [0-1])$ ​​/",$日期);` (16认同)
  • 这个问题是关于如何检查日期格式(YYYY-MM-DD),标记为已接受的答案并不总是最佳答案,它只是意味着它适用于提问者,阅读这个美丽的旅游:http:http: //stackoverflow.com/tour. (6认同)
  • 为什么这被标记为正确的答案?对于2016-02-30和2016-09-31这样的无效日期,这将返回true (4认同)
  • @Graham 老帖子我知道但同意 Stramin - 这个问题询问格式验证 - 不是实际的日期验证 (2认同)

Jon*_*Jon 88

为此使用另一种机制可能更好.

现代解决方案,包括DateTime:

$dt = DateTime::createFromFormat("Y-m-d", $date);
return $dt !== false && !array_sum($dt::getLastErrors());
Run Code Online (Sandbox Code Playgroud)

这也验证了输入:$dt !== false确保可以使用指定的格式解析日期,并且array_sum技巧是确保PHP不进行"月移"的简洁方法(例如,考虑1月32日是2月1日).有关DateTime::getLastErrors()更多信息,请参阅

老派解决方案:explodecheckdate:

list($y, $m, $d) = array_pad(explode('-', $date, 3), 3, 0);
return ctype_digit("$y$m$d") && checkdate($m, $d, $y);
Run Code Online (Sandbox Code Playgroud)

这验证输入也是有效日期.当然,你可以用正则表达式做到这一点,但它会更加大惊小怪 - 2月29日根本无法使用正则表达式进行验证.

这种方法的缺点是你必须非常小心地拒绝所有可能的"坏"输入而不在任何情况下发出通知.这是如何做:

  • explode仅限返回3个令牌(如果输入为"1-2-3-4",$d则变为"3-4")
  • ctype_digit 用于确保输入不包含任何非数字字符(除了破折号)
  • array_pad使用(具有将导致checkdate失败的默认值)以确保返回足够的元素,以便如果输入为"1-2" list()将不会发出通知


小智 39

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

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

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


Gra*_*ham 35

标准:

每年可被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
Run Code Online (Sandbox Code Playgroud)

2月在闰年有29天,在闰年有28天

四月,六月,九月和十一月30天

1月,3月,5月,7月,8月,10月和12月31天

测试:

以下日期应全部通过验证:

1976-02-29
2000-02-29
2004-02-29
1999-01-31
Run Code Online (Sandbox Code Playgroud)

以下日期都应验证失败:

2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00
Run Code Online (Sandbox Code Playgroud)

范围:

我们将测试从1000年1月1日到2999年12月31日的日期.从 技术上讲,目前使用的公历仅在1753年用于大英帝国,在17世纪的欧洲各国的17年不同年份,但我不会担心这一点.

正则表达式测试闰年:

可被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
Run Code Online (Sandbox Code Playgroud)

可被4整除的年份:

[12]\d([02468][048]|[13579][26])
Run Code Online (Sandbox Code Playgroud)

可被100整除的年份:

[12]\d00
Run Code Online (Sandbox Code Playgroud)

不能被100整除:

[12]\d([1-9]\d|\d[1-9])
Run Code Online (Sandbox Code Playgroud)

这些年可被100整除但不会被400整除:

((1[1345789])|(2[1235679]))00
Run Code Online (Sandbox Code Playgroud)

可被4除以100而不是100:

[12]\d([2468][048]|[13579][26]|0[48])
Run Code Online (Sandbox Code Playgroud)

闰年:

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])
Run Code Online (Sandbox Code Playgroud)

不能被4整除:

[12]\d([02468][1235679]|[13579][01345789])
Run Code Online (Sandbox Code Playgroud)

不是闰年:

Not divisible by 4 OR is divisible by 100 but not by 400
([12]\d([02468][1235679]|[13579][01345789]))|(((1[1345789])|(2[1235679]))00)
Run Code Online (Sandbox Code Playgroud)

有效的月份和日期(二月除外)(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))
Run Code Online (Sandbox Code Playgroud)

二月28天:

02-(0[1-9]|1\d|2[0-8])
Run Code Online (Sandbox Code Playgroud)

2月29日:

02-(0[1-9]|[12]\d)
Run Code Online (Sandbox Code Playgroud)

有效日期:

(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]))))
Run Code Online (Sandbox Code Playgroud)

因此,您可以在YYYY-MM-DD格式的1000年1月1日到2999年12月31日之间使用它.

我怀疑它可以缩短很多,但我会把它留给其他人.

这将匹配所有有效日期.如果你希望它只在一个日期只包含一个日期时才有效,那么^( )$就像这样包装它:

^(((((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])))))$
Run Code Online (Sandbox Code Playgroud)

如果你想要一个可选的日期条目(即它可以是空白或有效日期),那么^$|在开头添加,如下所示:

^$|^(((((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])))))$
Run Code Online (Sandbox Code Playgroud)

  • 这是一个英雄的表达,并解释得非常好. (7认同)

k10*_*102 16

你可以这样做:

if (preg_match("/\d{4}\-\d{2}-\d{2}/", $date)) {
    echo 'true';
} else {
    echo 'false';
}
Run Code Online (Sandbox Code Playgroud)

但你最好使用这个:

$date = DateTime::createFromFormat('Y-m-d', $date);
if ($date) {
    echo $date -> format('Y-m-d');
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,你会得到一个比简单的字符串更容易使用的对象.

  • 此处使用的 dateTime 技术将为 2016-05-44 之类的日期返回 true,该日期不是实际日期 (3认同)

Jon*_*ler 7

你可以使用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;
Run Code Online (Sandbox Code Playgroud)


小智 7

验证通用日期格式的函数:

function validateDate($date, $format = 'Y-m-d') {
  $d = DateTime::createFromFormat($format, $date);
  return $d && $d->format($format) == $date;
}
Run Code Online (Sandbox Code Playgroud)

执行示例:

var_dump(validateDate('2021-02-28')); // true
var_dump(validateDate('2021-02-29')); // false
Run Code Online (Sandbox Code Playgroud)


Mic*_*a93 6

我知道这是一个老问题.但我认为我有一个很好的解决方案.

$date = "2016-02-21";
$format = "Y-m-d";

if(date($format, strtotime($date)) == date($date)) {
    echo "true";
} else {
    echo "false";
}
Run Code Online (Sandbox Code Playgroud)

你可以尝试一下.如果将日期更改为21.02.2016,则回显为假.如果你之后将格式更改为dmY,则回显为真.

使用这个简单的代码,你应该能够检查使用哪种日期格式而不用正则表达式进行检查.

也许有人会在每个案例中对其进行测试.但我认为我的想法通常是有效的.对我来说似乎合乎逻辑.


mar*_*oda 5

preg_match 需要一个 / 或另一个字符作为分隔符。

preg_match("/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/",$date)
Run Code Online (Sandbox Code Playgroud)

你还应该检查那个日期的有效性,这样你就不会得到像 9999-19-38 这样的结果

bool checkdate ( int $month , int $day , int $year )
Run Code Online (Sandbox Code Playgroud)


the*_*yen 5

可能对某人有用:

$patterns = array(
            'Y'           =>'/^[0-9]{4}$/',
            'Y-m'         =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])$/',
            'Y-m-d'       =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])$/',
            'Y-m-d H'     =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\s(0|[0-1][0-9]|2[0-4])$/',
            'Y-m-d H:i'   =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\s(0|[0-1][0-9]|2[0-4]):?(0|[0-5][0-9]|60)$/',
            'Y-m-d H:i:s' =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\s(0|[0-1][0-9]|2[0-4]):?((0|[0-5][0-9]):?(0|[0-5][0-9])|6000|60:00)$/',
        );
echo preg_match($patterns['Y'], '1996'); // true
echo preg_match($patterns['Y'], '19966'); // false
echo preg_match($patterns['Y'], '199z'); // false
echo preg_match($patterns['Y-m'], '1996-0'); // false
echo preg_match($patterns['Y-m'], '1996-09'); // true
echo preg_match($patterns['Y-m'], '1996-1'); // true
echo preg_match($patterns['Y-m'], '1996/1'); // true
echo preg_match($patterns['Y-m'], '1996/12'); // true
echo preg_match($patterns['Y-m'], '1996/13'); // false
echo preg_match($patterns['Y-m-d'], '1996-11-1'); // true
echo preg_match($patterns['Y-m-d'], '1996-11-0'); // false
echo preg_match($patterns['Y-m-d'], '1996-11-32'); // false
echo preg_match($patterns['Y-m-d H'], '1996-11-31 0'); // true
echo preg_match($patterns['Y-m-d H'], '1996-11-31 00'); // true
echo preg_match($patterns['Y-m-d H'], '1996-11-31 24'); // true
echo preg_match($patterns['Y-m-d H'], '1996-11-31 25'); // false
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 2400'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:00'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:59'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:60'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:61'); // false
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:61'); // false
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:6000'); // true
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:60:00'); // true
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:59:59'); // true
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:59:60'); // false
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:60:01'); // false
Run Code Online (Sandbox Code Playgroud)

  • `'1996-11-31 24:00'); // true`,真的吗?而且,有时一分钟有61秒,参见:https://en.wikipedia.org/wiki/Leap_second (2认同)