PHP DateTime accepting invalid date
I'm having trouble using the PHP DateTime
class, and more specifically the DateTime::createFromFormat()
.
I get a date from a string, then try to instanciate a DateTime object, using DateTime::cr开发者_如何学CeateFromFormat()
. But, when I give this function a date that cannot exist, it is still working, returning me a valid DateTime
object, with a valid date, which isn't the date I gave it.
Code example :
$badDate = '2010-13-03';
$date = DateTime::createFromFormat('Y-m-d', $badDate);
var_dump($date);
/*
object(DateTime)#284 (3) {
["date"]=>
string(19) "2011-01-03 10:01:20"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
*/
Any ideas? I really need a way to check date validity.
Thank you.
Edit:
I just found why, see my answer.
You have to make use of DateTime::getLastErrors()
which will contain the error The parsed date was invalid
.
$badDate = '2010-13-03';
$date = DateTime::createFromFormat('Y-m-d', $badDate);
if( DateTime::getLastErrors()['warning_count'] > 0 ){
//not a correct date
}else{
//correct date
print $date->format('Y-m-d');
}
DateTime::createFromFormat
doesn't throw exception/return false when the given date is impossible. It try to guess the expected date.
If you give it '2010-01-32'
(as in Januar, 32th), it will return a DateTime
object containing Februar, 1st (Januar 31th + 1 day). Must be logical... in some weird twisted way.
To check the validity, you must check the DateTime::getLastErrors()
which contains warning, like for my case :
array(4) {
["warning_count"]=>
int(1)
["warnings"]=>
array(1) {
[10]=>
string(27) "The parsed date was invalid"
}
["error_count"]=>
int(0)
["errors"]=>
array(0) {
}
}
This behavior seems to come from the UNIX timestamp which PHP calculate, based on the year, month and date you give it (even if the date is invalid).
I found example where validation based on DateTime::getLastErrors()
will fail, so better solution would be to compare inputed date with generated date.
Code:
function validateDate($date, $format = 'Y-m-d')
{
$dt = DateTime::createFromFormat($format, $date);
return $dt && $dt->format($format) == $date;
}
Use example:
var_dump(validateDate('2012-02-28')); # true
var_dump(validateDate('2012-02-30')); # false
# you can validate and date/time format
var_dump(validateDate('14:50', 'H:i')); # true
var_dump(validateDate('14:99', 'H:i')); # false
# this is the example where validation with `DateTime::getLastErrors()` will fail
var_dump(validateDate('Tue, 28 Feb 2012 12:12:12 +0200', DateTime::RSS)); # true
var_dump(validateDate('Tue, 27 Feb 2012 12:12:12 +0200', DateTime::RSS)); # false
Look for checkdate()
function at php documentation. It will help you :)
You can do that :
DateTime::getLastErrors()
change
$date = DateTime::createFromFormat('Y-m-d', $badDate);
into
$date = DateTime::createFromFormat('Y-d-m', $badDate);
Your given format is wrong, you properly mixed up days and months...
To understand what is behind the magical calculation of dates read this very very good article by Derick Rethans and all comments ;)
精彩评论