Skip to content

Instantly share code, notes, and snippets.

@lapp0
Created March 31, 2024 20:26
Show Gist options
  • Save lapp0/ee9e1035945a838868805e941f73bb25 to your computer and use it in GitHub Desktop.
Save lapp0/ee9e1035945a838868805e941f73bb25 to your computer and use it in GitHub Desktop.
Regex Pattern for Dates between 0001-01-01 and 9999-12-31, Accounting for All Leap Year Rules
# Huge Pattern
`0(0(0([1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[48]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[2468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))))|[1235679](0([0-35679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[48]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[2468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))))|[48]([02468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))))|[13579]([01345789](0([0-35679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[48]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[2468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))))|[26]([02468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))))|[2468]([048]([02468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))))|[1235679](0([0-35679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[48]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[13579]([01345789]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[26]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))|[2468]([048]-(0(2-(0[1-9]|[12]\\d)|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d)))|[1235679]-(0(2-(0[1-9]|1\\d|2[0-8])|[13578]-(0[1-9]|3[01]|[12]\\d)|[469]-(0[1-9]|30|[12]\\d))|1(1-(0[1-9]|30|[12]\\d)|[02]-(0[1-9]|3[01]|[12]\\d))))))`
I verified the pattern using `interegular`, which generated the set of legal strings the pattern can produce. I verified it matches the set of date strings.
```
>>> fsm = interegular.parse_pattern(pattern).to_fsm()
>>> fsm_strings = set(["".join(s) for s in fsm.strings()])
>>> datetime_dates = set([(dt.date(1, 1, 1) + dt.timedelta(days=x)).isoformat() for x in range((dt.date(9999, 12, 31) - dt.date(1, 1, 1)).days + 1)])
>>> fsm_strings == datetime_dates
True
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment