| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- import datetime
- import re
- class Frequencies:
- @staticmethod
- def hourly(t):
- dt = t + datetime.timedelta(hours=1)
- return dt.replace(minute=0, second=0, microsecond=0)
- @staticmethod
- def daily(t):
- dt = t + datetime.timedelta(days=1)
- return dt.replace(hour=0, minute=0, second=0, microsecond=0)
- @staticmethod
- def weekly(t):
- dt = t + datetime.timedelta(days=7 - t.weekday())
- return dt.replace(hour=0, minute=0, second=0, microsecond=0)
- @staticmethod
- def monthly(t):
- if t.month == 12:
- y, m = t.year + 1, 1
- else:
- y, m = t.year, t.month + 1
- return t.replace(year=y, month=m, day=1, hour=0, minute=0, second=0, microsecond=0)
- @staticmethod
- def yearly(t):
- y = t.year + 1
- return t.replace(year=y, month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
- def parse_size(size):
- size = size.strip()
- reg = re.compile(r"([e\+\-\.\d]+)\s*([kmgtpezy])?(i)?(b)", flags=re.I)
- match = reg.fullmatch(size)
- if not match:
- return None
- s, u, i, b = match.groups()
- try:
- s = float(s)
- except ValueError as e:
- raise ValueError("Invalid float value while parsing size: '%s'" % s) from e
- u = "kmgtpezy".index(u.lower()) + 1 if u else 0
- i = 1024 if i else 1000
- b = {"b": 8, "B": 1}[b] if b else 1
- return s * i**u / b
- def parse_duration(duration):
- duration = duration.strip()
- reg = r"(?:([e\+\-\.\d]+)\s*([a-z]+)[\s\,]*)"
- units = [
- ("y|years?", 31536000),
- ("months?", 2628000),
- ("w|weeks?", 604800),
- ("d|days?", 86400),
- ("h|hours?", 3600),
- ("min(?:ute)?s?", 60),
- ("s|sec(?:ond)?s?", 1), # spellchecker: disable-line
- ("ms|milliseconds?", 0.001),
- ("us|microseconds?", 0.000001),
- ]
- if not re.fullmatch(reg + "+", duration, flags=re.I):
- return None
- seconds = 0
- for value, unit in re.findall(reg, duration, flags=re.I):
- try:
- value = float(value)
- except ValueError as e:
- raise ValueError("Invalid float value while parsing duration: '%s'" % value) from e
- try:
- unit = next(u for r, u in units if re.fullmatch(r, unit, flags=re.I))
- except StopIteration:
- raise ValueError("Invalid unit value while parsing duration: '%s'" % unit) from None
- seconds += value * unit
- return datetime.timedelta(seconds=seconds)
- def parse_frequency(frequency):
- frequencies = {
- "hourly": Frequencies.hourly,
- "daily": Frequencies.daily,
- "weekly": Frequencies.weekly,
- "monthly": Frequencies.monthly,
- "yearly": Frequencies.yearly,
- }
- frequency = frequency.strip().lower()
- return frequencies.get(frequency, None)
- def parse_day(day):
- days = {
- "monday": 0,
- "tuesday": 1,
- "wednesday": 2,
- "thursday": 3,
- "friday": 4,
- "saturday": 5,
- "sunday": 6,
- }
- day = day.strip().lower()
- if day in days:
- return days[day]
- if day.startswith("w") and day[1:].isdigit():
- day = int(day[1:])
- if not 0 <= day < 7:
- raise ValueError("Invalid weekday value while parsing day (expected [0-6]): '%d'" % day)
- else:
- day = None
- return day
- def parse_time(time):
- time = time.strip()
- reg = re.compile(r"^[\d\.\:]+\s*(?:[ap]m)?$", flags=re.I)
- if not reg.match(time):
- return None
- formats = [
- "%H",
- "%H:%M",
- "%H:%M:%S",
- "%H:%M:%S.%f",
- "%I %p",
- "%I:%M %S",
- "%I:%M:%S %p",
- "%I:%M:%S.%f %p",
- ]
- for format_ in formats:
- try:
- dt = datetime.datetime.strptime(time, format_)
- except ValueError:
- pass
- else:
- return dt.time()
- raise ValueError("Unrecognized format while parsing time: '%s'" % time)
- def parse_daytime(daytime):
- daytime = daytime.strip()
- reg = re.compile(r"^(.*?)\s+at\s+(.*)$", flags=re.I)
- match = reg.match(daytime)
- if match:
- day, time = match.groups()
- else:
- day = time = daytime
- try:
- parsed_day = parse_day(day)
- if match and parsed_day is None:
- raise ValueError("Unparsable day")
- except ValueError as e:
- raise ValueError("Invalid day while parsing daytime: '%s'" % day) from e
- try:
- parsed_time = parse_time(time)
- if match and parsed_time is None:
- raise ValueError("Unparsable time")
- except ValueError as e:
- raise ValueError("Invalid time while parsing daytime: '%s'" % time) from e
- if parsed_day is None and parsed_time is None:
- return None
- return parsed_day, parsed_time
|