breakitdown

Regex for a YYYY-MM-DD date

Answer

^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$ checks the shape of an ISO 8601 date: four-digit year, month 01-12, day 01-31. It cannot know that February has 28 or 29 days, so 2023-02-30 passes. Parse the date to check that.

flags: g all matches · i ignore case · m ^ $ per line · s . matches newlines · u Unicode

JavaScript ✓PCRE ✓

No catastrophic-backtracking patterns found. (A heuristic check: nested and adjacent repeats, overlapping alternatives.)

  1. ^Start of the stringanchor
  2. \dA digit (0-9)character type
  3. {4}Repeat it exactly 4 timesquantifier
  4. -The character '-' literallyliteral
  5. (?:…)Non-capturing group: groups without rememberinggroup
  6. |Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation
  7. Alternative 1:
  8. 0The character '0' literallyliteral
  9. [1-9]One character: '1' to '9'character class
  10. Alternative 2:
  11. 1The character '1' literallyliteral
  12. [0-2]One character: '0' to '2'character class
  13. -The character '-' literallyliteral
  14. (?:…)Non-capturing group: groups without rememberinggroup
  15. |Either of 3 alternatives, tried left to right; the first that leads to an overall match winsalternation
  16. Alternative 1:
  17. 0The character '0' literallyliteral
  18. [1-9]One character: '1' to '9'character class
  19. Alternative 2:
  20. [12]One character: '1' or '2'character class
  21. \dA digit (0-9)character type
  22. Alternative 3:
  23. 3The character '3' literallyliteral
  24. [01]One character: '0' or '1'character class
  25. $End of the stringanchor

Examples

Checked at build time in JavaScript and in Python's re.

InputMatches?
2024-02-29✓ match
1999-12-31✓ match
2024-13-01✗ no match
2024-00-10✗ no match
2024-1-5✗ no match
2024-04-31✓ match
2023-02-30✓ match
24-01-05✗ no match
2024/01/05✗ no match
2024-01-05T10:00:00Z✗ no match

Try your own text

One string per line: each line is tested on its own (the m flag is added here).

How it works

Month is 0[1-9]|1[0-2] and day is 0[1-9]|[12]\d|3[01]. Both require two digits, which is what ISO 8601 and RFC 3339 specify. That rules out 2024-1-5.

Day validity depends on the month and, for February, on the leap-year rule (divisible by 4, except centuries not divisible by 400). You can encode that in a regex, but the result is unreadable. Use the regex to check the format, then parse. Watch out in JavaScript: new Date("2023-02-30") does not fail. V8 rolls it over to March 2. Compare the parsed parts back to the input, or use Python's date.fromisoformat, which raises ValueError on day 30 of February.

Variants

Gotchas

Related explainers

← Explain any regular expression