Correctly determine if date string is a valid date in that format
我从API接收日期字符串,格式为
我目前正在使用正则表达式验证字符串格式,这可以正常工作,但我可以看到一些情况,根据字符串它可能是正确的格式,但实际上是无效的日期。 例如,
在PHP中有更好的方法来获取
您可以使用
1 2 3 4 5 6 | function validateDate($date, $format = 'Y-m-d') { $d = DateTime::createFromFormat($format, $date); // The Y ( 4 digits year ) returns TRUE for any integer with any number of digits so changing the comparison from == to === fixes the issue. return $d && $d->format($format) === $date; } |
[功能取自这个答案。也在php.net上。最初由Glavi撰写?。]
测试用例:
1 2 3 4 5 6 7 8 9 | var_dump(validateDate('2013-13-01')); // false var_dump(validateDate('20132-13-01')); // false var_dump(validateDate('2013-11-32')); // false var_dump(validateDate('2012-2-25')); // false var_dump(validateDate('2013-12-01')); // true var_dump(validateDate('1970-12-01')); // true var_dump(validateDate('2012-02-29')); // true var_dump(validateDate('2012', 'Y')); // true var_dump(validateDate('12012', 'Y')); // false |
演示!
确定是否有任何字符串是日期
1 2 3 |
使用php预建函数以简单的方式使用:
1 2 3 4 5 |
测试
1 2 | checkmydate('2015-12-01'); //true checkmydate('2015-14-04'); //false |
确定字符串是否为日期,即使字符串是非标准格式
(strtotime不接受任何自定义格式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <?php function validateDateTime($dateStr, $format) { date_default_timezone_set('UTC'); $date = DateTime::createFromFormat($format, $dateStr); return $date && ($date->format($format) === $dateStr); } // These return true validateDateTime('2001-03-10 17:16:18', 'Y-m-d H:i:s'); validateDateTime('2001-03-10', 'Y-m-d'); validateDateTime('2001', 'Y'); validateDateTime('Mon', 'D'); validateDateTime('March 10, 2001, 5:16 pm', 'F j, Y, g:i a'); validateDateTime('March 10, 2001, 5:16 pm', 'F j, Y, g:i a'); validateDateTime('03.10.01', 'm.d.y'); validateDateTime('10, 3, 2001', 'j, n, Y'); validateDateTime('20010310', 'Ymd'); validateDateTime('05-16-18, 10-03-01', 'h-i-s, j-m-y'); validateDateTime('Monday 8th of August 2005 03:12:46 PM', 'l jS \of F Y h:i:s A'); validateDateTime('Wed, 25 Sep 2013 15:28:57', 'D, d M Y H:i:s'); validateDateTime('17:03:18 is the time', 'H:m:s \i\s \t\h\e \t\i\m\e'); validateDateTime('17:16:18', 'H:i:s'); // These return false validateDateTime('2001-03-10 17:16:18', 'Y-m-D H:i:s'); validateDateTime('2001', 'm'); validateDateTime('Mon', 'D-m-y'); validateDateTime('Mon', 'D-m-y'); validateDateTime('2001-13-04', 'Y-m-d'); |
这个选项不仅简单,而且几乎可以接受任何格式,但是对于非标准格式,它可能是错误的。
1 2 |
您还可以解析月份日期和年份的日期,然后您可以使用PHP函数
你也可以尝试这个:
1 2 3 4 5 6 7 8 | $date="2013-13-01"; if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date)) { echo 'Date is valid'; }else{ echo 'Date is invalid'; } |
符合cl-sah的答案,但这听起来更好,更短......
1 2 3 4 |
测试
1 2 | checkmydate('2015-12-01');//true checkmydate('2015-14-04');//false |
我有这个东西,即使使用PHP,我也希望找到功能性解决方案。所以,例如,@ migli给出的答案确实很好,非常灵活和优雅。
但它有一个问题:如果你需要用相同的格式验证很多DateTime字符串怎么办?你必须在整个地方重复这种格式,这与DRY原则背道而驰。我们可以将格式放在常量中,但是,我们必须将常量作为参数传递给每个函数调用。
但不要再害怕了!我们可以使用currying来救援! PHP不会使这个任务变得愉快,但仍然可以用PHP实现currying:
1 2 3 4 5 6 7 8 | <?php function validateDateTime($format) { return function($dateStr) use ($format) { $date = DateTime::createFromFormat($format, $dateStr); return $date && $date->format($format) === $dateStr; }; } |
那么,我们刚刚做了什么?基本上我们将函数体包装成匿名并返回这样的函数。我们可以像这样调用验证函数:
1 | validateDateTime('Y-m-d H:i:s')('2017-02-06 17:07:11'); // true |
是的,没有太大的区别......但真正的力量来自部分应用的功能,通过currying来实现:
1 2 3 4 5 6 7 | // Get a partially applied function $validate = validateDateTime('Y-m-d H:i:s'); // Now you can use it everywhere, without repeating the format! $validate('2017-02-06 17:09:31'); // true $validate('1999-03-31 07:07:07'); // true $validate('13-2-4 3:2:45'); // false |
功能编程FTW!
检查给定日期是否有效的最简单方法可能是使用
return date('Y-m-d', strtotime($date)) === $date;
}
当然,您可以使用正则表达式来检查有效性,但它将限制为给定的格式,每次您必须编辑它以满足其他格式,并且它将超过要求。内置功能是实现工作的最佳方式(在大多数情况下)。
这个怎么样?
我们只使用try-catch块。
1 2 3 4 5 6 7 | $dateTime = 'an invalid datetime'; try { $dateTimeObject = new DateTime($dateTime); } catch (Exception $exc) { echo 'Do something with an invalid DateTime'; } |
此方法不仅限于一种日期/时间格式,您无需定义任何功能。
经过测试的Regex解决方案:
1 2 3 4 5 6 7 | function isValidDate($date) { if (preg_match("/^(((((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)) { return $date; } return null; } |
如果日期无效或不是yyyy-mm-dd格式,则返回null,否则返回日期。
使用checkdate函数进行验证:
1 2 3 4 5 6 7 8 9 |
1 2 3 4 5 6 7 8 9 10 | /********************************************************************************* Returns TRUE if the input parameter is a valid date string in"YYYY-MM-DD" format (aka"MySQL date format") The date separator can be only the '-' character. *********************************************************************************/ function isMysqlDate($yyyymmdd) { return checkdate(substr($yyyymmdd, 5, 2), substr($yyyymmdd, 8), substr($yyyymmdd, 0, 4)) && (substr($yyyymmdd, 4, 1) === '-') && (substr($yyyymmdd, 7, 1) === '-'); } |
我担心大多数投票解决方案(https://stackoverflow.com/a/19271434/3283279)无法正常工作。第四个测试用例(var_dump(validateDate('2012-2-25')); // false)是错误的。日期是正确的,因为它对应于格式 - m允许一个月有或没有前导零(参见:http://php.net/manual/en/datetime.createfromformat.php)。因此,日期2012-2-25的格式为Y-m-d,测试用例必须为true而不是false。
我相信更好的解决方案是测试可能的错误如下:
1 2 3 4 5 6 | function validateDate($date, $format = 'Y-m-d') { DateTime::createFromFormat($format, $date); $errors = DateTime::getLastErrors(); return $errors['warning_count'] === 0 && $errors['error_count'] === 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /**** date check is a recursive function. it's need 3 argument MONTH,DAY,YEAR. ******/ $always_valid_date = $this->date_check($month,$day,$year); private function date_check($month,$day,$year){ /** checkdate() is a php function that check a date is valid or not. if valid date it's return true else false. **/ $status = checkdate($month,$day,$year); if($status == true){ $always_valid_date = $year . '-' . $month . '-' . $day; return $always_valid_date; }else{ $day = ($day - 1); /**recursive call**/ return $this->date_check($month,$day,$year); } } |
尝试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | $date ="2017-10-01"; function date_checker($input,$devider){ $output = false; $input = explode($devider, $input); $year = $input[0]; $month = $input[1]; $day = $input[2]; if (is_numeric($year) && is_numeric($month) && is_numeric($day)) { if (strlen($year) == 4 && strlen($month) == 2 && strlen($day) == 2) { $output = true; } } return $output; } if (date_checker($date, '-')) { echo"The function is working"; }else { echo"The function isNOT working"; } |