PHP正则expression式检查date是YYYY-MM-DD格式

我试图检查最终用户input的date是在YYYY-MM-DD。 正则expression式从来没有是我的强项,我一直得到preg_match()我已经设置一个虚假的返回值。

所以我假设我已经弄乱了正则expression式,详见下文。

$date="2012-09-12"; if (preg_match("^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$",$date)) { return true; }else{ return false; } 

有什么想法吗?

尝试这个。

 $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; } 

这可能是更好的使用另一种机制。

现代的解决scheme,与DateTime

 $dt = DateTime::createFromFormat("Ymd", $date); return $dt !== false && !array_sum($dt->getLastErrors()); 

这也validation了input: $dt !== false确保date可以用指定的格式进行parsing,而array_sum技巧是确保PHP不会执行“月份移动”的简单方法(例如,考虑1月32日是2月1)。 有关更多信息,请参阅DateTime::getLastErrors()

explode和检查的老式解决scheme:

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

这也validationinput是有效的date。 你当然可以用正则expression式来做,但是会更加大惊小怪,而且2月29日也不能用正则expression式来validation。

这种方法的缺点是,在任何情况下,您都必须非常小心地拒绝所有可能的“坏”input,而不发出通知。 就是这样:

  • explode限于返回3个令牌(所以如果input是“1-2-3-4”, $d将变成“3-4”)
  • ctype_digit用于确保input不包含任何非数字字符(除了破折号)
  • array_pad (带有会导致checkdate失败的默认值),以确保返回了足够的元素,这样如果input是“1-2”, list()将不会发出通知

标准:

每一年除以四是一个闰年,除非它可以被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 

二月有闰年29天,闰年不过28天

4月,6月,9月和11月30天

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

testing:

以下date都应通过validation:

 1976-02-29 2000-02-29 2004-02-29 1999-01-31 

以下date应该都不通过validation:

 2015-02-29 2015-04-31 1900-02-29 1999-01-32 2015-02-00 

范围:

我们将testing从1000年1月1日到2999年12月31日的date。从技术上讲,目前使用的公历只是在1753年为大英帝国使用,并在17世纪在欧洲各国的不同年份,但我不打算担心这一点。

正则expression式来testing闰年:

可以被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 

年可以被4整除的年份:

 [12]\d([02468][048]|[13579][26]) 

可以被100整除的年份:

 [12]\d00 

不能被100整除:

 [12]\d([1-9]\d|\d[1-9]) 

可以被100除尽而不能被400除的年份:

 ((1[1345789])|(2[1235679]))00 

除以4而不是100:

 [12]\d([2468][048]|[13579][26]|0[48]) 

闰年:

 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]) 

不能被4整除:

 [12]\d([02468][1235679]|[13579][01345789]) 

不是闰年:

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

不包括二月份的有效月份和date(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)) 

2月28日:

 02-(0[1-9]|1\d|2[0-8]) 

2月29日:

 02-(0[1-9]|[12]\d) 

有效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])))) 

因此,在1000年1月1日至2999年12月31date间,您可以使用YYYY-MM-DD格式的正则expression式。

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

这将匹配所有有效的date。 如果你只希望它只包含一个date而没有其他的东西,那么把它包装在^( )$就像这样:

 ^(((((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])))))$ 

如果你想要一个可选的date条目(即它可以是空白或有效的date),然后添加^$| 在开始时,像这样:

 ^$|^(((((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])))))$ 

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

/^(((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[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

你可以这样做:

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

但是你最好使用这个:

 $date = DateTime::createFromFormat('Ym-d', $date); if ($date) { echo $date -> format('Ym-d'); } 

在这种情况下,你会得到一个比string更容易使用的对象。

您可以使用checkg_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; 

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

 preg_match("/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/",$date) 

你也应该检查该date的有效性,所以你不会像9999-19-38那样结束

 bool checkdate ( int $month , int $day , int $year ) 

我知道这是一个老问题。 但是我觉得我有一个很好的解决scheme。

 $date = "2016-02-21"; $format = "Ymd"; if(date($format, strtotime($date)) == date($date)) { echo "true"; } else { echo "false"; } 

你可以尝试一下。 如果将date更改为21.02.2016,则回显为false。 如果你将格式改为dmY,则回显为真。

有了这个简单的代码,你应该能够检查使用哪种date格式,而不用正则expression式检查。

也许有一个人会对每一个案子进行testing。 但我认为我的想法一般是有效的。 对我来说这似乎合乎逻辑。

如果您想匹配该types的date,请使用:

 preg_match("~^\d{4}-\d{2}-\d{2}$~", $date) 

这应该告诉你,如果格式是有效的,如果inputdate是有效的。

  $datein = '2012-11-0'; if(preg_match('/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/', $datein)){ echo 'good'; }else{ echo 'no good'; } 

这完全取决于你想要这个function有多严格。 例如,如果你不想让12个月以上的月份和31天以上的日子(不依赖于月份,这将需要写date逻辑),它可能会变得非常复杂:

 function checkDate($date) { $regex = '/^' . '(' . // Allows years 0000-9999 '(?:[0-9]{4})' . '\-' . // Allows 01-12 '(?:' . '(?:01)|(?:02)|(?:03)|(?:04)|(?:05)|(?:06)|(?:07)|(?:08)|(?:09)|(?:10)|' . '(?:11)|(?:12)' . ')' . '\-' . // Allows 01-31 '(?:' . '(?:01)|(?:02)|(?:03)|(?:04)|(?:05)|(?:06)|(?:07)|(?:08)|(?:09)|(?:10)|' . '(?:11)|(?:12)|(?:13)|(?:14)|(?:15)|(?:16)|(?:17)|(?:18)|(?:19)|(?:20)|' . '(?:21)|(?:22)|(?:23)|(?:24)|(?:25)|(?:26)|(?:27)|(?:28)|(?:29)|(?:30)|' . '(?:31)' . ')' . '$/'; if ( preg_match($regex, $date) ) { return true; } return false; } $result = checkDate('2012-09-12'); 

就个人而言,我只是想: /^([0-9]{4}\-([0-9]{2}\-[0-9]{2})$/

要在PHP中使用date,你应该遵循PHP标准,所以给定的正则expression式将确保你有有效的date,可以使用PHP操作。

  preg_match("/^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date) 

这个方法可以用来在PHP中validationdate。 当前的方法是以mm / dd / yyyy格式。 您必须根据您的格式和爆炸中的分隔符更新checkdate中的参数序列。

  function isValidDate($dt) { $dtArr = explode('/', $dt); if (!empty($dtArr[0]) && !empty($dtArr[1]) && !empty($dtArr[2])) { return checkdate((int) $dtArr[0], (int) $dtArr[1], (int) $dtArr[2]); } else { return false; } }