Regex for 12-Hour Time with AM/PM (hh:mm AM/PM)

Time can be expressed in both 24-hour or 12-hour format. In this article, we will look specifically at matching 12-hour time formats that also specify AM or PM to denote before or after midday, respectively.

A regular expression for AM/PM time format must match an hour format from 00 to 12, followed by a colon, then a minute format from 00 to 59, and finally the text “am” or “pm” in both upper and lower case.

Here’s an expression that can do all this:

/^(0?[1-9]|1[0-2]):([0-5]\d)\s?((?:A|P)\.?M\.?)$/iEdit with Regexity

So let’s break this down and see how it works.

General Format of hh:mm AM/PM Time

After looking through this article on Wikipedia, it is clear that the 12-hour clock must have the following format:

  • Hour expression ranging from 01 to 12, including single digits like 2 and 9. The zero hour expression (or 00) is not used in a 12-hour clock.
  • Followed by a colon.
  • Followed by a minute expression from 00 to 59. This expression must have two digits with leading zeros where necessary (e.g. 3 is not allowed by 03 is).
  • Followed by an optional space.
  • Followed by the text “AM” or “PM” in both upper and lower case. Sometimes the letters are followed by periods (for example A.M. or P.M.).

Regular Expression for hh:mm AM/PM time

Let’s start by writing regex to match the hour expression. For the hours 01 through 09, we can use the following expression:

/0[1-9]/Edit with Regexity

The [1-9]Edit with Regexity in square brackets indicate that we’ll accept any character in the range 1 to 9.

To match single-digit hours as well (like 1 and 9), we can add a zero-or-more quantifier ?Edit with Regexity behind the zero to make it optional:

/0?[1-9]/Edit with Regexity

For the hours 10 through 12, we can add the following regex to our expression, separated by an OR character |Edit with Regexity from the first part, to indicate that we’ll accept either the first or second part:

/0?[1-9]|1[0-2]/Edit with Regexity

The additional part will match a 1 followed by either 0, 1, or 2 as denoted by the [0-2]Edit with Regexity in square brackets.

Our expression thus far will match the hour correctly. We can enclose this part of the expression in parentheses as a capture group to be able to extract and use it later on.

/(0?[1-9]|1[0-2])/Edit with Regexity

Next, we add a colon behind the hour capture group and start working on the minute expression. The minute expression can be any two-digit number from 00 to 59. Thus we add the following:

/(0?[1-9]|1[0-2]):[0-5]\d/Edit with Regexity

The [0-5]Edit with Regexity will match any digit from 0 to 5 as the first minute digit, while the digit symbol \dEdit with Regexity will match any digit from 0 to 9 as the second minute digit.

To ensure that we can extract and use the minutes as well later on, we’ll enclose it in parentheses as well to indicate a second capture group:

/(0?[1-9]|1[0-2]):([0-5]\d)/Edit with Regexity

Next, we add a space behind our expression, denoted by the space character \sEdit with Regexity and follow it with a zero-or-more quantifier (expressed as ?Edit with Regexity) to indicate that it is optional:

/(0?[1-9]|1[0-2]):([0-5]\d)\s?/Edit with Regexity

And now we can focus on matching AM or PM. One way to do this would be to simply list all the possible variations of AM/PM, enclosed in parentheses as a capture group to group them together, and separated by an OR symbol to indicate that we’ll accept any of them:

/(0?[1-9]|1[0-2]):([0-5]\d)\s?(AM|A\.M\.|am|a\.m\.|PM|P\.M\.|pm|p\.m\.)/Edit with Regexity

Take note that all periods that form part of a.m. or p.m. are escaped using a backslash character (e.g. \.Edit with Regexity) to distinguish them from the dot character .Edit with Regexity that matches any character.

A more succinct way would be to specify character ranges in square brackets:

/(0?[1-9]|1[0-2]):([0-5]\d)\s?(([Aa]|[Pp])\.?[Mm]\.?)/Edit with Regexity

The square brackets contain both cases to indicate that we’ll accept any of the character cases. [Aa]Edit with Regexity and [Pp]Edit with Regexity is enclosed in a separate set of parentheses to group them, and separated by an OR character |Edit with Regexity to indicate that we can match either of them before [Mm]Edit with Regexity.

Also included is an optional period after the A or P, as well as after the M. Both periods are escaped by placing a backslash (e.g. \.Edit with Regexity) in front of each one to distinguish them from the dot character .Edit with Regexity which matches any character. They are also followed by a zero-or-more quantifier (written as ?Edit with Regexity) to indicate that they are optional.

Note, however, that the set of parentheses that group [Aa]Edit with Regexity and [Pp]Edit with Regexity is now also a capture group that will return either A or P. Since we have already enclosed the entire AM/PM expression in a capture group, we don’t need to return the A or P on their own as well. We can convert the capture group to a non-capture group by placing ?:Edit with Regexity at the start of the set of parentheses:

/(0?[1-9]|1[0-2]):([0-5]\d)\s?((?:[Aa]|[Pp])\.?[Mm]\.?)/Edit with Regexity

Finally, to ensure that we match only the time expression with nothing before or after it, we need to include the start-of-string ^Edit with Regexity and end-of-string $Edit with Regexity characters at the start and end of the string, respectively:

/^(0?[1-9]|1[0-2]):([0-5]\d)\s?((?:[Aa]|[Pp])\.?[Mm]\.?)$/Edit with Regexity

Which Flags to Use

Since AM and PM can be expected in both upper and lowercase, it makes sense to use the case insensitive flag iEdit with Regexity, which will match any case of these expressions. This will allow us to shorten our regular expression by only including one case:

/^(0?[1-9]|1[0-2]):([0-5]\d)\s?((?:A|P)\.?M\.?)$/iEdit with Regexity

If you’d like to match all instances of AM/PM time in a body of text, instead of simply validating the given input, you might want to use the global flag gEdit with Regexity. In this case, you will also need to remove the start-of-string and end-of-string characters:

/(0?[1-9]|1[0-2]):([0-5]\d)\s?((?:A|P)\.?M\.?)/giEdit with Regexity

Sources

The regular expressions on this page were adapted from solutions on Stack Overflow presented by Eason on this question. In addition, this article provided valuable insights into the correct formatting of AM/PM time.

Benjamin

Founder, owner, and sole content creator on RegexLand. Enjoys programming, blogging, and teaching others how to do the same. Read more...

1 thought on “Regex for 12-Hour Time with AM/PM (hh:mm AM/PM)”

Leave a Comment