php date validation

112,289

Solution 1

You could use checkdate. For example, something like this:

$test_date = '03/22/2010';
$test_arr  = explode('/', $test_date);
if (checkdate($test_arr[0], $test_arr[1], $test_arr[2])) {
    // valid date ...
}

A more paranoid approach, that doesn't blindly believe the input:

$test_date = '03/22/2010';
$test_arr  = explode('/', $test_date);
if (count($test_arr) == 3) {
    if (checkdate($test_arr[0], $test_arr[1], $test_arr[2])) {
        // valid date ...
    } else {
        // problem with dates ...
    }
} else {
    // problem with input ...
}

Solution 2

You can use some methods of the DateTime class, which might be handy; namely, DateTime::createFromFormat() in conjunction with DateTime::getLastErrors().

$test_date = '03/22/2010';

$date = DateTime::createFromFormat('m/d/Y', $test_date);
$date_errors = DateTime::getLastErrors();
if ($date_errors['warning_count'] + $date_errors['error_count'] > 0) {
    $errors[] = 'Some useful error message goes here.';
}

This even allows us to see what actually caused the date parsing warnings/errors (look at the warnings and errors arrays in $date_errors).

Solution 3

Though checkdate is good, this seems much concise function to validate and also you can give formats. [Source]

function validateDate($date, $format = 'Y-m-d H:i:s') {
    $d = DateTime::createFromFormat($format, $date);
    return $d && $d->format($format) == $date;
}

function was copied from this answer or php.net


The extra ->format() is needed for cases where the date is invalid but createFromFormat still manages to create a DateTime object. For example:

// Gives "2016-11-10 ..." because Thursday falls on Nov 10
DateTime::createFromFormat('D M j Y', 'Thu Nov 9 2016');

// false, Nov 9 is a Wednesday
validateDate('Thu Nov 9 2016', 'D M j Y');

Solution 4

Instead of the bulky DateTime object .. just use the core date() function

function isValidDate($date, $format= 'Y-m-d'){
    return $date == date($format, strtotime($date));
}

Solution 5

Use it:

function validate_Date($mydate,$format = 'DD-MM-YYYY') {

    if ($format == 'YYYY-MM-DD') list($year, $month, $day) = explode('-', $mydate);
    if ($format == 'YYYY/MM/DD') list($year, $month, $day) = explode('/', $mydate);
    if ($format == 'YYYY.MM.DD') list($year, $month, $day) = explode('.', $mydate);

    if ($format == 'DD-MM-YYYY') list($day, $month, $year) = explode('-', $mydate);
    if ($format == 'DD/MM/YYYY') list($day, $month, $year) = explode('/', $mydate);
    if ($format == 'DD.MM.YYYY') list($day, $month, $year) = explode('.', $mydate);

    if ($format == 'MM-DD-YYYY') list($month, $day, $year) = explode('-', $mydate);
    if ($format == 'MM/DD/YYYY') list($month, $day, $year) = explode('/', $mydate);
    if ($format == 'MM.DD.YYYY') list($month, $day, $year) = explode('.', $mydate);       

    if (is_numeric($year) && is_numeric($month) && is_numeric($day))
        return checkdate($month,$day,$year);
    return false;           
}         
Share:
112,289
Pablo Lopez
Author by

Pablo Lopez

Updated on August 20, 2020

Comments

  • Pablo Lopez
    Pablo Lopez over 3 years

    Im trying to to set up a php date validation (MM/DD/YYYY) but I'm having issues. Here is a sample of what I got:

    $date_regex = '%\A(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d\z%'; 
    
    $test_date = '03/22/2010'; 
    if (preg_match($date_regex, $test_date,$_POST['birthday']) ==true) {
        $errors[] = 'user name most have no spaces';`
    
  • Cody Caughlan
    Cody Caughlan over 11 years
    This is the best solution as it also checks for invalid dates, e.g. Feb 29. A pure regex approach based on formatting would allow invalid dates.
  • Madara's Ghost
    Madara's Ghost over 11 years
    +1 for a regexless solution. Not all problems need a regex solution.
  • zerkms
    zerkms over 11 years
    regex solution also checked for a format, while this doesn't. If string foobar is passed - you'll get notices
  • salathe
    salathe over 11 years
    Let's come into the 21st century. DateTime::createFromFormat() and DateTime::getLastErrors(). Thank me later.
  • Sk446
    Sk446 over 11 years
    @salathe has the best approach. Nicolás should really update his answer as it's providing an old approach of doing this.
  • s3m3n
    s3m3n about 11 years
    It's worth to mention that you can check it straight with DateTime::createFromFormat() only, by checking if it's false, so if(DateTime::createFromFormat('m/d/Y', $test_date) === false) exit('bad date format');
  • salathe
    salathe about 11 years
    Only very crudely @s3m3n. For example, without checking for warnings, "44/33/2211" is a valid m/d/Y date (it is 2nd Sep 2214 btw).
  • s3m3n
    s3m3n about 11 years
    You are right, but in my case I'm only validating if moderator didn't make literal mistake in date format which is going directly to database instead of logical sense of given date. Someone else might need the same thing.
  • Nitsan Baleli
    Nitsan Baleli almost 10 years
    DateTime::createFromFormat(PHP 5 >= 5.3.0)
  • o0'.
    o0'. almost 9 years
    This is not always the best approach. If you receive the input already in separated values, but you don't know how exactly they are formatted (M vs. MM, YYYY vs. YY), I think checkdate would be more flexible and accept anything that resembles a valid date. Additionaly, with DateTime, if I write 31 as the month it will be considered valid, and simply add 2 years and set it to July (since 31%12 = 7). I really don't think this would be expected behaviour by many people…
  • Gras Double
    Gras Double over 8 years
    Why/when is the extra verification $d->format($format) == $date needed?
  • BillyTom
    BillyTom over 8 years
    But why would you want regex in the first place?
  • jjwdesign
    jjwdesign about 8 years
    @Gras Double - Validation. He's returning true/false, but ensuring that the DateTime object was created and that the formatted DateTime equals the function input $date.
  • Gras Double
    Gras Double about 8 years
    Sure, but a return (bool) $d; would do it. My question was, as the createFromFormat succeeded, in what scenario could the $d->format() be different from the input?
  • Gras Double
    Gras Double about 8 years
    I have found this: validateDate('Mon, 21-Jan-2041 15:24:52 GMT', DateTime::COOKIE);. Returns false because the ->format() produces "Monday" instead of "Mon". Though, it would be better to return true, as the input is valid. I'm updating the answer.
  • Gras Double
    Gras Double about 8 years
    Found out a purpose for the ->format() verification. Answer updated again.
  • Gras Double
    Gras Double about 8 years
    @ksimka Actually yes, see answer above.
  • Rich R
    Rich R about 8 years
    The call to format will throw an exception if the date is invalid.
  • GordonM
    GordonM almost 7 years
    This question has already had plenty of far superior answers, what's more it's years old. Your answer adds nothing. Please don't indulge in necromancing.
  • rolinger
    rolinger about 4 years
    Everyone, in multiple posts, keeps saying to use checkdate. But checkdate fails if the year is : 2, 20, 202, 2020 or even 20201 - it returns true every time.
  • Andrew Rump
    Andrew Rump over 3 years
    Why not just test if strtotime() === false?
  • Nicolás Ozimica
    Nicolás Ozimica over 3 years
    @rolinger Why should checkdate fail with such years??? First: are they invalid years? Second: the documentation for checkdate explicitly states that: "The year is between 1 and 32767 inclusive."