PHP DateTime accepting invalid date
Solution 1
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).
Solution 2
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');
}
Solution 3
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
Solution 4
Look for checkdate()
function at php documentation. It will help you :)
Solution 5
You can do that :
DateTime::getLastErrors()
Related videos on Youtube
Clement Herreman
Software developer, mainly web and API development. I design solution for people's problem, using the right tools. I mainly use PHP (Symfony, API-Platform), bash, SQL. Some devops with docker, varnish, ansible. Graduated from EPSI Arras, France. Currently lead developer at motoblouz.com, France.
Updated on March 21, 2020Comments
-
Clement Herreman about 4 years
I'm having trouble using the PHP
DateTime
class, and more specifically theDateTime::createFromFormat()
.I get a date from a string, then try to instanciate a DateTime object, using
DateTime::createFromFormat()
. But, when I give this function a date that cannot exist, it is still working, returning me a validDateTime
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.
-
Clement Herreman about 13 yearsThe format isn't wrong, it really is `Y-m-d', I want to ensure that date validity is checked.
-
emmanuel honore about 13 yearsBut when
m
is the second part and you pass13
: its calculated as January in the next year. Everything is fine here! This is the way PHP calculates with overlapping numbers on dates. -
Clement Herreman about 13 yearsIndeed, that's what I just discovered, but 2 questions rise : 1. where the hell is it documented ? 2. Am I the only that doesn't find this behavior logical/expectable ?
-
emmanuel honore about 13 yearsI added a link to an article.
-
Clement Herreman about 13 yearsNice article, but maybe you should also edit your answer about me using a bad format =).
-
Clement Herreman over 10 yearsouch, nice catch. What version of PHP are you using for this test? Maybe this was fixed along the way?
-
Glavić over 10 years@ClementHerreman: this result is on all PHP version that support
DateTime::createFromFormat
, that is all above php >= 5.3.0. See it in action here. I never said thatDateTime::getLastErrors()
should report warning or error in this case, probably this works as intended (ignoring string days), but IMO, if we are doing validation function, it should matter, because27 Feb 2012
is notTuesday
, it isMonday
. -
Glavić over 10 yearsIn this example
DateTime::getLastErrors()
reports error only in case if textual day cannot be found or it is invalid, see. -
Chris over 9 yearsMuch nicer solution, as this should handle both errors and warnings. Thanks!
-
Jan K. S. over 8 years"Must be logical... in some weird twisted way." ==> Oh, we see that a lot in PHP.
-
Optimae almost 6 yearsAnyone reading this remember to check for both warnings AND errors, especially if you write your own isValidDate function to wrap around this.