kiorky / croniter

MIT License
410 stars 40 forks source link

Restrict both day-of-week and day-of-month like vixie-cron #75

Open tintamarre opened 4 months ago

tintamarre commented 4 months ago

According to the cron specification, it is not possible to restrict both the day-of-week and the day-of-month simultaneously:

While normally the job is executed when the time/date specification fields all match the current time and date, there is one exception: if both "day of month" and "day of week" are restricted (not "*"), then either the "day of month" field (3) or the "day of week" field (5) must match the current day. Source: https://en.wikipedia.org/wiki/Cron#cite_ref-posix_8-0

Although it is generally not possible to restrict both fields, there is a hacky workaround described here and working for vixie-cron.

Here is an example on cronguru restricting both day of month and day of week: https://crontab.guru/#42_5_*/32,10-17_*_Tue

When using Croniter, this workaround doesn't seem to work. Is this the intended behavior?

Thanks ! Martin

kiorky commented 4 months ago

Please give reproducible cases to be sure to understand your use case.

tintamarre commented 4 months ago

Of course. :-)

from croniter import croniter
from datetime import datetime
base = datetime(2024, 7, 12)
iter = croniter('1 1 */32,1-7 * 2', base) #First Tuesday of the month a 01:01

for _ in range(4):
    print(iter.get_next(datetime)) 

Results

2024-07-16 01:01:00
2024-07-23 01:01:00
2024-07-30 01:01:00
2024-08-01 01:01:00

Expected results (ref: Crontab.guru: https://crontab.guru/#1_1_*/32,1-7_*_2)

2024-08-06 01:01:00
2024-09-03 01:01:00
2024-10-01 01:01:00
2024-11-05 01:01:00

The proposed test

def testFirstTuesdayOfMonth(self):
    it = croniter("1 1 */32,1-7 * 2", datetime(2024, 7, 12))
    self.assertEqual(it.get_next(datetime), datetime(2024, 8, 6, 1, 1))
    self.assertEquat(it.get_next(datetime), datetime(2024, 9, 3, 1, 1))
    self.assertEqual(it.get_next(datetime), datetime(2024, 10, 1, 1, 1))
    self.assertEqual(it.get_next(datetime), datetime(2024, 11, 5, 1, 1))