Sample output
Made on 27 October 2026
Pattern
^(?:\d{4})-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$
Piece-by-piece explanation
^— Start of the string.\d{4}— Exactly four digits for the year.-— Literal hyphen.(?:0[1-9]|1[0-2])— Month from01through12.0[1-9]matches01–09.1[0-2]matches10–12.
-— Literal hyphen.(?:0[1-9]|[12]\d|3[01])— Day from01through31.0[1-9]matches01–09.[12]\dmatches10–29.3[01]matches30–31.
$— End of the string.
Matching examples
2026-07-02
1999-12-31
2000-01-01
0001-09-09
9999-11-30
Non-matching examples
2026-7-02 # Month is not two digits
2026-07-2 # Day is not two digits
26-07-02 # Year is not four digits
2026-13-01 # Invalid month
2026/07/02 # Wrong separator
Common pitfalls
- This regex validates the format and basic month/day ranges, but not actual calendar validity. For example, it matches:
2026-02-312025-04-312025-02-29
- Use a date parser or additional validation if leap years and month-specific day limits matter.
\dmay match Unicode digits in some regex engines. To require ASCII digits only, use:
^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$
- Multiline mode can change the behavior of
^and$, allowing matches at line boundaries rather than only at the boundaries of the entire input.
PCRE compatibility
Supported as written:
\A[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])\z
\A and \z provide strict whole-string anchoring in PCRE.
JavaScript compatibility
Supported as written:
const pattern = /^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$/;
Avoid the m flag if the entire input must be one date.
Python compatibility
Supported with re.fullmatch, which is preferable for whole-string validation:
import re
pattern = re.compile(
r"[0-9]{4}-