ISO Date Regular Expression – Free, Online, Private
Matches a YYYY-MM-DD date with a real month and a day from 01 to 31.
- 2026-10-17
The pattern
The pattern requires a four-digit year, a hyphen, a month from 01 to 12, a hyphen, and a day from 01 to 31. 2026-10-17 matches. 2026-13-01 does not, because 13 is not a month. 2026-1-7 does not, because the month and the day must be two digits. The pattern does not know how many days a month has. 2026-02-31 matches and is not a date. Check the calendar after the match if that matters.
The source is \d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01]). No flags are set. The match is case-sensitive, and ^ or $ mean the start and end of the whole input. Add m yourself in the tester if you paste several lines. The box under the title is a tester with this pattern and the sample already filled in. Edit either one. Nothing you type is uploaded. The same tester, without a preset, is the regex tool.
How to read it
\d{4} is the year. It allows 0000 and 9999. The month alternation is 0[1-9] for January through September and 1[0-2] for October through December. The day alternation is 0[1-9], then [12]\d for 10 through 29, then 3[01] for 30 and 31. Hyphens are literal. There is no time and no zone. A longer timestamp still matches the date at the start of the token unless you anchor the pattern or stop at a boundary.
What it will not do
Leap days are not checked. 2025-02-29 matches here and is not a real day. So does 2026-04-31. The expression is a shape check. A Date parser is the calendar check. Years are not limited to the 2000s. The pattern does not accept a slash or a dot as the separator. It does not accept a month name. If the source is a spreadsheet that writes 2026/10/17, change the separator in a copy of the pattern and test it in the box before you trust it.
A match is not a parsed value. An email pattern does not send mail, a UUID pattern does not allocate an id, and a password pattern does not store a password. When the next step needs a real parser, use one: the URL constructor, a date library, a semver library, or the converters on this site. The expression is the part you can see.
JavaScript, Python, and Go
The JavaScript snippet uses the RegExp constructor so the source does not have to be escaped for a literal slash. The Python snippet uses a normal string with the same escapes JSON would emit, which keeps \d as a regex digit class. Go's snippet uses a raw string. If the pattern contains a lookahead, the Go snippet says so and does not call MustCompile, because RE2 would reject it at runtime.
JavaScriptconst re = new RegExp("\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])", "");
const found = text.match(re);
console.log(found ? found[0] : "no match");
Pythonimport re
pattern = re.compile("\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])")
found = pattern.search(text)
print(found.group(0) if found else "no match")
Gopackage main
import (
"fmt"
"regexp"
)
func main() {
text := ""
re := regexp.MustCompile(`\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])`)
fmt.Println(re.FindString(text))
}
Frequently asked questions
Does 2026-02-31 match?
Yes. The pattern allows day 31 in every month. Validate the calendar separately.
Does 2026-1-7 match?
No. Month and day have to be two digits, so the form is 2026-01-07.
Are two-digit years accepted?
No. The year is exactly four digits.
Does a full timestamp match?
The date portion can match inside a timestamp. Anchor the pattern if the field must be a date and nothing more.