I'm trying to use preg_match to validate that a time input is in this format - "HH:MM"
I'm trying to use preg_match to validate that a time input is in this format - "HH:MM"
Function that validates hours, minutes and seconds, according to the desired format:
function validTime($time, $format='H:i:s') {
$d = DateTime::createFromFormat("Y-m-d $format", "2017-12-01 $time");
return $d && $d->format($format) == $time;
}
$valid = validTime("23","H");
$valid = validTime("23:59","H:i");
$valid = validTime("23:59:59","H:i:s");
$valid = validTime("23:59:59");
$valid = validTime("25","H");
$valid = validTime("01:60","H:i");
$valid = validTime("01:20:61","H:i:s");
$valid = validTime("01:20:61");
Based on the Charles's elegant answer with regular expression. If you need a one line validation of both "HH:MM" and "H:MM" (i.e. "9:45"/"09:45") use the following regexp to match 24-hour format:
preg_match("/^(?(?=\d{2})(?:2[0-3]|[01][0-9])|[0-9]):[0-5][0-9]$/", $time)
(? stands for conditional subpattern, the syntax is:
(?(condition)yes-pattern|no-pattern)
?= in condition is the regexp assertion
?: in yes-pattern is optional for better performance and you may drop it. This means we don't need any capturing within parentheses (), we need just alternatives feature.
So, we merely describe the following:
$time string begins with two digits (?=\d{2}), use (2[0-3]|[01][0-9]) pattern to match HH-hour notation ("09:45" case)[0-9] pattern to match H-hour notation ("9:45" case)As they say, simplicity is the sister of a talent. We don't necessarily need the condition pattern described above. The simpler validation of "HH:MM/H:MM" for 24-hour format:
preg_match("/^(?:2[0-3]|[01][0-9]|[0-9]):[0-5][0-9]$/", $time)
Again, ?: in grouping parentheses () is optional to disable capturing, you can drop it.
So, in this regexp the alternative subpatterns withing () is trying to match two digits hour at the first (20..23) and second (01..19) pattern, then one digit at the last third one (0..9).
In addition, the validation of "HH:MM/H:MM" for 12-hour format:
preg_match("/^(?:0?[1-9]|1[012]):[0-5][0-9]$/", $time);
Here, we're trying to match at first one digit (1..9) with possible preceding zero (0?), and then two digits (10..12).
Another approch without using regex.
if(is_string($foo) && (strlen($foo) == 4 || strlen($foo) == 5) && intval(str_replace(':','',$foo)) > -1 && intval(str_replace(':','',$foo)) < 2360){
stuff to do if valid time
}
else{
stuff to do if invalid time
}
First of all I check if the datatype is string. If not it obvious that it is not a valid time. Then I check if the string has the right lenght of 4 / 5 letters. With str_replace I remove the ':' and then cast the result to an integer which I could easily compare to the desired time range (in my example 00:00 - 23:59).