tags:

views:

169

answers:

7

I get dates from a text area in the dd-mm-yyyy or dd/mm/yyyy format (the user is allowed to use - or /) How do I check (using a regex or php) if the date is valid? Is there a regex or php method done this far to validate dates in this format? I tried searching here but could not find anything.

A: 

A regular expression alone cannot validate a date because of the different number of days in months - especially for leap years.

/^(\d{1,2})(\/|-)(\d{1,2})\2(\d{2}|\d{4})$/

but above regex solves your problem of allowing - or / based on these format dd-mm-yyyy or dd/mm/yyyy

Here are some examples

//Date d/m/yy and dd/mm/yyyy
//1/1/00 through 31/12/99 and 01/01/1900 through 31/12/2099
//Matches invalid dates such as February 31st
'\b(0?[1-9]|[12][0-9]|3[01])[- /.](0?[1-9]|1[012])[- /.](19|20)?[0-9]{2}\b'

//Date dd/mm/yyyy
//01/01/1900 through 31/12/2099
//Matches invalid dates such as February 31st
'(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)[0-9]{2}'

//Date m/d/y and mm/dd/yyyy
//1/1/99 through 12/31/99 and 01/01/1900 through 12/31/2099
//Matches invalid dates such as February 31st
//Accepts dashes, spaces, forward slashes and dots as date separators
'\b(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}\b'

//Date mm/dd/yyyy
//01/01/1900 through 12/31/2099
//Matches invalid dates such as February 31st
'(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)[0-9]{2}'

//Date yy-m-d or yyyy-mm-dd
//00-1-1 through 99-12-31 and 1900-01-01 through 2099-12-31
//Matches invalid dates such as February 31st
'\b(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])\b'

//Date yyyy-mm-dd
//1900-01-01 through 2099-12-31
//Matches invalid dates such as February 31st
'(19|20)[0-9]{2}[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])'
JapanPro
This would also allow `5/2/02`, i.e. it does not meet the requirements. At least you should mention it.
Felix Kling
This doesn't check if the date is *valid*.
Dan Beam
A: 

A very simplistic way would be to have a regular expression that checks for one of the formats, then make sure the input is converted to that first by replacing any characters:

$regexDate = '#\d\d\-\d\d\-\d\d\d\d#' ;

$dateIn = trim($_GET['date']) ;

//replace all / with - since our regex expects those
$dateIn = str_replace('/', '-', $dateIn) ;

if (preg_match($regexDate, $dateIn)) {
    //valid date input
}
Fanis
This doesn't check if the date is *valid*.
Dan Beam
@Dan, hence "simplistic". You can pair it up with checking if the date elements are within ranges later but you have to start somewhere
Fanis
A: 

Hi, I'd use strftime and strptime. At first I'd convert string into "time" than back to string and compare it...

msurovcak
+1  A: 

I highly recommend using the PHP methodstrtotime(), as it will not only check to see if the format is valid, but if the time specified by the format is correct as well (i.e. there will never be a February 31st, but a regex might not catch this).

You can check to see if this is valid with if (strtotime($toCheck)) { as it'll return FALSE if it doesn't succeed (http://us2.php.net/strtotime).

EDIT: You'll need to switch the order before you can check if the date is valid with strtotime first like this:

$str = "07-31-1987";
$str = preg_replace('/([^-\/]+)[-\/]([^-\/]+)[-\/]([^-\/]+)/', '$2-$1-$3', $str);
echo date('r', strtotime($str)) . "\n"; // Fri, 31 Jul 1987 00:00:00 -0700
Dan Beam
`strtotime()` doesn't handle dd/MM/YYY
Colin Hebert
`echo date('r', strtotime('07/31/2010'))); // Sat, 31 Jul 2010 00:00:00 -0700`
Dan Beam
no dd/MM but MM/dd :)
Colin Hebert
true dat - self-trolled
Dan Beam
You would need to convert the date string into mm/dd/yyyy or mm-dd-yyyy before calling strtotime().
w3d
+1 for strtotime but make sure to either set it in stone to your users to use US date format, or try to do it for them as a fallback
Fanis
@w3d - just did, but I think better overall approach it to split `<input>`s into day, month, year (so you'll have better control...)
Dan Beam
-1 This answer is all wrong. (1) `strtotime()` doesn't support `mm-dd-YYYY`, only `mm/dd/YYYY` (2) `strtotime()` doesn't validate the date. `strtotime('Feb 31st 2010')` for example does not return false. Cups' answer is the right one. And wow, is that an ugly regex or what? Ironic that you donwvoted everyone, isn't it?
NullUserException
+8  A: 
$date = str_replace("/", "-", $incoming);
$d = explode("-"  , $date);

Re-assemble the parts and then run it through checkdate

if( !checkdate($d[1], $d[0], $d[2]) )
echo 'Not a recognised date' ;

http://www.php.net/manual/en/function.checkdate.php

Cups
+1 This is the right way to validate a date, not `strtotime()`
NullUserException
`$incoming = '3-2-1-*pop*';`
salathe
I did not know there was a checkdate function... Life is now easier.
Justin Johnson
`$incoming = '27/09-2010';`
zerkms
+1  A: 

I came up with this little function, it checks you use the format

DD(separator)MM(same separator)YYYY

With DD, MM and YYYY as integers.

function valid_date($input_date) {
    if(!preg_match('/(?P<d>\d{2})(?P<sep>\D)(?P<m>\d{2})\2(?P<y>\d{4})/',$input_date, $aux_date)) 
        return false; 
    else {
        $aux = mktime(0,0,0,$aux_date['m'],$aux_date['d'],$aux_date['y']);
        return $input_date == date('d'.$aux_date['sep'].'m'.$aux_date['sep'].'Y',$aux));
    }
}

(Edited as sugested below)

Adriana Villafañe
Why not just `return $input_date == date('d'.$aux_date['sep'].'m'.$aux_date['sep'].'Y',$aux)`. You have 3 lines of uselessness otherwise. +1 for the regex though: I didn't know you can name your groups.
Justin Johnson
You're absolutely right. Thanks.
Adriana Villafañe
A: 

You could use the datetime class, passing the date you want to validate to the constructor. If you have a valid date you'll get back a datetime object. If it's an invalid date the constructor will throw an exception, which you can catch and the handle the error accordingly.

Jeremy