Quick answer
The regex for 24-hour time is ^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$. The hour is 00 to 19 or 20 to 23, the minutes are 00 to 59, and an optional :ss adds seconds, so 09:30, 23:59 and 13:45:30 match while 24:00, 9:30 and 12:60 do not. It is the format used by <input type="time"> and ISO 8601.
- Tested examples
- Token-by-token breakdown
- Code in 5 languages
- Live tester
How to use the time (24-hour) regex
- 1Copy the pattern with Copy pattern in the tester, or take a ready-made snippet for your language from the code section below.
- 2Check the sample lines in Test string: every line the time (24-hour) regex accepts is highlighted, rejected lines stay plain.
- 3Paste your own values one per line to see which pass, and read Explanation for what each part of the pattern does.
- 4Open the Code tab for JavaScript, Python, Go, C#, PHP or Dart with the pattern translated and escaped.
- 5Validate again on the server: client-side checks give users quick feedback, not security.
How does the time (24-hour) regex work?
Read it left to right. Each piece below matches one part of the input:
^Start of the string.(?:[01]\d|2[0-3])The hour: 00–19, or 20–23. Two digits are required.:A colon.[0-5]\dMinutes from 00 to 59.(?::[0-5]\d)?Optionally a colon and seconds from 00 to 59.$End of the string: no AM/PM suffix.
Which strings does the time (24-hour) regex match?
The whole input must match, from the first character to the last. Every row below is checked against the pattern by our automated test suite before each release.
| Input | Matches? | Why |
|---|---|---|
00:00 | Yes | Midnight. |
09:30 | Yes | A leading zero for morning hours. |
23:59 | Yes | The last minute of the day. |
13:45:30 | Yes | With seconds. |
18:00:00 | Yes | Seconds of zero are written out. |
24:00 | No | ISO 8601 allows 24:00 for the end of a day, but RFC 3339 and HTML time inputs do not. |
9:30 | No | The hour needs two digits (see the variant below). |
12:60 | No | Minutes stop at 59. |
12:30:60 | No | Leap seconds are not accepted. |
12:30 PM | No | 12-hour clock with a suffix. |
1230 | No | The colon is required. |
How do I accept single-digit hours or a 12-hour clock?
Three common variations:
- 24-hour, hour may be one digit (9:30):
^(?:[01]?\d|2[0-3]):[0-5]\d$ - 12-hour with AM/PM (9:30 pm):
^(?:0?[1-9]|1[0-2]):[0-5]\d\s?[AaPp][Mm]$ - With milliseconds (13:45:30.250):
^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d\.\d{3}$
Note the 12-hour clock runs from 1 to 12, so 0?[1-9]|1[0-2] replaces the 24-hour alternatives. Normalize to 24-hour time before storing; it avoids the "is 12:00 AM midnight or noon?" question entirely.
Does a valid time string mean a valid moment?
Not on its own. A time without a date and a time zone is a wall-clock reading, and some readings do not exist or happen twice: when clocks spring forward for daylight saving time, 02:30 does not occur in many zones, and in autumn 01:30 happens twice. If you combine a date, a time and a zone, use a time-zone-aware library (Temporal in modern JavaScript, zoneinfo in Python, time.LoadLocation in Go) to resolve it.
For schedules that repeat, such as "every weekday at 09:30", a cron expression is the better format: build one with the cron expression generator.
How do I use the time (24-hour) regex in JavaScript, Python, Go, C# and PHP?
The pattern is translated for each engine rather than pasted as is: named groups, anchors, escapes, shorthand classes and flags are adjusted so each snippet behaves as closely to the JavaScript version as its engine allows. Differences that remain (Go's RE2 has no lookarounds or backreferences, for example) are called out under each one. The Code tab in the tester above also exports Dart, and updates as you edit the pattern.
JavaScript and TypeScript
const regex = /^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/;
function isValid(value) {
return regex.test(value);
}
console.log(isValid("00:00"));Python
import re
pattern = re.compile(r"^(?:[01][0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?\Z")
def is_valid(value: str) -> bool:
return pattern.search(value) is not None
print(is_valid("00:00"))- \d and \w are written as [0-9] and [A-Za-z0-9_] because in Python they also match digits and letters from other scripts.
- JavaScript's $ only matches at the very end of the string. Python's $ also matches before a trailing newline, so the pattern uses \Z instead.
Go
package main
import (
"fmt"
"regexp"
)
func main() {
re := regexp.MustCompile(`^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$`)
fmt.Println(re.MatchString("00:00"))
}C#
using System;
using System.Text.RegularExpressions;
// The timeout stops a pathological input from hanging the thread (ReDoS).
var regex = new Regex(@"^(?:[01][0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?\z", RegexOptions.None, TimeSpan.FromSeconds(1));
Console.WriteLine(regex.IsMatch("00:00"));- \d and \w are written as [0-9] and [A-Za-z0-9_] because in .NET they also match digits and letters from other scripts.
- JavaScript's $ only matches at the very end of the string. .NET's $ also matches before a trailing newline, so the pattern uses \z instead.
PHP
<?php
$pattern = '/^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/D';
function isValid(string $value, string $pattern): bool
{
return preg_match($pattern, $value) === 1;
}
var_dump(isValid('00:00', $pattern));- The D modifier makes $ match only at the very end, like JavaScript (PCRE's $ also matches before a trailing newline).
Which related regex patterns are useful?
- Regex for Dates in yyyy-mm-dd Format: ISO 8601 calendar dates: four-digit year, month 01–12, day 01–31.
- Regex for Numbers Only: Digits only, plus variants for signs, decimals and thousands separators.
- Regex for Semantic Versioning (SemVer): major.minor.patch with optional prerelease and build metadata, per semver.org.
- Regex for Hex Color Codes: CSS hex colors in 3, 4, 6 or 8 digits with a leading hash.
Browse all 25 patterns in the regex pattern library, or build your own in the regex tester.
Frequently asked questions
Last updated by the Playxoft engineering team.