27

Below is how I previously verified dates. I also had my own functions to convert date formats, however, now am using PHP's DateTime class so no longer need them. How should I best verify a valid date using DataTime? Please also let me know whether you think I should be using DataTime in the first place. Thanks

PS. I am using Object oriented style, and not Procedural style.

static public function verifyDate($date)
{
  //Given m/d/Y and returns date if valid, else NULL.
  $d=explode('/',$date);
  return ((isset($d[0])&&isset($d[1])&&isset($d[2]))?(checkdate($d[0],$d[1],$d[2])?$date:NULL):NULL);
}
user1032531
  • 24,767
  • 68
  • 217
  • 387

8 Answers8

78

You can try this one:

static public function verifyDate($date)
{
    return (DateTime::createFromFormat('m/d/Y', $date) !== false);
}

This outputs true/false. You could return DateTime object directly:

static public function verifyDate($date)
{
    return DateTime::createFromFormat('m/d/Y', $date);
}

Then you get back a DateTime object or false on failure.

UPDATE:

Thanks to Elvis Ciotti who showed that createFromFormat accepts invalid dates like 45/45/2014. More information on that: https://stackoverflow.com/a/10120725/1948627

I've extended the method with a strict check option:

static public function verifyDate($date, $strict = true)
{
    $dateTime = DateTime::createFromFormat('m/d/Y', $date);
    if ($strict) {
        $errors = DateTime::getLastErrors();
        if (!empty($errors['warning_count'])) {
            return false;
        }
    }
    return $dateTime !== false;
}
Community
  • 1
  • 1
bitWorking
  • 12,485
  • 1
  • 32
  • 38
  • Thanks Redreggae, Looks like this will work. If I didn't care about the original format but only that it is a valid date, would you recommend just creating a new DateTime($data), and using exceptions? – user1032531 Jan 24 '13 at 15:40
  • I have updated my answer...exceptions won't help, because the method doesn't throw an exception on failure only returns `false`. – bitWorking Jan 24 '13 at 15:43
  • Sorry didn't answer you question right. If you don't care about the date format, then shadyyx's solution is better. – bitWorking Jan 24 '13 at 15:51
  • I believe exceptions will work if all you care about is whether the date was of any acceptable format, but not if you were checking if it was in the m/d/Y format. – user1032531 Jan 24 '13 at 15:52
  • I think I didn't ask it right, but since I said "given m/d/Y", you answered it correct. Sorry for the confusion, I wish I could answer them both correct. – user1032531 Jan 24 '13 at 15:54
  • 4
    careful `DateTime::createFromFormat('Y-m-d', '2014-21-31')->format('d/m/Y')` outputs `01/10/2015`, not `false` – E Ciotti Jul 25 '14 at 11:55
  • 2
    @ElvisCiotti thanks for this information. I've made an update. – bitWorking Jul 25 '14 at 12:36
  • @bitWorking might I suggest that you add a `format` argument to the function, to allow for format strings to be passed to the Datetime function; and that the function itself return either the Datetime object created or `false`, to increase its utility? – Eamonn May 23 '18 at 13:45
  • Maybe i'm late with my comment but better late than never - `::createFromFormat('m/Y')` can return `true` on invalid date as `82/2017` **with strict** –  Apr 16 '19 at 20:38
16

With DateTime you can make the shortest date&time validator for all formats.

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

var_dump(validateDate('2012-02-28 12:12:12')); # true
var_dump(validateDate('2012-02-30 12:12:12')); # false

function was copied from this answer or php.net

Glavić
  • 42,781
  • 13
  • 77
  • 107
Faiyaz Alam
  • 1,191
  • 9
  • 27
11

You could check this resource: http://php.net/manual/en/datetime.getlasterrors.php

The PHP codes states:

try {
    $date = new DateTime('asdfasdf');
} catch (Exception $e) {
    print_r(DateTime::getLastErrors());
    // or
    echo $e->getMessage();
}
shadyyx
  • 15,825
  • 6
  • 60
  • 95
  • 1
    This doesn't throw an exception if the string is `0000-00-00 00:00:00` – rybo111 Oct 09 '18 at 15:53
  • The issue with this - not actually the code's, but PHP's fault - that from 24:00 to 24:59 time is accepted without error. – Mcload Mar 08 '19 at 12:07
6

Try this:

  function is_valid_date($date,$format='dmY')
  {
    $f = DateTime::createFromFormat($format, $date);
    $valid = DateTime::getLastErrors();         
    return ($valid['warning_count']==0 and $valid['error_count']==0);
  }
AstroCB
  • 12,337
  • 20
  • 57
  • 73
boctulus
  • 404
  • 9
  • 15
  • It's more concise and safe (check both counter: warning_count and error_count). I would just add a third condition (just in case): $f !== false. – Delmo Jan 10 '17 at 17:36
0
$date[] = '20/11/2569';     
$date[] = 'lksdjflskdj'; 
$date[] = '11/21/1973 10:20:30';
$date[] = '21/11/1973 10:20:30';
$date[] = " ' or uid like '%admin%"; 
foreach($date as $dt)echo date('Y-m-d H:i:s', strtotime($dt))."\n";

Output

1970-01-01 05:30:00
1970-01-01 05:30:00
1970-01-01 05:30:00
1973-11-21 10:20:30
1970-01-01 05:30:00
1970-01-01 05:30:00
bluepinto
  • 165
  • 9
0

I needed to allow user input in (n) different, known, formats...including microtime. Here is an example with 3.

function validateDate($date)
{
    $formats = ['Y-m-d','Y-m-d H:i:s','Y-m-d H:i:s.u'];
    foreach($formats as $format) {
        $d = DateTime::createFromFormat($format, $date);
        if ($d && $d->format($format) == $date) return true;
    }
    return false;
}
julius patta
  • 78
  • 1
  • 8
0

With the following an empty string like '' or 0 or '0000-00-00 00:00:00' is false

$valid = strtotime($date) > 0;
M-Phil
  • 9
  • 1
  • I know this comment is more than a decade old... Still, this is bascially a regex checker which doesn't cover months with less than 31 days such as '2000-11-31'. – Alexander Uhl Apr 01 '22 at 07:45
0

For me, the combination of date_parse and checkdate works best and it is almost one-liner:

$date="2024-02-29";
$dp=date_parse("$date");

if (sprintf("%04d-%02d-%02d",$dp['year'], $dp['month'], $dp['day'])===$date && checkdate($dp['month'], $dp['day'], $dp['year'])) {
    // format is OK and date is valid
}
Martin Kuchar
  • 51
  • 2
  • 3