1

I want to validate a time input (like 10:30 am, 02:30 pm) using preg_match()

I use this,

 $pattern   =   "/([1-12]):([0-5])([0-9])( )(am|pm|AM|PM)/";
 if(preg_match($pattern,$time)){
   return true;
 }

But when i give an input like 10:30 pmxxxx it will not validated. I dont know whether the method is correct or not. Help please.

raina77ow
  • 103,633
  • 15
  • 192
  • 229
Sherin Jose
  • 2,508
  • 3
  • 18
  • 39

3 Answers3

7

DATETIME SOLUTION

You can validate all your date/time strings with DateTime::createFromFormat:

Function

function isTimeValid($time) {
    return is_object(DateTime::createFromFormat('h:i a', $time));
}

Example

foreach (['12:30 am', '13:30 am', '00:00 pm', '00:00 am', '12:30am', '15:50pm'] as $time) {
    echo "Time '$time' is " . (isTimeValid($time) ? "" : "not ") . "valid.\n";
}

Example output

Time '12:30 am' is valid.
Time '13:30 am' is not valid.
Time '00:00 pm' is valid.
Time '00:00 am' is valid.
Time '12:30am' is valid.
Time '15:50pm' is not valid.
Glavić
  • 42,781
  • 13
  • 77
  • 107
  • I had tried `function isDateValid($date) { return is_object(DateTime::createFromFormat("Y/m/d",$date)); }` for validate a date format, is it correct – Sherin Jose Oct 08 '12 at 10:57
  • Like I said in the answer, you can use this for any kind of date/time validation... – Glavić Oct 08 '12 at 11:25
  • But it returns true when i give 2012/19/21...19 is not a valid month..:-( – Sherin Jose Oct 08 '12 at 11:29
  • I meant that you can use DateTime::createFromFormat for any date/time validators, but i didn't say the function will look like this... – Glavić Oct 08 '12 at 11:30
  • You can use my validateDate function > http://stackoverflow.com/questions/12322824/php-preg-match-with-working-regex/12323025#12323025 – Glavić Oct 08 '12 at 11:51
2

The [...] notation in regexes defines character class: something that's applied to the single character. It's alternation that should be used here instead:

0[1-9]|1[0-2]

... so the regex in whole would look like this:

/^(?:0[1-9]|1[0-2]):[0-5][0-9] (am|pm|AM|PM)$/
raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • Actually when i give 10:30 pm or 10:30 pmxxxxx, the function returns true....But i need the function to be true only for 10:30 pm – Sherin Jose Oct 06 '12 at 11:26
  • Then please be more specific in your question. You described what you want to be matched, but didn't say anything about what shouldn't match; the art of regex is finding balance between those - and other criterias, like readability and performance. – raina77ow Oct 06 '12 at 11:28
  • @raina77ow: what does `?:` mean? – Glavić Oct 06 '12 at 11:56
  • It means that the pattern in parentheses is not caught as a subpattern. The parentheses are used only for the alternative. – Michal Trojanowski Oct 06 '12 at 12:05
  • @MichalTrojanowski: Thanks for the explanation. So in this example (validation) `?:` has no meaning? – Glavić Oct 06 '12 at 12:18
  • How to allow 5:30 PM instead of 05:30 PM? Is (?:[1-9]|1[0-2]):[0-5][0-9] (AM|PM) ok? – RN Kushwaha Oct 08 '15 at 10:39
1

REGEX SOLUTION

  • [1-12] will not work, because this is not range definition, but [ and ] means start and end character class definition.
  • use /i pattern modifier at end, so you don't need to write PM, pm, pM, Pm, AM, am, aM, Am combinations.
  • PM and AM fetch can bi simpleffied with [ap]m.
  • if you wish to validate whole string, then the string must be valid from the start to end with ^ and $.
  • I added \h escape sequence (horizontal whitespace char) between time and pm|am, so time like 10:10am can be valid to.

Code:

$time = '10:30 am';
$pattern = '~^(0[0-9]|1[0-2]):([0-5][0-9])\h*([ap]m)$~i';
if (preg_match($pattern, $time, $m)) {
    print_r($m);
    return true;
}

Output

Array
(
    [0] => 10:30 am
    [1] => 10
    [2] => 30
    [3] => am
)
Community
  • 1
  • 1
Glavić
  • 42,781
  • 13
  • 77
  • 107
  • I had tried `function isDateValid($date) { return is_object(DateTime::createFromFormat("Y/m/d",$date)); }` for validate a date format, is it correct – Sherin Jose Oct 08 '12 at 10:56