Regex for Dates
ISO, US, EU and Custom Formats
Patterns that actually work, the February-30 problem regex cannot solve, and how to extract dates from unstructured text.
Regex for dates is one of those tasks that looks simple until you encounter February 30th, two-digit years, or a log file that mixes three formats on the same line. This guide gives you working patterns for the most common date formats, explains what regex cannot validate, and shows how to extract dates from free text in JavaScript and Python.
ISO 8601: YYYY-MM-DD
ISO 8601 is the only date format that sorts correctly as a string and is unambiguous internationally. Match it with:
# Basic — accepts any digit in range
\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])
# Anchored for full-string validation
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
# With optional time and timezone (full ISO 8601)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$
2026-05-02
2026-12-31
2026-01-01
2026-13-01
2026-00-15
2026-05-32
2026-02-30
26-05-02
US Format: MM/DD/YYYY
The US format uses slashes and puts the month first. The pattern below accepts slashes, hyphens, or dots as separators and handles one- or two-digit months and days:
# MM/DD/YYYY — slash, hyphen, or dot separator
(0?[1-9]|1[0-2])[/.-](0?[1-9]|[12]\d|3[01])[/.-]\d{4}
# Anchored, slash only, strict two-digit padding
^(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{4}$
[/.-], your pattern will match 01/15-2026 — a mix of separators. Use a backreference to enforce consistency: (0?[1-9]|1[0-2])([/.-])(0?[1-9]|[12]\d|3[01])\2\d{4} — the \2 back-references whatever separator the first group captured.EU Format: DD/MM/YYYY
The EU format puts the day first. The regex structure is the same as US with month and day swapped:
# DD/MM/YYYY
(0?[1-9]|[12]\d|3[01])[/.-](0?[1-9]|1[0-2])[/.-]\d{4}
01/02/2026 is January 2nd in the US and February 1st in Europe. Both patterns match it. The only solution is to know your data source and apply the correct pattern — or use ISO 8601 everywhere.What Regex Cannot Validate: The February 30 Problem
Regex can enforce that months are 01–12 and days are 01–31, but it cannot check whether a specific day is valid for a specific month. February 30th, April 31st, and June 31st all pass a regex check.
// JavaScript: regex match, then parse to catch invalid calendar dates
function isValidDate(str) {
const pattern = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
if (!pattern.test(str)) return false;
// regex passed — now check the calendar
const d = new Date(str);
return d instanceof Date && !isNaN(d) && d.toISOString().startsWith(str);
}
isValidDate('2026-02-30'); // false — regex passes, Date rejects
isValidDate('2026-05-02'); // true
import re
from datetime import date
def is_valid_iso_date(s: str) -> bool:
if not re.fullmatch(r'\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])', s):
return False
try:
date.fromisoformat(s)
return True
except ValueError:
return False
is_valid_iso_date('2026-02-30') # False
is_valid_iso_date('2026-05-02') # True
Extracting Dates from Free Text
When you need to pull dates out of a paragraph, log line, or document — rather than validate a single field — remove the anchors and use findall / matchAll:
import re
text = """
Order placed on 2026-01-15. Shipped 2026-01-18.
Expected delivery: 2026-01-22. Invoice date: 2026-01-15.
"""
dates = re.findall(r'\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])', text)
# ['2026-01-15', '2026-01-18', '2026-01-22', '2026-01-15']
# Deduplicate while preserving order
unique_dates = list(dict.fromkeys(dates))
# ['2026-01-15', '2026-01-18', '2026-01-22']
// JavaScript: extract ISO dates from a string
const text = `Report generated 2026-03-01. Data from 2026-02-01 to 2026-02-28.`;
const pattern = /\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])/g;
const dates = [...text.matchAll(pattern)].map(m => m[0]);
// ['2026-03-01', '2026-02-01', '2026-02-28']
Timestamps and Datetime Strings
Log files typically include a time component. Here are patterns for common timestamp formats:
| Format | Example | Pattern |
|---|---|---|
| ISO 8601 datetime | 2026-05-02T14:30:00Z | \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z |
| ISO with ms | 2026-05-02T14:30:00.123Z | \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z |
| Apache CLF | 02/May/2026:14:30:00 +0000 | \d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2} [+-]\d{4} |
| Syslog | May 2 14:30:00 | \w{3}\s+\d{1,2} \d{2}:\d{2}:\d{2} |
| US datetime | 05/02/2026 14:30:00 | \d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2} |
| Unix epoch (seconds) | 1746191400 | \b1[0-9]{9}\b |
Common Mistakes
Test Your Date Pattern
Paste a date regex and test it against real inputs — including edge cases like Feb 30th and mixed separators.
Open Regex Tester →