Update 31-Jul-2010: Check out the updated version for a slightly more concise function.
This is an updated PHP based date validator, correcting some issues with the original version. An additional parameter has been added specifying the expected format of the date, using PHP date expressions.
function bi_IsDate($d, $f='m-H:%M'){
if (empty($d)) return true;
#Convert Unix timestamp to a std format (must not include regular expressions)
if (preg_match('!\d{5,}!',$d))
$d=strftime($f,$d);
$re_day='%d|%e';
$re_month='%m';
$re_year='%g|%G|%y|%Y';
$re_sep='[\/\-\.]';
$re = array(
'/'.$re_day.'/' => '(0?[1-9]|[12][0-9]|3[01])',
'/'.$re_month.'/' => '(0?[1-9]|1[012])',
'/'.$re_year.'/' => '(19\d\d|20\d\d)',
'/%H|%I|%l/' => '([0-1]?\d|2[0-3])',
'/%M/' => '([0-5]\d)'
);
$re_date = preg_replace(
array_keys($re),
array_values($re),
$f); #convert $f into a regular expression
#does %d match the regular expression version of $f?
if (preg_match('!^'.$re_date.'$!',$d,$x)
#determine expected date order based on $f and checkdate
&& ((preg_match(
'!^('.$re_day.')' .$re_sep .'('.$re_month.')' .$re_sep .'('.$re_year.')!',$f)
&& checkdate($x[2], $x[1], $x[3]))
|| (preg_match(
'!^('.$re_month.')' .$re_sep .'('.$re_day.')' .$re_sep .'('.$re_year.')!',$f)
&& checkdate($x[1], $x[2], $x[3]))
|| (preg_match(
'!^('.$re_year.')' .$re_sep .'('.$re_month.')' .$re_sep. '('.$re_day.')!',$f)
&& checkdate($x[3], $x[1], $x[2]))
)) return true;
return false;
}