diff options
author | Lowell Alleman <lowell@kintyre.co> | 2021-03-25 11:35:32 -0400 |
---|---|---|
committer | kiorky <kiorky@cryptelium.net> | 2021-04-07 17:01:14 +0200 |
commit | 8a83d37b6fe97c9dc74da2516d36d6047ef56155 (patch) | |
tree | 111847bef8d87d46d93a66cd4e06093394a35d99 | |
parent | 9d3bbe81d2bea0d2361765855f3e0b11290bff5c (diff) | |
download | croniter-8a83d37b6fe97c9dc74da2516d36d6047ef56155.tar.gz |
Refactoring
-rw-r--r-- | src/croniter/croniter.py | 60 | ||||
-rwxr-xr-x | src/croniter/tests/test_croniter.py | 33 |
2 files changed, 46 insertions, 47 deletions
diff --git a/src/croniter/croniter.py b/src/croniter/croniter.py index 43f5ff5..0275061 100644 --- a/src/croniter/croniter.py +++ b/src/croniter/croniter.py @@ -131,13 +131,21 @@ class croniter(object): def prep_expr(self, expr_format): """ Intercept "<dow>L" entries in day-of-week and handle them specially. Everything else is passed along as-is. Unpack / repack. """ - expressions = expr_format.split() + def handle_dow(day_of_week): + mo = re.match(r"^L([0-7])$", day_of_week, re.IGNORECASE) + if mo: + dow = int(mo.group(1)) % 7 + self.last_weekday_of_month.add(dow) + # Last dow should always be either the 4 or 5th occurrence of that dow + return "L", "{dow}#4,{dow}#5".format(dow=dow) + return "other", day_of_week + expressions = expr_format.split() # day of week field manipulations found_types = set() items = [] for dow in expressions[4].split(","): - type_, dow = self.handle_dow(dow) + type_, dow = handle_dow(dow) found_types.add(type_) items.append(dow) if len(found_types) > 1: @@ -149,32 +157,6 @@ class croniter(object): expr_format = " ".join(expressions) return expr_format - def handle_dow(self, day_of_week): - mo = re.match(r"^L([0-7])$", day_of_week, re.IGNORECASE) - if mo: - dow = int(mo.group(1)) % 7 - self.last_weekday_of_month.add(dow) - # Last dow should always be either the 4 or 5th occurrence of that dow - return "L", "{dow}#4,{dow}#5".format(dow=dow) - return "other", day_of_week - - @staticmethod - def find_day_of_last_dow(timestamp, day_of_week): - """ Given the year/month of timestamp, determine the last day of the - month which is the day of the week. Calendar week starts on Sunday, to - match cron day_of_week convention. - """ - # How expensive is this? Easily cache by (year, month, dow) - day_of_week = int(day_of_week) - cal = calendar.Calendar(6).monthdayscalendar(timestamp.year, timestamp.month) - week = -1 - while True: - day = cal[week][day_of_week] - if day == 0: # 0 means absent / different month - week -= 1 - else: - return day - @classmethod def _alphaconv(cls, index, key, expressions): try: @@ -305,11 +287,12 @@ class croniter(object): if self.last_weekday_of_month: ts_dow = timestamp.isoweekday() % 7 if ts_dow in self.last_weekday_of_month: - last_dow = self.find_day_of_last_dow(timestamp, ts_dow) + last_dow = self._get_last_weekday_of_month( + timestamp.year, timestamp.month, ts_dow) return timestamp.day == last_dow else: # Have LDOM, but not for current day, return anyways??? - # Q: Can this still happen after blocking L/non-L missing in dow.... + # Q: Can this still happen after blocking L/non-L mixing in dow? return True else: # For all the other "normal" cron expression, no extra filter needed @@ -612,6 +595,23 @@ class croniter(object): return (candidate - x - range_val) + @staticmethod + def _get_last_weekday_of_month(year, month, day_of_week): + """ Given the year/month of timestamp, determine the last day of the + month which is a particular day of the week. Calendar week starts on + Sunday, to match cron's day_of_week convention. + """ + # How expensive is this? Easily cache by (year, month, dow) + day_of_week = int(day_of_week) + cal = calendar.Calendar(6).monthdayscalendar(year, month) + week = -1 + while True: + day = cal[week][day_of_week] + if day == 0: # 0 means absent / different month + week -= 1 + else: + return day + def is_leap(self, year): if year % 400 == 0 or (year % 4 == 0 and year % 100 != 0): return True diff --git a/src/croniter/tests/test_croniter.py b/src/croniter/tests/test_croniter.py index 3002a03..0948a5a 100755 --- a/src/croniter/tests/test_croniter.py +++ b/src/croniter/tests/test_croniter.py @@ -1102,27 +1102,26 @@ class CroniterTest(base.TestCase): '2020-03-29T03:01:00+02:00']) def test_last_wdom_simple(self): - f = croniter.find_day_of_last_dow + f = croniter._get_last_weekday_of_month sun, mon, tue, wed, thu, fri, sat = range(7) - self.assertEqual(f(datetime(2021, 3, 6), sun), 28) - self.assertEqual(f(datetime(2035, 12, 31), sat), 29) - self.assertEqual(f(datetime(2000, 1, 1), fri), 28) - self.assertEqual(f(datetime(2014, 8, 15), mon), 25) - self.assertEqual(f(datetime(2022, 2, 19), tue), 22) - self.assertEqual(f(datetime(1999, 10, 10), wed), 27) - self.assertEqual(f(datetime(2005, 7, 19), thu), 28) + self.assertEqual(f(2021, 3, sun), 28) + self.assertEqual(f(2035, 12, sat), 29) + self.assertEqual(f(2000, 1, fri), 28) + self.assertEqual(f(2014, 8, mon), 25) + self.assertEqual(f(2022, 2, tue), 22) + self.assertEqual(f(1999, 10, wed), 27) + self.assertEqual(f(2005, 7, thu), 28) def test_last_wdom_leap_year(self): - f = croniter.find_day_of_last_dow + f = croniter._get_last_weekday_of_month sun, mon, tue, wed, thu, fri, sat = range(7) - self.assertEqual(f(datetime(2000, 2, 1), tue), 29) - self.assertEqual(f(datetime(2000, 2, 10), tue), 29) # day doesn't matter - self.assertEqual(f(datetime(2000, 2, 1), sun), 27) - self.assertEqual(f(datetime(2000, 2, 1), mon), 28) - self.assertEqual(f(datetime(2000, 2, 1), wed), 23) - self.assertEqual(f(datetime(2000, 2, 1), thu), 24) - self.assertEqual(f(datetime(2000, 2, 1), fri), 25) - self.assertEqual(f(datetime(2000, 2, 1), sat), 26) + self.assertEqual(f(2000, 2, tue), 29) + self.assertEqual(f(2000, 2, sun), 27) + self.assertEqual(f(2000, 2, mon), 28) + self.assertEqual(f(2000, 2, wed), 23) + self.assertEqual(f(2000, 2, thu), 24) + self.assertEqual(f(2000, 2, fri), 25) + self.assertEqual(f(2000, 2, sat), 26) def test_croniter_last_friday(self): it = croniter("0 0 * * L5", datetime(1987, 1, 15), ret_type=datetime) |