24-Hour Time Regex (HH:MM and HH:MM:SS)
Check a time written on the 24-hour clock, two-digit hours from 00 to 23 and minutes from 00 to 59, with seconds as an optional extra.
One case per line; the m flag makes ^ and the end anchor work line by line.
Link optionspattern only
The address bar holds the pattern, flags and replacement, so Copy link shares them. Your test text stays out of it unless you include it (up to 2,000 characters), because it may be private. Nothing is sent to a server.
Matches
6matches
The first is “00:00”, at position 0.
- Groups
- none
- Characters matched
- 36 of 84
What the pattern meansHover or tap a part to see it in the pattern and what it matched
How this works: Method, 4 sources, Checked against 1 worked example,
How this works
Method
Your pattern runs in your own browser’s JavaScript engine, in a background worker that is stopped after 1.5 seconds, so a pattern that backtracks catastrophically can’t freeze the page. The explanation comes from our own parser of the ECMAScript pattern grammar, checked against the engine; what each part matched is found by wrapping that part in one more group and running the pattern again. Conversions to other flavours only rewrite the syntax and list what their documentation says works differently.
Sources
How it’s tested
One worked example for this page is checked by automated tests before every release: given the inputs, the tool must show the expected answer.
Changes
- First published, with a library of 19 common patterns and their test cases.
Worked example
Take 00:00, the first case in the tester. Reading the pattern left to right, each part takes its share of the text:
^The start of the text (matches a position, no characters)(?:[01]\d|2[0-3])A group (not captured), either of two alternatives: matches 00:“:” matches :[0-5]One character: 0–5 matches 0\dA digit (0–9) matches 0(?::[0-5]\d)?A group (not captured), optional (zero or one time): (matches a position, no characters)$The end of the text (matches a position, no characters)
How the 24-hour time regex works
Hours are the tricky part, because the first digit limits the second. \(?:[01]\d|2[0-3])\ splits them into two cases: a 0 or 1 followed by any digit gives 00 to 19, and a 2 followed by 0 to 3 gives 20 to 23. The \(?:…)\ brackets group the two branches without capturing them, so the alternation applies only to the hour and not to the rest of the pattern.
After the colon, \[0-5]\d\ gives minutes from 00 to 59: the tens digit can't go above 5. The seconds use the same piece inside \(?::[0-5]\d)?\, where the question mark makes the whole group, colon included, optional. That is why 23:59 and 23:59:59 both pass while 23:59: (a dangling colon) does not.
To read the parts in code, change the non-capturing groups to named ones, for example \(?<h>[01]\d|2[0-3])\, and the match's groups will hold them. Comparing two times written this way is easy: zero-padded HH:MM strings sort in time order, so "09:30" < "13:45" is true as plain text.
- RFC 3339 limits hours to 00–23 and minutes to 00–59, and lets seconds reach 60 only for a leap second. Source: RFC 3339, section 5.6.
- RFC 3339 notes that leap seconds have so far been inserted only at the end of June or December, written 23:59:60. Source: RFC 3339, section 5.7.
Test cases
Every case runs as an automated test of this page’s pattern, so the table can’t drift from what the pattern really does.
| Text | Result | Why |
|---|---|---|
| 00:00 | Passes | midnight |
| 09:30 | Passes | morning, with its leading zero |
| 13:45 | Passes | quarter to two in the afternoon |
| 23:59 | Passes | the last minute of the day |
| 23:59:59 | Passes | with seconds |
| 07:05:00 | Passes | zero seconds still need two digits |
| 24:00 | Fails | hours stop at 23 here |
| 9:30 | Fails | one-digit hour |
| 12:60 | Fails | minutes stop at 59 |
| 7pm | Fails | a 12-hour time |
| 12:30:5 | Fails | seconds need two digits |
| 1230 | Fails | no colon |
| 23:59:60 | Fails | a leap second: RFC 3339 allows it, this pattern doesn’t |
What it doesn’t check
- It does not accept 12-hour times with AM or PM; convert those first or use a separate pattern.
- Midnight written as 24:00 is rejected; most systems write it as 00:00 of the next day.
- Leap seconds (23:59:60) are allowed by RFC 3339 but fail here, which suits most forms and schedules.
- Fractions of a second and time zones (09:30:00.250Z, 09:30+02:00) are not accepted.
The same pattern in other languages
Converted automatically from the JavaScript version; the tester above always runs JavaScript.
| Flavour | Pattern | Notes |
|---|---|---|
| Python | (?a)^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?\Z | |
| PCRE | ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?\z | |
| Go | ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$ | |
| Java | ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?\z | |
| .NET | ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?\z | In .NET, \d and \w match any Unicode digit or letter. Pass RegexOptions.ECMAScript, or write [0-9] and [A-Za-z0-9_], for JavaScript’s ASCII-only meaning. |
Sources
Frequently Asked Questions
How do I match 12-hour times with AM and PM?
Use hours 1 to 12 instead, for example an optional leading zero then 1 to 9, or 10 to 12, followed by the minutes and a space and AM or PM with the case-insensitive flag. Keep it separate from this 24-hour pattern.
Why does 9:30 fail?
The pattern wants two-digit hours, as 24-hour times are normally written. To accept a single digit too, make the first hour digit optional for 0 to 9, but then 09:30 and 9:30 both pass and you should pad before storing.
Is 24:00 a valid time?
Some standards have used 24:00 to mean the end of a day, but software almost always writes it as 00:00 of the next day. This pattern follows that and stops at 23:59.