PHP Regex to check date is in YYYY-MM-DD format
Asked Answered
T

27

131

I'm trying to check that dates entered by end users are in the YYYY-MM-DD. Regex has never been my strong point, I keep getting a false return value for the preg_match() I have setup.

So I'm assuming I have made a mess of the regex, detailed below.

$date="2012-09-12";

if (preg_match("^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$",$date))
    {
        return true;
    }else{
        return false;
    }

Any thoughts?

Tinct answered 2/11, 2012 at 11:27 Comment(4)
Regex is not enough to validate a date. After regex you should also use one of these two: date("Y-m-d", strtotime("2012-09-12"))=="2012-09-12"; or PHP's checkdate ( int $month , int $day , int $year ).Pyroligneous
Im not trying to validate it at this point, i just want to make sure its in the YYYY-MM-DD format.Tinct
For a user entered value, what better "point" in time to validate other than right after the regex, on form submission (so you can display an error)?Pyroligneous
Fair point, could save a hickup later.Tinct
I
231

Try this.

$date="2012-09-12";

if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date)) {
    return true;
} else {
    return false;
}
Intermix answered 2/11, 2012 at 11:33 Comment(7)
return (bool)preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date);Pyroligneous
Why has this been marked as the correct answer? This returns true for a number of invalid dates like 2016-02-30 and 2016-09-31Carola
This question is about how to check a date format (YYYY-MM-DD), and an answer marked as accepted is not always the best answer, it just means that it worked for the person who asked, read this beautiful tour: stackoverflow.com/tour .Donothingism
@Carola old post I know but agree with Stramin - this question asks about format validation - not actual date validationClarino
validate datetime preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T(0[1-9]|1[0-9]|2[0-4]):(0[1-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|6[0-9])$/",$dateTime)Agglutination
Should be as simple as this (one of my answers properly formatted down the page): $date_pattern = '/^(19|20)\d{2}\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01])$/'; if (empty($date) || (!preg_match("$date_pattern", $date, $m) || (!checkdate($m[2], $m[3], $m[1])))) { $echo 'Invalid Start date e.g. YYYY-MM-DD'; }Counterweight
Not a correct answer. I tried 0~9 numbers without dashes and it returns as true.Alethiaaletta
U
136

It's probably better to use another mechanism for this.

The modern solution, with DateTime:

// For PHP >= 8.2
$dt = DateTime::createFromFormat("Y-m-d", $date);
return $dt !== false && $dt::getLastErrors() === false;

// For PHP < 8.2
$dt = DateTime::createFromFormat("Y-m-d", $date);
return $dt !== false && !array_sum($dt::getLastErrors());

This validates the input too: $dt !== false ensures that the date can be parsed with the specified format and the array_sum trick is a terse way of ensuring that PHP did not do "month shifting" (e.g. consider that January 32 is February 1). See DateTime::getLastErrors() for more information.

Old-school solution with explode and checkdate:

list($y, $m, $d) = array_pad(explode('-', $date, 3), 3, 0);
return ctype_digit("$y$m$d") && checkdate($m, $d, $y);

This validates that the input is a valid date as well. You can do that with a regex of course, but it's going to be more fuss -- and February 29 cannot be validated with a regex at all.

The drawback of this approach is that you have to be very careful to reject all possible "bad" inputs while not emitting a notice under any circumstances. Here's how:

  • explode is limited to return 3 tokens (so that if the input is "1-2-3-4", $d will become "3-4")
  • ctype_digit is used to make sure that the input does not contain any non-numeric characters (apart from the dashes)
  • array_pad is used (with a default value that will cause checkdate to fail) to make sure that enough elements are returned so that if the input is "1-2" list() will not emit a notice
Uzzia answered 2/11, 2012 at 11:32 Comment(8)
+1, always used DateTime and never heard about checkdate... shame on me.Capitalistic
@k102: DateTime can also do this. I just finished fleshing out the answer, have a look again if you 'd like.Uzzia
Looking at the PHP manual, it looks like the first solution will validate incomplete dates (filling out the missing values from the current date).Supercolumnar
Another problem with solution #1: "non-existant values roll over", e.g. 2001-02-31 becomes 2001-03-03. (Though the OP hasn't asked explicitly that this isn't possible.)Supercolumnar
@user2428118: Did you try solution #1 exactly as given, or just the first line? Did you click the link I give to the documentation for getLastErrors?Uzzia
@Uzzia Sorry, hadn't looked through the comments on the getLastErrors page.Supercolumnar
DateTime::createFromFormat("Y-m-d", $date); This will pass a single digit month also. For example, 2021-3-23 would be valid, while the user apparently is looking for only allowing 2021-03-23Rancorous
I will suggest this for PHP 8: $dt = DateTime::createFromFormat("Y-m-d", $date); return $dt !== false && (false === $dt::getLastErrors() || !array_sum($dt::getLastErrors()));Alyce
C
52

yyyy-mm-dd : /^((((19|[2-9]\d)\d{2})\-(0[13578]|1[02])\-(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\-(0[13456789]|1[012])\-(0[1-9]|[12]\d|30))|(((19|[2-9]\d)\d{2})\-02\-(0[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\-02\-29))$/g

yyyy/mm/dd : /^((((19|[2-9]\d)\d{2})\/(0[13578]|1[02])\/(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\/(0[13456789]|1[012])\/(0[1-9]|[12]\d|30))|(((19|[2-9]\d)\d{2})\/02\/(0[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\/02\/29))$/g

mm-dd-yyyy : /^(((0[13578]|1[02])\-(0[1-9]|[12]\d|3[01])\-((19|[2-9]\d)\d{2}))|((0[13456789]|1[012])\-(0[1-9]|[12]\d|30)\-((19|[2-9]\d)\d{2}))|(02\-(0[1-9]|1\d|2[0-8])\-((19|[2-9]\d)\d{2}))|(02\-29\-((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g

mm/dd/yyyy : /^(((0[13578]|1[02])\/(0[1-9]|[12]\d|3[01])\/((19|[2-9]\d)\d{2}))|((0[13456789]|1[012])\/(0[1-9]|[12]\d|30)\/((19|[2-9]\d)\d{2}))|(02\/(0[1-9]|1\d|2[0-8])\/((19|[2-9]\d)\d{2}))|(02\/29\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g

dd/mm/yyyy : /^(((0[1-9]|[12]\d|3[01])\/(0[13578]|1[02])\/((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\/(0[13456789]|1[012])\/((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\/02\/((19|[2-9]\d)\d{2}))|(29\/02\/((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g

dd-mm-yyyy : /^(((0[1-9]|[12]\d|3[01])\-(0[13578]|1[02])\-((19|[2-9]\d)\d{2}))|((0[1-9]|[12]\d|30)\-(0[13456789]|1[012])\-((19|[2-9]\d)\d{2}))|((0[1-9]|1\d|2[0-8])\-02\-((19|[2-9]\d)\d{2}))|(29\-02\-((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))))$/g

Cundiff answered 3/6, 2016 at 10:1 Comment(1)
The above all work for dates from 1900 to 9999 which is what is needed most of the time and is 74 characters shorter than my attempt (re the yyyy-mm-dd format). if you want dates pre-1900, then a minor tweak to Shyju answer will allow from year 1000 and is another 23 characters shorter: ^((([1-9]\d{3})\-(0[13578]|1[02])\-(0[1-9]|[12]\d|3[01]))|(((19|[2-9]\d)\d{2})\-(0[13456789]|1[012])\-(0[1-9]|[12]\d|30))|(([1-9]\d{3})\-02\-(0[1-9]|1\d|2[0-8]))|(([1-9]\d(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))\-02\-29))$Carola
C
40

Criteria:

Every year divisible by 4 is a leap year, except when it is divisible by 100 unless it is divisible by 400. So:

2004 - leap year - divisible by 4
1900 - not a leap year - divisible by 4, but also divisible by 100
2000 - leap year - divisible by 4, also divisible by 100, but divisible by 400

February has 29 days in a leap year and 28 when not a leap year

30 days in April, June, September and November

31 days in January, March, May, July, August, October and December

Test:

The following dates should all pass validation:

1976-02-29
2000-02-29
2004-02-29
1999-01-31

The following dates should all fail validation:

2015-02-29
2015-04-31
1900-02-29
1999-01-32
2015-02-00

Range:

We'll test for dates from 1st Jan 1000 to 31st Dec 2999. Technically the currently used Gregorian calendar only came into use in 1753 for the British Empire and at various years in the 1600s for countries in Europe, but I'm not going to worry about that.

Regex to test for a leap year:

The years divisible by 400:

1200|1600|2000|2400|2800
can be shortened to:
(1[26]|2[048])00

if you wanted all years from 1AD to 9999 then this would do it:
(0[48]|[13579][26]|[2468][048])00
if you're happy with accepting 0000 as a valid year then it can be shortened:
([13579][26]|[02468][048])00

The years divisible by 4:

[12]\d([02468][048]|[13579][26])

The years divisible by 100:

[12]\d00

Not divisible by 100:

[12]\d([1-9]\d|\d[1-9])

The years divisible by 100 but not by 400:

((1[1345789])|(2[1235679]))00

Divisible by 4 but not by 100:

[12]\d([2468][048]|[13579][26]|0[48])

The leap years:

divisible by 400 or (divisible by 4 and not divisible by 100)
((1[26]|2[048])00)|[12]\d([2468][048]|[13579][26]|0[48])

Not divisible by 4:

[12]\d([02468][1235679]|[13579][01345789])

Not a leap year:

Not divisible by 4 OR is divisible by 100 but not by 400
([12]\d([02468][1235679]|[13579][01345789]))|(((1[1345789])|(2[1235679]))00)

Valid Month and day excluding February(MM-DD):

((01|03|05|07|08|10|12)-(0[1-9]|[12]\d|3[01]))|((04|06|09|11)-(0[1-9]|[12]\d|30))
shortened to:
((0[13578]|1[02])-(0[1-9]|[12]\d|3[01]))|((0[469]|11)-(0[1-9]|[12]\d|30))

February with 28 days:

02-(0[1-9]|1\d|2[0-8])

February with 29 days:

02-(0[1-9]|[12]\d)

Valid date:

(leap year followed by (valid month-day-excluding-february OR 29-day-february)) 
OR
(non leap year followed by (valid month-day-excluding-february OR 28-day-february))

((((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]))))

So there you have it a regex for dates between 1st Jan 1000 and 31st Dec 2999 in YYYY-MM-DD format.

I suspect it can be shortened quite a bit, but I'll leave that up to somebody else.

That will match all valid dates. If you want it to only be valid when it contains just one date and nothing else, then wrap it in ^( )$ like so:

^(((((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])))))$

If you want it for an optional date entry (ie. it can be blank or a valid date) then add ^$| at the beginning, like so:

^$|^(((((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])))))$
Carola answered 2/4, 2015 at 16:14 Comment(5)
That is a heroic expression, and explained very well.Twickenham
Do you have strong proof that it will pass every valid case and fail on every invalid case?Sandal
@Md Ashraful Islam NoCarola
@Carola Altough no problem, we are using it in our website. I hope no problem will occur.Sandal
@Md Ashraful Islam - We also use it and have not had any problems with it so farCarola
C
20

You can make it this way:

if (preg_match("/\d{4}\-\d{2}-\d{2}/", $date)) {
    echo 'true';
} else {
    echo 'false';
}

but you'd better use this one:

$date = DateTime::createFromFormat('Y-m-d', $date);
if ($date) {
    echo $date -> format('Y-m-d');
}

in this case you'll get an object which is muck easier to use than just strings.

Capitalistic answered 2/11, 2012 at 11:34 Comment(3)
The dateTime technique used here will return true for a date like 2016-05-44 which is not an actual dateWonderment
This is not a good example especially if you want to get date( Y-m-d ). Example: 0175-44-19927 will pass.Esposito
I don't see ^ and $.Bacteria
S
11

I know that this is a old question. But I think I have a good solution.

$date = "2016-02-21";
$format = "Y-m-d";

if(date($format, strtotime($date)) == date($date)) {
    echo "true";
} else {
    echo "false";
}

You can try it. If you change the date to 21.02.2016 the echo is false. And if you change the format after that to d.m.Y the echo is true.

With this easy code you should be able to check which date-format is used without checking it by the regex.

Maybe there is a person who will test it on every case. But I think my idea is generally valid. For me it seems logical.

Searcy answered 20/2, 2016 at 23:11 Comment(2)
I don't think you need date() around $date on the if line. if(date($format, strtotime($date)) == $date) - should be sufficientDoubletalk
This seems to work fine and it handles leap years okFlooring
V
9

Probably useful to someone:

$patterns = array(
            'Y'           =>'/^[0-9]{4}$/',
            'Y-m'         =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])$/',
            'Y-m-d'       =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])$/',
            'Y-m-d H'     =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\s(0|[0-1][0-9]|2[0-4])$/',
            'Y-m-d H:i'   =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\s(0|[0-1][0-9]|2[0-4]):?(0|[0-5][0-9]|60)$/',
            'Y-m-d H:i:s' =>'/^[0-9]{4}(-|\/)([1-9]|0[1-9]|1[0-2])(-|\/)([1-9]|0[1-9]|[1-2][0-9]|3[0-1])\s(0|[0-1][0-9]|2[0-4]):?((0|[0-5][0-9]):?(0|[0-5][0-9])|6000|60:00)$/',
        );
echo preg_match($patterns['Y'], '1996'); // true
echo preg_match($patterns['Y'], '19966'); // false
echo preg_match($patterns['Y'], '199z'); // false
echo preg_match($patterns['Y-m'], '1996-0'); // false
echo preg_match($patterns['Y-m'], '1996-09'); // true
echo preg_match($patterns['Y-m'], '1996-1'); // true
echo preg_match($patterns['Y-m'], '1996/1'); // true
echo preg_match($patterns['Y-m'], '1996/12'); // true
echo preg_match($patterns['Y-m'], '1996/13'); // false
echo preg_match($patterns['Y-m-d'], '1996-11-1'); // true
echo preg_match($patterns['Y-m-d'], '1996-11-0'); // false
echo preg_match($patterns['Y-m-d'], '1996-11-32'); // false
echo preg_match($patterns['Y-m-d H'], '1996-11-31 0'); // true
echo preg_match($patterns['Y-m-d H'], '1996-11-31 00'); // true
echo preg_match($patterns['Y-m-d H'], '1996-11-31 24'); // true
echo preg_match($patterns['Y-m-d H'], '1996-11-31 25'); // false
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 2400'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:00'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:59'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:60'); // true
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:61'); // false
echo preg_match($patterns['Y-m-d H:i'], '1996-11-31 24:61'); // false
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:6000'); // true
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:60:00'); // true
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:59:59'); // true
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:59:60'); // false
echo preg_match($patterns['Y-m-d H:i:s'], '1996-11-31 24:60:01'); // false
Vanillin answered 21/2, 2020 at 3:32 Comment(1)
'1996-11-31 24:00'); // true, really? Moreover, sometimes there is 61 seconds in a minute, see: en.wikipedia.org/wiki/Leap_secondCarisa
A
8

You can use a preg_match with a checkdate php function

$date  = "2012-10-05";
$split = array();
if (preg_match ("/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/", $date, $split))
{
    return checkdate($split[2], $split[3], $split[1]);
}

return false;
Attlee answered 2/11, 2012 at 11:34 Comment(1)
return preg_match ("/^([0-9]{4})-([0-9]{2})-([0-9]{2})$/", $date, $split)) && checkdate($split[2],$split[3],$split[1]) ;Pyroligneous
C
7

Function to validate generic date format:

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

Example of execution:

var_dump(validateDate('2021-02-28')); // true
var_dump(validateDate('2021-02-29')); // false
Chancelor answered 29/11, 2019 at 9:52 Comment(2)
Please put your answer always in context instead of just pasting code. See here for more details. Please also edit your answer to contain all parts of the code in the markdown blockHolguin
Source : php.net/manual/en/function.checkdate.php#113205Alyce
L
6

preg_match needs a / or another char as delimiter.

preg_match("/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/",$date)

you also should check for validity of that date so you wouldn't end up with something like 9999-19-38

bool checkdate ( int $month , int $day , int $year )
Legged answered 2/11, 2012 at 11:34 Comment(0)
E
4

You could also do it like this:

if (DateTime::createFromFormat('Y-m-d', $date)->format('Y-m-d') === $date) {

    // date is correctly formatted and valid, execute some code

}

This will not only check the format, but also the validity of the date self, since DateTime will create only valid dates and this needs to match the input.

Elsie answered 12/2, 2018 at 15:47 Comment(0)
P
4

you can use

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

$date="2012-09-12";    
echo validateDate($date, 'Y-m-d'); // true or false
Pontone answered 13/4, 2018 at 13:38 Comment(0)
B
3

Format 1 : $format1 = "2012-12-31";

Format 2 : $format2 = "31-12-2012";

if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$format1)) {
    return true;
} else {
    return false;
}

if (preg_match("/^(0[1-9]|[1-2][0-9]|3[0-1])-(0[1-9]|1[0-2])-[0-9]{4}$/",$format2)) {
    return true;
} else {
    return false;
}
Bestiality answered 25/7, 2019 at 11:42 Comment(0)
C
3

The below ensures digits YYYY(1900-2099)-MM(01-12)-DD(01-31) as well as utilises checkdate() function for date correctness e.g. 29 Feb:

$date_pattern = '/^(19|20)\d{2}\-(0[1-9]|1[0-2])\-(0[1-9]|[12][0-9]|3[01])$/';

if (empty($date) || (!preg_match("$date_pattern", $date, $m) || (!checkdate($m[2], $m[3], $m[1])))) {
    echo 'Invalid Start date e.g. YYYY-MM-DD';
}

To change date patterns and year range:

// pattern DD/MM/YYYY where DD (01-31), MM (01-12) and YYYY (1950-2099) & have to be digits - replace checkdate () with !checkdate($m[2], $m[1], $m[3]

// To extend year range e.g. 1900-2099 /^(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[0-2])/(19|20)\d{2}$/ - replace checkdate () with !checkdate($m[2], $m[1], $m[3]

Counterweight answered 30/9, 2021 at 10:48 Comment(0)
S
2

If you want to match that type of date, use:

preg_match("~^\d{4}-\d{2}-\d{2}$~", $date)
Service answered 2/11, 2012 at 11:34 Comment(0)
S
2

This should tell you if the format is valid and if the input date is valid.

    $datein = '2012-11-0';

    if(preg_match('/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/', $datein)){
        echo 'good';
    }else{
        echo 'no good';
    }
Shifflett answered 2/11, 2012 at 11:47 Comment(0)
C
2

Check and validate YYYY-MM-DD date in one line statement

function isValidDate($date) {
    return preg_match("/^(\d{4})-(\d{1,2})-(\d{1,2})$/", $date, $m)
        ? checkdate(intval($m[2]), intval($m[3]), intval($m[1]))
        : false;
}

The output will be:

var_dump(isValidDate("2018-01-01")); // bool(true)
var_dump(isValidDate("2018-1-1"));   // bool(true)
var_dump(isValidDate("2018-02-28")); // bool(true)
var_dump(isValidDate("2018-02-30")); // bool(false)

Day and month without leading zero are allowed. If you don't want to allow this, the regexp should be:

"/^(\d{4})-(\d{2})-(\d{2})$/"
Capello answered 19/11, 2017 at 16:22 Comment(0)
I
2

I was searching "how to validate date" and found this solution, Its old but i ll share below method that can be use to validate date in php,

checkdate('01', '31', '2019')
Interrogatory answered 21/11, 2019 at 9:29 Comment(0)
S
1

It all depends on how strict you want this function to be. For instance, if you don't want to allow months above 12 and days above 31 (not depending on the month, that would require writing date-logic), it could become pretty complicated:

function checkDate($date)
{
  $regex = '/^' . 
    '(' .

    // Allows years 0000-9999
    '(?:[0-9]{4})' .
    '\-' .

    // Allows 01-12
    '(?:' .
    '(?:01)|(?:02)|(?:03)|(?:04)|(?:05)|(?:06)|(?:07)|(?:08)|(?:09)|(?:10)|' .
    '(?:11)|(?:12)' .
    ')' .
    '\-' .

    // Allows 01-31
    '(?:' .
    '(?:01)|(?:02)|(?:03)|(?:04)|(?:05)|(?:06)|(?:07)|(?:08)|(?:09)|(?:10)|' .
    '(?:11)|(?:12)|(?:13)|(?:14)|(?:15)|(?:16)|(?:17)|(?:18)|(?:19)|(?:20)|' .
    '(?:21)|(?:22)|(?:23)|(?:24)|(?:25)|(?:26)|(?:27)|(?:28)|(?:29)|(?:30)|' .
    '(?:31)' .
    ')' .

    '$/';

  if ( preg_match($regex, $date) ) {
    return true;
  }

  return false;
}

$result = checkDate('2012-09-12');

Personally I'd just go for: /^([0-9]{4}\-([0-9]{2}\-[0-9]{2})$/

Sheehy answered 2/11, 2012 at 12:37 Comment(2)
This regex is unnecessarily complicated. 0[1-9]|1[0-2] matches month 01-12 and 0[1-9]|[12][0-9]|3[01] matches day 01-31.Gonococcus
Excuse me while i vomitMerbromin
R
1

To work with dates in php you should follow the php standard so the given regex will assure that you have valid date that can operate with PHP.

    preg_match("/^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date)
Rose answered 23/9, 2014 at 4:49 Comment(1)
Your rgex is wrong, it will not match 1980-01-01 but will match 2100-02-29Carisa
F
1

If it is of any help, here is a regex for j-n-Y format (year has to be greater than 2018):

if (preg_match('/^([1-9]|[1-2][0-9]|[3][0-1])\-([1-9]|[1][0-2])\-(?:20)([1][8-9]|[2-9][0-9])$/', $date)) {
   // Do stuff
}
Fontanel answered 7/10, 2018 at 10:18 Comment(0)
L
1

From Laravel 5.7 and date format i.e.: 12/31/2019

function checkDateFormat(string $date): bool
{
    return preg_match("/^(0[1-9]|1[0-2])\/(0[1-9]|[1-2][0-9]|3[0-1])\/[0-9]{4}$/", $date);
}
Lipsey answered 26/6, 2019 at 10:30 Comment(0)
M
1

Easiest way is to convert it to desired format:

$date="2012-09-12";
$date=strtotime($date);
if($date != NULL){
    /*Valid Date*/
    $date=date("Y-m-d",$date);
    return true;
}else{
    /*InValid Date*/
    return false;
};
Materialism answered 20/11, 2022 at 4:17 Comment(0)
E
0

This method can be useful to validate date in PHP. Current method is for mm/dd/yyyy format. You have to update parameter sequence in checkdate as per your format and delimiter in explode .

    function isValidDate($dt)
    {
        $dtArr = explode('/', $dt);
        if (!empty($dtArr[0]) && !empty($dtArr[1]) && !empty($dtArr[2])) {
            return checkdate((int) $dtArr[0], (int) $dtArr[1], (int) $dtArr[2]);
        } else {
            return false;
        }
    }
Exquisite answered 29/5, 2017 at 11:52 Comment(0)
I
0

[If you use Symfony 4.1.2 try this][1]

  $validDate = explode("-",$request->get('date'));
        if (checkdate(filter_var($validDate[1],FILTER_SANITIZE_NUMBER_INT),filter_var($validDate[0],FILTER_SANITIZE_NUMBER_INT),filter_var($validDate[2],FILTER_SANITIZE_NUMBER_INT))){
            $date = date_create(filter_var($request->get('date'),FILTER_SANITIZE_SPECIAL_CHARS));
        }else{
            return $this->redirectToRoute('YOUR_ROUTE');
        }
Incautious answered 31/1, 2019 at 14:8 Comment(0)
C
0

A more pragmatic pattern could be like this

$date="2012-09-12";

if (preg_match("/^(20[0-9]{2})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/",$date)) {
    return true;
} else {
    return false;
}

Which will prevent to put 9999-09-12 such values.

Convincing answered 9/4, 2021 at 19:25 Comment(0)
P
0

One-liner solution for checking the correctness of the date using DateTime and > PHP 8.0.

(DateTime::createFromFormat('Y-m-d', $date) ?: null)?->format('Y-m-d') === $date
Pirali answered 27/3, 2023 at 11:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.