Regex patterns/Dates & times

ISO date (YYYY-MM-DD)

Month and day ranges enforced by alternation, not by \d{2}.

/^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/
Open it in Rex

The problem

Check that a string is a calendar date in YYYY-MM-DD form.

How it reads

start\drepeat-group0[1-9]1[0-2]-group0[1-9][12]\d3[01]end

Follow the line from left to right — every path you can trace is a string this pattern matches.

  1. ^\d{4}-(?:0[1-9]|1[0-…In order:
  2. ^The start of the text (or of a line with the m flag)
  3. \d{4}A digit, exactly 4 times, as many as possible
  4. -The character "-"
  5. (?:0[1-9]|1[0-2])Group (not captured):
  6. 0[1-9]|1[0-2]Any one of these alternatives:
  7. 0[1-9]In order:
  8. 0The character "0"
  9. [1-9]Any one of: "1" to "9"
  10. 1[0-2]In order:
  11. 1The character "1"
  12. [0-2]Any one of: "0" to "2"
  13. -The character "-"
  14. (?:0[1-9]|[12]\d|3[01…Group (not captured):
  15. 0[1-9]|[12]\d|3[01]Any one of these alternatives:
  16. 0[1-9]In order:
  17. 0The character "0"
  18. [1-9]Any one of: "1" to "9"
  19. [12]\dIn order:
  20. [12]Any one of: "1" or "2"
  21. \dA digit
  22. 3[01]In order:
  23. 3The character "3"
  24. [01]Any one of: "0" or "1"
  25. $The end of the text (or of a line with the m flag)

Matches

  • 2024-06-01
  • 1999-12-31
  • 2024-02-30

Does not match

  • 2024-13-01
  • 24-06-01
  • 2024-6-1
  • 2024/06/01

Where it bites

  • 2024-02-30 passes. A regex counts characters; it cannot know February is short or which years are leap years. Validate the range here and the real date with Date.
  • The ranges are spelled out as alternatives because \d{2} would accept month 99.
  • It is anchored, so it validates a whole string. Drop the anchors to find dates inside a log line.

More dates & times patterns