Last active
March 5, 2022 11:12
-
-
Save moreati/5a64bd9779a2a0832058f376cfe00ad3 to your computer and use it in GitHub Desktop.
Hacky wrapper for dateparser.parse() that handles christmas and new year
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import datetime | |
import re | |
import dateparser | |
def fudge_datetime(s: str, now: datetime.datetime = None) -> datetime.datetime: | |
""" | |
Return a best guess datetime for the free-form string s, relative to now. | |
>>> fudge_datetime("Christmas Day 2020") | |
datetime.datetime(2020, 12, 25, 23, 59, 59) | |
>>> fudge_datetime("yesterday", now=datetime.datetime(2020, 2, 28, 12, 00) | |
datetime.datetime(2020, 2, 27, 23, 59, 59) | |
Assumptions: | |
- the date/time in `s` occurs before the date/time `now` | |
""" | |
# TODO Timezones | |
wip = s | |
# Replace references to holidays with dates | |
# TODO Easter | |
holidays = { | |
"christmas eve": "24 December", | |
"christmas day": "25 December", | |
"boxing day": "26 December", | |
"new year's eve": "31 December", | |
"new years eve": "31 December", | |
"new year's day": "1 January", | |
"new years day": "1 January", | |
} | |
holiday_patt = re.compile( | |
# NB Relies on Python 3.6+ stable dict ordering | |
r'|'.join(re.escape(holiday) for holiday in holidays), | |
flags=re.IGNORECASE, | |
) | |
def holiday_repl(m: re.Match) -> str: | |
holiday = m.group(0).lower() | |
return holidays[holiday] | |
wip = holiday_patt.sub(holiday_repl, wip) | |
last_patt = re.compile(r'^last\s+', flags=re.IGNORECASE) | |
wip = last_patt.sub('', wip) | |
dt = dateparser.parse(wip) | |
if dt is None: | |
raise ValueError(repr(s)) | |
# Initialise this *after* parsing, so the sanity check passes for s=='today' | |
if now is None: | |
now = datetime.datetime.now() | |
if dt > now: | |
raise ValueError(f'{s=!r} {dt=} {now=}') | |
# If s contained time information, use it | |
if dt.time() > datetime.time(0): | |
return dt | |
return dt.replace(hour=23, minute=59, second=59) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment