PHP DateTime accepting invalid date

11,084

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()
Share:
11,084

Related videos on Youtube

Clement Herreman
Author by

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, 2020

Comments

  • Clement Herreman
    Clement Herreman about 4 years

    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::createFromFormat(). 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.

  • Clement Herreman
    Clement Herreman about 13 years
    The format isn't wrong, it really is `Y-m-d', I want to ensure that date validity is checked.
  • emmanuel honore
    emmanuel honore about 13 years
    But when m is the second part and you pass 13: 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
    Clement Herreman about 13 years
    Indeed, 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
    emmanuel honore about 13 years
    I added a link to an article.
  • Clement Herreman
    Clement Herreman about 13 years
    Nice article, but maybe you should also edit your answer about me using a bad format =).
  • Clement Herreman
    Clement Herreman over 10 years
    ouch, nice catch. What version of PHP are you using for this test? Maybe this was fixed along the way?
  • Glavić
    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 that DateTime::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, because 27 Feb 2012 is not Tuesday, it is Monday.
  • Glavić
    Glavić over 10 years
    In this example DateTime::getLastErrors() reports error only in case if textual day cannot be found or it is invalid, see.
  • Chris
    Chris over 9 years
    Much nicer solution, as this should handle both errors and warnings. Thanks!
  • Jan K. S.
    Jan K. S. over 8 years
    "Must be logical... in some weird twisted way." ==> Oh, we see that a lot in PHP.
  • Optimae
    Optimae almost 6 years
    Anyone reading this remember to check for both warnings AND errors, especially if you write your own isValidDate function to wrap around this.

Related