Regex for dates

The patterns for finding dates in text, with capture groups ready to use. Principle up front: regex finds the shape; your date library validates the calendar. A regex that "knows" February has 28 days is a regex nobody can read.

🎙️ Published & recorded: ·

ISO and slashed date shapes

Prefer year, month, day when you control the format. It sorts correctly and avoids regional arguments. Capture the three parts when your code needs them separately. Slashed dates are inherently ambiguous: the same value means different days in Boston and London, so the data contract must decide the order.

\b\d{4}-\d{2}-\d{2}\b

# with capture groups — year, month, day come back separately:
(\d{4})-(\d{2})-(\d{2})

# Python
m = re.search(r"(\d{4})-(\d{2})-(\d{2})", text)
year, month, day = m.groups()      # ("2026", "07", "22")
\b\d{1,2}/\d{1,2}/\d{4}\b          # both DD/MM and MM/DD shapes

# the regex CANNOT tell you which one it is. 04/07/2026 is
# July 4th in Boston and April 7th in London. only context
# (or the data's spec) knows. no pattern fixes ambiguity.
Real failure symptom
If imported birthdays are exactly one month off for days 1 through 12, the regex is not the fix. The source and parser disagree about day-first versus month-first. Record the source format explicitly and parse with that declared format.

Logs, timestamps, and month names

Regex earns its keep when dates are embedded in messy text. In logs, capture the date and time as separate pieces, or anchor a search to the beginning of each line. Month names need an explicit list so ordinary words do not become accidental dates.

# classic log line:  2026-07-22 14:30:07,123 ERROR ...
(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})

# grep all of yesterday's errors from a log:
grep -E "^2026-07-21 .*ERROR" app.log

# time on its own (24h):
\b([01]?\d|2[0-3]):[0-5]\d\b        # 9:05, 14:30 — rejects 25:99
\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]* \d{1,2},? \d{4}\b

# matches "Jul 22, 2026", "July 22 2026", "Dec 3, 1999"

Let a date parser validate the calendar

A shape match can still describe an impossible day. Do not teach a regex leap years and month lengths. Find candidate strings first, then ask the date library to parse each one. Its actual parse error is useful evidence; catch that error only when skipping bad candidates is the intended behavior.

Where the regex should stop
A two-digit month accepts 13 through 99. You can restrict that range and still accept February 30. The honest split is: regex finds candidates, the date parser validates them. In Python, datetime.strptime raises ValueError: day is out of range for month; fix the source date or reject that candidate rather than growing the regex.
# the find-then-parse pattern (Python):
for m in re.finditer(r"\b\d{4}-\d{2}-\d{2}\b", text):
    try:
        d = datetime.strptime(m.group(), "%Y-%m-%d")
    except ValueError:
        continue            # shaped like a date, isn't one (2026-13-45)
Honest take
If you are parsing known structured data, such as an API field or a specified CSV column, skip regex and call the date parser with the declared format. Regex belongs where dates hide inside logs, emails, and scraped pages.
📚 One page of our regex series. The five concepts, the greedy trap, and when to decline regex entirely — with audio: Regex in 10 Minutes →

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.