Created
January 30, 2021 19:47
-
-
Save minsis/177eb893423a1ce46ed730e880c9d019 to your computer and use it in GitHub Desktop.
Simple library for parsing some human readable dates. Setup as a jinja2 filter
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 re | |
import calendar | |
from datetime import datetime | |
from dateutil.relativedelta import relativedelta | |
_day_of_week_to_ = { | |
"day": 0, | |
"monday": 0, | |
"tuesday": 1, | |
"wednesday": 2, | |
"thursday": 3, | |
"friday": 4, | |
"saturday": 5, | |
"sunday": 6 | |
} | |
_advance_to_ = { | |
"this": +0, | |
"the": +0, | |
"next": +1, | |
"last": -1 | |
} | |
_time_period_to_ = { | |
"month": "months", | |
"week": "weeks" | |
} | |
class FilterModule: | |
def filters(self): | |
return {'parse_human_date': self.parse_date} | |
@staticmethod | |
def parse_date(human_date): | |
try: | |
num_value = int(re.match(r"(\d+)", human_date).group()) | |
except (AttributeError, ValueError): | |
raise ValueError("It seems that you may not have specified a number of something. e.g. '5th' day") | |
try: | |
weekday = re.search( | |
r"(\bday\b|\bMo(nday)?\b|\bTu(e(sday)?)?\b|\bWe(d(nesday)?)?\b|\bTh(ur(sday)?)?\b|\bFr(i(day)?)?\b|\bSa(t(urday)?)?\b|\bSu(n(day)?)?\b)", | |
human_date | |
).group().lower() | |
except AttributeError: | |
raise ValueError("It seems that you may not have specified a day. e.g. 'day' or 'Friday'") | |
try: | |
advance = re.search(r"(\bnext\b|\blast\b|\bthis\b|\bthe\b)", human_date).group() | |
except AttributeError as e: | |
raise ValueError("It seems that you may not have specified a advance direction. e.g. 'next' or 'last' or 'this'") | |
try: | |
time_period = re.search(r"(\bmo(nth)?\b)", human_date).group() | |
except AttributeError: | |
raise ValueError("It seems that you may not have specified a time period. e.g. 'month' or 'week'") | |
today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) | |
options = { | |
_time_period_to_[time_period]: _advance_to_[advance] | |
} | |
new_date = today + relativedelta(**options) | |
month_cal = calendar.monthcalendar(new_date.year, new_date.month) | |
if weekday == "day" and time_period == "month": | |
new_date = new_date.replace(day=num_value) | |
# issues getting to previous week or next week | |
# elif time_period == "week": | |
# for week in month_cal: | |
# if new_date.day in week: | |
# the_week = week | |
# break | |
# new_date = new_date.replace( | |
# day=the_week[num_value - 2] | |
# ) | |
else: | |
first_week = month_cal[0] | |
the_day = first_week[_day_of_week_to_[weekday]] | |
new_date = new_date.replace( | |
day=month_cal[ | |
num_value if the_day == 0 else num_value - 1 | |
][ | |
_day_of_week_to_[weekday] | |
] | |
) | |
return new_date | |
if __name__ == "__main__": | |
print(FilterModule.parse_date("1st day of next month")) | |
print(FilterModule.parse_date("2nd Friday of this month")) | |
print(FilterModule.parse_date("1st Sunday of next month")) | |
print(FilterModule.parse_date("5th day of next month")) | |
print(FilterModule.parse_date("2nd Tuesday of this month")) | |
# print(FilterModule.parse_date("1rd day of last week")) | |
# print(FilterModule.parse_date("1st day of next week")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Main issue with this I'm having troubles with is getting "someday of last week". But I dont need it for what I'm using this library for so feel free to add to it.