Correctly determine if date string is a valid date in that format

PhpDateDatetime

Php Problem Overview


I'm receiving a date string from an API, and it is formatted as yyyy-mm-dd.

I am currently using a regex to validate the string format, which works ok, but I can see some cases where it could be a correct format according to the string but actually an invalid date. i.e. 2013-13-01, for example.

Is there a better way in PHP to take a string such as 2013-13-01 and tell if it is a valid date or not for the format yyyy-mm-dd?

Php Solutions


Solution 1 - Php

You can use DateTime::createFromFormat() for this purpose:

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;
}

[Function taken from this answer. Also on php.net. Originally written by Glavić.]


Test cases:

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

Demo!

Solution 2 - Php

Determine if any string is a date

function checkIsAValidDate($myDateString){
    return (bool)strtotime($myDateString);
}

Solution 3 - Php

Use in simple way with php prebuilt function:

function checkmydate($date) {
  $tempDate = explode('-', $date);
  // checkdate(month, day, year)
  return checkdate($tempDate[1], $tempDate[2], $tempDate[0]);
}

Test

   checkmydate('2015-12-01'); //true
   checkmydate('2015-14-04'); //false

Solution 4 - Php

Determine if string is a date, even if string is a non-standard format

(strtotime doesn't accept any custom format)

<?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');

Solution 5 - Php

This option is not only simple but also accepts almost any format, although with non-standard formats it can be buggy.

$timestamp = strtotime($date);
return $timestamp ? $date : null;

Solution 6 - Php

You can also Parse the date for month date and year and then you can use the PHP function checkdate() which you can read about here: http://php.net/manual/en/function.checkdate.php

You can also try this one:

$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';
    }

Solution 7 - Php

The easiest way to check if given date is valid probably converting it to unixtime using strtotime, formatting it to the given date's format, then comparing it:

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

Of course you can use regular expression to check for validness, but it will be limited to given format, every time you will have to edit it to satisfy another formats, and also it will be more than required. Built-in functions is the best way (in most cases) to achieve jobs.

Solution 8 - Php

I'm afraid that most voted solution (https://stackoverflow.com/a/19271434/3283279) is not working properly. The fourth test case (var_dump(validateDate('2012-2-25')); // false) is wrong. The date is correct, because it corresponds to the format - the m allows a month with or without leading zero (see: http://php.net/manual/en/datetime.createfromformat.php). Therefore a date 2012-2-25 is in format Y-m-d and the test case must be true not false.

I believe that better solution is to test possible error as follows:

function validateDate($date, $format = 'Y-m-d') {
    DateTime::createFromFormat($format, $date);
    $errors = DateTime::getLastErrors();

    return $errors['warning_count'] === 0 && $errors['error_count'] === 0;
}

Solution 9 - Php

Accordling with cl-sah's answer, but this sound better, shorter...

function checkmydate($date) {
  $tempDate = explode('-', $date);
  return checkdate($tempDate[1], $tempDate[2], $tempDate[0]);
}

Test

checkmydate('2015-12-01');//true
checkmydate('2015-14-04');//false

Solution 10 - Php

I have this thing that, even with PHP, I like to find functional solutions. So, for example, the answer given by @migli is really a good one, highly flexible and elegant.

But it has a problem: what if you need to validate a lot of DateTime strings with the same format? You would have to repeat the format all over the place, what goes against the DRY principle. We could put the format in a constant, but still, we would have to pass the constant as an argument to every function call.

But fear no more! We can use currying to our rescue! PHP doesn't make this task pleasant, but it's still possible to implement currying with PHP:

<?php
function validateDateTime($format)
{
    return function($dateStr) use ($format) {
        $date = DateTime::createFromFormat($format, $dateStr);
        return $date && $date->format($format) === $dateStr;
    };
}

So, what we just did? Basically we wrapped the function body in an anonymous and returned such function instead. We can call the validation function like this:

validateDateTime('Y-m-d H:i:s')('2017-02-06 17:07:11'); // true

Yeah, not a big difference... but the real power comes from the partially applied function, made possible by currying:

// 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

Functional programming FTW!

Solution 11 - Php

How about this one?

We simply use a try-catch block.

$dateTime = 'an invalid datetime';

try {
    $dateTimeObject = new DateTime($dateTime);
} catch (Exception $exc) {
    echo 'Do something with an invalid DateTime';
}

This approach is not limited to only one date/time format, and you don't need to define any function.

Solution 12 - Php

Validate with checkdate function:

$date = '2019-02-30';

$date_parts = explode( '-', $date );

if(checkdate( $date_parts[1], $date_parts[2], $date_parts[0] )){
	//date is valid
}else{
	//date is invalid
}

Solution 13 - Php

Tested Regex solution:

    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;
    }

This will return null if the date is invalid or is not yyyy-mm-dd format, otherwise it will return the date.

Solution 14 - Php

/*********************************************************************************
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) === '-');
}

Solution 15 - Php

To add onto the accepted answer, you can further check for a valid date or DateTime by checking if the formatted date is an instanceof DateTime.

$date = DateTime::createFromFormat('Ymd', $value);
$is_datetime = ($date instanceof DateTime);
$is_valid_datetime_format = $is_datetime
  ? ($date->format('Ymd') === $value)
  : false;

if (!$is_datetime || !$is_valid_datetime_format) {
  // Not a valid date.
  return false;
}

This will catch any values that are not a DateTime such as random strings or an invalid date such as 20202020.

Solution 16 - Php

    /**** 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);
        }

    }

Solution 17 - Php

Try and let me know it works for me

$date = \DateTime::createFromFormat('d/m/Y', $dataRowValue);
if (!empty($date)) {
//Your logic
}else{
//Error
}

if you pass any alpha or alphanumberic values it will give you the empty value in return

Solution 18 - Php

Give this a try:

$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";
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarty WallaceView Question on Stackoverflow
Solution 1 - PhpAmal MuraliView Answer on Stackoverflow
Solution 2 - PhparshView Answer on Stackoverflow
Solution 3 - PhpvineetView Answer on Stackoverflow
Solution 4 - PhpmigliView Answer on Stackoverflow
Solution 5 - PhpgalkiView Answer on Stackoverflow
Solution 6 - PhpSuvash sarkerView Answer on Stackoverflow
Solution 7 - Phpuser4600953View Answer on Stackoverflow
Solution 8 - PhpBarvajzView Answer on Stackoverflow
Solution 9 - PhpsdotbertoliView Answer on Stackoverflow
Solution 10 - PhpVictor SchröderView Answer on Stackoverflow
Solution 11 - PhpJulianView Answer on Stackoverflow
Solution 12 - PhpPrince AhmedView Answer on Stackoverflow
Solution 13 - PhpAkumaburnView Answer on Stackoverflow
Solution 14 - PhpMarco DemaioView Answer on Stackoverflow
Solution 15 - PhpJake StewartView Answer on Stackoverflow
Solution 16 - PhpSubham GhoruiView Answer on Stackoverflow
Solution 17 - PhpBhupendra MehraView Answer on Stackoverflow
Solution 18 - PhpYoussef GamraView Answer on Stackoverflow