Skip to content

Commit

Permalink
Remove DOW-7 as alias & fix DOW calcs when DOW=0
Browse files Browse the repository at this point in the history
This fixes #90.
  • Loading branch information
kiorky committed Oct 28, 2024
1 parent 6ce433d commit f9c58ed
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 17 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Changelog
3.0.5 (unreleased)
------------------

- Nothing changed yet.

- Remove DayOfWeek alias 7 to DayOfWeek 0 to stick to standard cron (#90). [kiorky]
- Fix DOW ranges calculations when lastday is a Sunday. [kiorky]

3.0.4 (2024-10-25)
------------------
Expand Down
16 changes: 12 additions & 4 deletions src/croniter/croniter.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class croniter(object):
(0, 23),
(1, 31),
(1, 12),
(0, 7),
(0, 6),
(0, 59),
(1970, 2099)
)
Expand All @@ -218,7 +218,7 @@ class croniter(object):
{},
{0: 1},
{0: 1},
{7: 0},
{},
{},
{}
)
Expand Down Expand Up @@ -886,6 +886,7 @@ def _expand(cls, expr_format, hash_id=None, second_at_beginning=False, from_time

if m:
# early abort if low/high are out of bounds
add_sunday = False

(low, high, step) = m.group(1), m.group(2), m.group(4) or 1
if i == DAY_FIELD and high == 'l':
Expand All @@ -901,9 +902,10 @@ def _expand(cls, expr_format, hash_id=None, second_at_beginning=False, from_time
not low or not high or int(low) > int(high)
or not only_int_re.search(str(step))
):
# handle -Sun notation as Sunday is DOW-0
if i == DOW_FIELD and high == '0':
# handle -Sun notation -> 7
high = '7'
add_sunday = True
high = '6'
else:
raise CroniterBadCronError(
"[{0}] is not acceptable".format(expr_format))
Expand All @@ -923,8 +925,14 @@ def _expand(cls, expr_format, hash_id=None, second_at_beginning=False, from_time
except ValueError as exc:
raise CroniterBadCronError(
'invalid range: {0}'.format(exc))

e_list += (["{0}#{1}".format(item, nth) for item in rng]
if i == DOW_FIELD and nth and nth != "l" else rng)
# if low == high, this means all week
if (i == DOW_FIELD) and low == high and not (add_sunday and low == 6):
_ = [e_list.append(i) for i in range(7)]
if (i == DOW_FIELD) and add_sunday and (0 not in e_list):
e_list.insert(0, 0)
else:
if t.startswith('-'):
raise CroniterBadCronError((
Expand Down
120 changes: 109 additions & 11 deletions src/croniter/tests/test_croniter.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,10 @@ def testOptimizeCronExpressions(self):
self.assertEqual(croniter('0 0 1 1-12 0').expanded[mon], wildcard)
self.assertEqual(croniter('0 0 1 1 0-6').expanded[dow], [0, 1, 2, 3, 4, 5, 6])
self.assertEqual(croniter('0 0 * 1 0-6').expanded[dow], wildcard)
self.assertEqual(croniter('0 0 1 1 1-7').expanded[dow], [0, 1, 2, 3, 4, 5, 6])
self.assertEqual(croniter('0 0 1 1 1-7,sat#3').expanded[dow], [0, 1, 2, 3, 4, 5, 6])
self.assertEqual(croniter('0 0 * 1 1-7').expanded[dow], wildcard)
self.assertEqual(croniter('0 0 * 1 1-7,sat#3').expanded[dow], wildcard)
self.assertEqual(croniter('0 0 1 1 0-6').expanded[dow], [0, 1, 2, 3, 4, 5, 6])
self.assertEqual(croniter('0 0 1 1 0-6,sat#3').expanded[dow], [0, 1, 2, 3, 4, 5, 6])
self.assertEqual(croniter('0 0 * 1 0-6').expanded[dow], wildcard)
self.assertEqual(croniter('0 0 * 1 0-6,sat#3').expanded[dow], wildcard)
self.assertEqual(croniter('0 0 1 1 0 0-59').expanded[s], wildcard)
# Real life examples
self.assertEqual(croniter('30 1-12,0,10-23 15-21 * fri').expanded[h], wildcard)
Expand Down Expand Up @@ -468,13 +468,13 @@ def testPrevWeekDay2(self):

def testISOWeekday(self):
base = datetime(2010, 2, 25)
itr = croniter('0 0 * * 7', base)
itr = croniter('0 0 * * 6', base)
n1 = itr.get_next(datetime)
self.assertEqual(n1.isoweekday(), 7)
self.assertEqual(n1.day, 28)
self.assertEqual(n1.isoweekday(), 6)
self.assertEqual(n1.day, 27)
n2 = itr.get_next(datetime)
self.assertEqual(n2.isoweekday(), 7)
self.assertEqual(n2.day, 7)
self.assertEqual(n2.isoweekday(), 6)
self.assertEqual(n2.day, 6)
self.assertEqual(n2.month, 3)

def testBug1(self):
Expand Down Expand Up @@ -990,7 +990,7 @@ def test_weekday_range(self):
ret = []
dt = datetime(2019, 1, 14, 0, 0, 0, 0)
for i in range(10):
c = croniter("0 0 * * 1-7 *", start_time=dt)
c = croniter("0 0 * * 0-6 *", start_time=dt)
dt = datetime.fromtimestamp(c.get_next(), dateutil.tz.tzutc()).replace(tzinfo=None)
ret.append(dt)
dt += timedelta(days=1)
Expand All @@ -1011,7 +1011,7 @@ def test_weekday_range(self):
def test_issue_monsun_117(self):
ret = []
dt = datetime(2019, 1, 14, 0, 0, 0, 0)
for i in range(10):
for i in range(12):
# c = croniter("0 0 * * Mon-Sun *", start_time=dt)
c = croniter("0 0 * * Wed-Sun *", start_time=dt)
dt = datetime.fromtimestamp(c.get_next(), tz=dateutil.tz.tzutc()).replace(tzinfo=None)
Expand All @@ -1024,10 +1024,12 @@ def test_issue_monsun_117(self):
'2019-01-17 00:00:01',
'2019-01-18 00:00:02',
'2019-01-19 00:00:03',
'2019-01-20 00:00:04',
'2019-01-23 00:00:00',
'2019-01-24 00:00:01',
'2019-01-25 00:00:02',
'2019-01-26 00:00:03',
'2019-01-27 00:00:04',
'2019-01-30 00:00:00',
'2019-01-31 00:00:01'])

Expand Down Expand Up @@ -1970,6 +1972,102 @@ def test_issue_2038y(self):
except OverflowError:
raise Exception("overflow not fixed!")

def test_issue_90(self):
self.assertFalse(croniter.is_valid("* * * * 7"))
# self.assertFalse(croniter.is_valid('0 0 Sun-Sun * *'))

def test_sunday_ranges_to(self):
cron = croniter('0 0 * * Sun-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret1 = aret = [a.day for a in ret]
self.assertEqual(aret, [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])

cron = croniter('0 0 * * Mon-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret2 = aret = [a.day for a in ret]
self.assertEqual(aret1, aret2)

cron = croniter('0 0 * * Tue-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19,
20, 21, 23, 24, 25, 26, 27, 28, 30, 31, 1, 2, 3, 4])

cron = croniter('0 0 * * Wed-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24,
25, 26, 27, 28, 31, 1, 2, 3, 4, 7, 8, 9, 10, 11])

cron = croniter('0 0 * * Thu-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [4, 5, 6, 7, 11, 12, 13, 14, 18, 19, 20, 21, 25, 26,
27, 28, 1, 2, 3, 4, 8, 9, 10, 11, 15, 16, 17, 18, 22, 23])

cron = croniter('0 0 * * Fri-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [5, 6, 7, 12, 13, 14, 19, 20, 21, 26, 27, 28, 2, 3, 4, 9,
10, 11, 16, 17, 18, 23, 24, 25, 1, 2, 3, 8, 9, 10])

cron = croniter('0 0 * * Sat-Sun', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [6, 7, 13, 14, 20, 21, 27, 28, 3, 4, 10, 11, 17, 18, 24,
25, 2, 3, 9, 10, 16, 17, 23, 24, 30, 31, 6, 7, 13, 14])

def test_sunday_ranges_from(self):
cron = croniter('0 0 * * Sun-Mon', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [7, 8, 14, 15, 21, 22, 28, 29, 4, 5, 11, 12, 18, 19, 25,
26, 3, 4, 10, 11, 17, 18, 24, 25, 31, 1, 7, 8, 14, 15])

cron = croniter('0 0 * * Sun-Tue', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [2, 7, 8, 9, 14, 15, 16, 21, 22, 23, 28, 29, 30, 4, 5, 6, 11,
12, 13, 18, 19, 20, 25, 26, 27, 3, 4, 5, 10, 11])

cron = croniter('0 0 * * Sun-Wed', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [2, 3, 7, 8, 9, 10, 14, 15, 16, 17, 21, 22, 23, 24, 28, 29,
30, 31, 4, 5, 6, 7, 11, 12, 13, 14, 18, 19, 20, 21])

cron = croniter('0 0 * * Sun-Thu', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24,
25, 28, 29, 30, 31, 1, 4, 5, 6, 7, 8, 11, 12])

cron = croniter('0 0 * * Sun-Fri', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 21,
22, 23, 24, 25, 26, 28, 29, 30, 31, 1, 2, 4, 5])

cron = croniter('0 0 * * Sun-Sat', base)
cron.set_current(datetime(2024, 1, 1), force=True)
ret = [cron.get_next(datetime) for a in range(30)]
aret = [a.day for a in ret]
self.assertEqual(aret, [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31])


if __name__ == '__main__':
unittest.main()

0 comments on commit f9c58ed

Please sign in to comment.