94

I am trying to write a function to determine if a string is a date/time using PHP. Basically a valid date/time would look like:

 2012-06-14 01:46:28

Obviously though its completely dynamic any of the values can change, but it should always be in form of XXXX-XX-XX XX:XX:XX, how can I write a regular expression to check for this pattern and return true if matched.

Salman A
  • 262,204
  • 82
  • 430
  • 521
Justin
  • 42,716
  • 77
  • 201
  • 296
  • 2
    Possible duplicate: http://stackoverflow.com/questions/37732/what-is-the-regex-pattern-for-datetime-2008-09-01-123545 – Fabian Jun 14 '12 at 08:59

17 Answers17

159

If that's your whole string, then just try parsing it:

if (DateTime::createFromFormat('Y-m-d H:i:s', $myString) !== false) {
  // it's a date
}
Cyril Graze
  • 3,881
  • 2
  • 21
  • 27
Joey
  • 344,408
  • 85
  • 689
  • 683
  • 17
    This is not a solution. I have `DateTime::createFromFormat('m/d/Y', '10/38/2013')` and that produces a valid DateTime object and not false. The date is converted to `object(DateTime)#39 (3) { ["date"]=> string(19) "2013-11-07 23:45:55" ["timezone_type"]=> int(3) ["timezone"]=> string(3) "UTC" }` – cj5 Oct 28 '13 at 23:48
  • 1
    Yikes. I love how these things are never pointed out in the documentation ... You don't happen to have found an alternative? (Edit: [Date formats](http://www.php.net/manual/en/datetime.formats.date.php) documents that you can over-/underflow months and days, but doesn't give a hint what to do when you *don't* want that behaviour. – Joey Oct 29 '13 at 06:24
  • Okay well there's no solution or setting to override this in PHP. I noted a workaround in the answers http://stackoverflow.com/a/19666600/486863 – cj5 Oct 29 '13 at 18:43
  • 1
    This solution indeed is not working ok for dates like the one specified by cj5 . Which can be very frustrating. I used as well this solution http://stackoverflow.com/questions/10120643/php-datetime-createfromformat-functionality/10120725#10120725 – Adrian C. Feb 26 '16 at 09:43
  • It's my format `Tue Oct 30 05:51:41 GMT+05:30 2018` how can we check it?, is there any common way of doing? – 151291 Dec 22 '18 at 05:58
  • You can combine with @Bjoern's answer and check that the formatted value matches the original `$date->format("Y-m-d H:i:s") == $myString` – Ali Gangji Oct 28 '19 at 22:33
  • Why so complicated? I prefer Yogesh Mistry answer below. – Samuel Ramzan Mar 06 '20 at 17:02
  • @SamuelRamzan: For one, that answer accepts [a lot](https://www.php.net/manual/en/datetime.formats.date.php) more formats than necessary. Broadening validation unnecessarily is probably a bad idea when you only want to expect a single input format. – Joey Mar 06 '20 at 18:13
  • very good answer – mercury Jan 16 '22 at 21:43
85

Easiest way to check if a string is a date:

if(strtotime($date_string)){
    // it's in date format
}
Yogesh Mistry
  • 2,082
  • 15
  • 19
  • 13
    I can't see why this would not be the accepted answer. Here is the PHP manual that specifically says this will return FALSE if anything but a date string: https://www.php.net/manual/en/function.strtotime.php – mrwpress Feb 13 '20 at 08:47
  • 8
    This is the best, elegant, simple and effective method I've seen so far. Thank You Yogesh Mistry – Samuel Ramzan Mar 06 '20 at 16:59
  • 12
    Does not work for `strtotime('a string');` -> returns current time. – Maarten Veerman Dec 04 '20 at 16:08
  • 2
    give incorrect result is string starts with `+` – ctf0 Mar 03 '21 at 12:07
  • 6
    `strtotime("2021-02-31 08:00:00")` will return `int(1614787200)` which evaluates to `TRUE` but it isn't a valid datetime string as OP asked for – SYNCRo May 09 '21 at 07:04
  • DateTime class is best for handling dates, strtotime is not a good practice. – Ravi Soni May 28 '22 at 05:22
  • @MaartenVeerman it solved my problem to determine if `strtotime('Not Defined')` and `strtotime('2022-10-10')` true of false. (PHP 8.1) – Vito Andolini Oct 27 '22 at 12:57
  • if this is given a string that is already a timestamp is will just return a new timestamp far in the future.. so does not work to determine if string is already a timestamp. – Janes Oosthuizen Apr 06 '23 at 05:52
53

Here's a different approach without using a regex:

function check_your_datetime($x) {
    return (date('Y-m-d H:i:s', strtotime($x)) == $x);
}
Leksat
  • 2,923
  • 1
  • 27
  • 26
Bjoern
  • 15,934
  • 4
  • 43
  • 48
  • 1
    This should be the accepted answer. It was the only solution that could properly handle leap years `"2023-02-29"` is `false` and `"2020-02-29"` is `true`. FYI, depending on your use case, you can optionally remove the `"H:i:s"` if you only care about date (and not time of day) – G M Feb 04 '23 at 02:57
33

In case you don't know the date format:

/**
 * Check if the value is a valid date
 *
 * @param mixed $value
 *
 * @return boolean
 */
function isDate($value) 
{
    if (!$value) {
        return false;
    }

    try {
        new \DateTime($value);
        return true;
    } catch (\Exception $e) {
        return false;
    }
}

var_dump(isDate('2017-01-06')); // true
var_dump(isDate('2017-13-06')); // false
var_dump(isDate('2017-02-06T04:20:33')); // true
var_dump(isDate('2017/02/06')); // true
var_dump(isDate('3.6. 2017')); // true
var_dump(isDate(null)); // false
var_dump(isDate(true)); // false
var_dump(isDate(false)); // false
var_dump(isDate('')); // false
var_dump(isDate(45)); // false
John Linhart
  • 1,746
  • 19
  • 23
10

In my project this seems to work:

function isDate($value) {
    if (!$value) {
        return false;
    } else {
        $date = date_parse($value);
        if($date['error_count'] == 0 && $date['warning_count'] == 0){
            return checkdate($date['month'], $date['day'], $date['year']);
        } else {
            return false;
        }
    }
}
Mowar
  • 402
  • 4
  • 9
  • What's date_parse and checkdate? – Head Wizard Locke Jan 09 '20 at 19:41
  • 1
    These are PHP given functions: https://www.php.net/manual/en/function.date-parse.php https://www.php.net/manual/en/function.checkdate.php 'date_parse' creates an array from the given string, by trying to identify possible date parts. 'checkdate' validates the date if you pass your variables in integer format as ($month, $day, $year). So the real question here is how well does the date_parse work. In my tests it worked better, than the other functions suggested by users on this page. – Mowar Jan 29 '20 at 08:45
  • 2
    Works well. Needed a method to decide if I was going to try and parse the date, or just display it as plain text. Worked well. – Goddard Feb 19 '20 at 15:15
  • 2
    Best solution to validate any date. Thanks! – Sebastián Cabanas Aug 04 '20 at 11:57
  • One caveat though. The date format you enter has to be 'culturally appropriate' to prevent the `date_parse` function from showing false positive errors. The function presumes that slash-separated date string is in North American format and a dash-separated date string is a European-style date. Therefore, a string like 30/9/2022 will show errors, but a 30-9-2022 string will pass with no problems. Interesting. – John Miller Dec 09 '22 at 08:03
  • This is **best** answer for check string is date(/time) from unknown format but it must be valid and acceptable by PHP. – vee May 09 '23 at 07:45
5

I use this function as a parameter to the PHP filter_var function.

  • It checks for dates in yyyy-mm-dd hh:mm:ss format
  • It rejects dates that match the pattern but still invalid (e.g. Apr 31)

function filter_mydate($s) {
    if (preg_match('@^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$@', $s, $m) == false) {
        return false;
    }
    if (checkdate($m[2], $m[3], $m[1]) == false || $m[4] >= 24 || $m[5] >= 60 || $m[6] >= 60) {
        return false;
    }
    return $s;
}
Salman A
  • 262,204
  • 82
  • 430
  • 521
4

A simple solution is:

echo is_numeric( strtotime( $string ) ) ? 'Yes' : 'No';
Patrick Buntsma
  • 621
  • 5
  • 7
3

Although this has an accepted answer, it is not going to effectively work in all cases. For example, I test date validation on a form field I have using the date "10/38/2013", and I got a valid DateObject returned, but the date was what PHP call "overflowed", so that "10/38/2013" becomes "11/07/2013". Makes sense, but should we just accept the reformed date, or force users to input the correct date? For those of us who are form validation nazis, We can use this dirty fix: https://stackoverflow.com/a/10120725/486863 and just return false when the object throws this warning.

The other workaround would be to match the string date to the formatted one, and compare the two for equal value. This seems just as messy. Oh well. Such is the nature of PHP dev.

Community
  • 1
  • 1
cj5
  • 785
  • 3
  • 12
  • 34
3
if (strtotime($date) > strtotime(0)) {
    echo 'it is a date'
}
dazed-and-confused
  • 1,293
  • 2
  • 11
  • 19
emmanuel
  • 133
  • 3
1

I found my answer here https://stackoverflow.com/a/19271434/1363220, bassically

$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.
if($d && $d->format($format) === $date) {
    //it's a proper date!
}
else {
    //it's not a proper date
}
ericksho
  • 347
  • 3
  • 12
0

I wouldn't use a Regex for this, but rather just split the string and check that the date is valid:

list($year, $month, $day, $hour, $minute, $second) = preg_split('%( |-|:)%', $mydatestring);
if(!checkdate($month, $day, $year)) {
     /* print error */
} 
/* check $hour, $minute and $second etc */
Artefact2
  • 7,516
  • 3
  • 30
  • 38
0

If your heart is set on using regEx then txt2re.com is always a good resource:

<?php

  $txt='2012-06-14 01:46:28';
  $re1='((?:2|1)\\d{3}(?:-|\\/)(?:(?:0[1-9])|(?:1[0-2]))(?:-|\\/)(?:(?:0[1-9])|(?:[1-2][0-9])|(?:3[0-1]))(?:T|\\s)(?:(?:[0-1][0-9])|(?:2[0-3])):(?:[0-5][0-9]):(?:[0-5][0-9]))';    # Time Stamp 1

  if ($c=preg_match_all ("/".$re1."/is", $txt, $matches))
  {
      $timestamp1=$matches[1][0];
      print "($timestamp1) \n";
  }

?>
PT114
  • 931
  • 3
  • 10
  • 18
0
 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

Community
  • 1
  • 1
0

If you have PHP 5.2 Joey's answer won't work. You need to extend PHP's DateTime class:

class ExDateTime extends DateTime{
    public static function createFromFormat($frmt,$time,$timezone=null){
        $v = explode('.', phpversion());
        if(!$timezone) $timezone = new DateTimeZone(date_default_timezone_get());
        if(((int)$v[0]>=5&&(int)$v[1]>=2&&(int)$v[2]>17)){
            return parent::createFromFormat($frmt,$time,$timezone);
        }
        return new DateTime(date($frmt, strtotime($time)), $timezone);
    }
}

and than you can use this class without problems:

ExDateTime::createFromFormat('d.m.Y G:i',$timevar);
MERT DOĞAN
  • 2,864
  • 26
  • 28
0

This solves for me, but also presents various other problems I think.

function validateTimeString($datetime, $format = "Y-m-d H:i:s"){
   return ($datetime == date($format, strtotime($datetime)));
 }
Harijs Krūtainis
  • 1,261
  • 14
  • 13
0

When I work with unconventional APIs, I sometimes get a bit of a messy return instead of a well defined date format. So I use a rather inelegant class and I readily admit that it is brutal and unconventional in principle but it does me good sometimes ^^.

class DateHelper
{
    private const DATE_FORMATS = [
        DATE_ATOM,
        DATE_COOKIE,
        DATE_RFC822,
        DATE_RFC850,
        DATE_RSS,
        DATE_W3C,
        "Y-m-d\TH:i:s.u",
        'Y-m-d\TH:i:s',
        "Y-m-d'T'H:i:s.SSS'Z'",
        "Y-m-d\TH:i:s.uP",
        "Y-m-d\TH:i:sP",
        "d/m/Y H:i:s",
    ];

    /**
     * @param string $inputStringDate
     * @return DateTime|null
     */
    public static function createDateFromUnknownFormat(string $inputStringDate): ?DateTime
    {
        $inputStringDate = str_replace('/', '-', $inputStringDate);
        preg_match('/^(\d{4})\-(\d{2})-(\d{2})$/', $inputStringDate, $result);
        if (!empty($result)) {
            return DateTime::createFromFormat('Y-m-d', $inputStringDate);
        }
        preg_match('/^(\d{2})\-(\d{2})-(\d{4})$/', $inputStringDate, $result);
        if (!empty($result)) {
            return DateTime::createFromFormat('d-m-Y', $inputStringDate);
        }
        foreach (self::DATE_FORMATS as $dateFormat) {
            if ($dateObject = DateTime::createFromFormat($dateFormat, $inputStringDate)) {
                return $dateObject;
            }
        }
        return null;
    }
}
arno
  • 792
  • 14
  • 33
-2

strtotime? Lists? Regular expressions?

What's wrong with PHP's native DateTime object?

http://www.php.net/manual/en/datetime.construct.php

Sherlock
  • 7,525
  • 6
  • 38
  • 79