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.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.
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)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.