Fix for last day of the month bug.

* In some situations, asking for the last day of the month would return the first.
* Patch provided by Franco Lucchini.
This commit is contained in:
Josiah Carlson 2012-03-25 20:55:18 -07:00
parent 74914494a0
commit 3cb7a6ad57
3 changed files with 10 additions and 10 deletions

View file

@ -51,14 +51,11 @@ MONTH = datetime.timedelta(days=28)
YEAR = datetime.timedelta(days=365) YEAR = datetime.timedelta(days=365)
# find the next scheduled time # find the next scheduled time
def _day_incr(dt, m): def _end_of_month(dt):
if m.day.input != 'l': ndt = dt + DAY
return DAY
odt = dt
ndt = dt = dt + DAY
while dt.month == ndt.month: while dt.month == ndt.month:
dt += DAY dt += DAY
return dt - odt return ndt.replace(day=1) - DAY
def _month_incr(dt, m): def _month_incr(dt, m):
odt = dt odt = dt
@ -81,7 +78,7 @@ def _year_incr(dt, m):
_increments = [ _increments = [
lambda *a: MINUTE, lambda *a: MINUTE,
lambda *a: HOUR, lambda *a: HOUR,
_day_incr, lambda *a: DAY,
_month_incr, _month_incr,
lambda *a: DAY, lambda *a: DAY,
_year_incr, _year_incr,
@ -138,7 +135,7 @@ class _Matcher(object):
self.any = self.allowed is None self.any = self.allowed is None
def __call__(self, v, dt): def __call__(self, v, dt):
if self.input == 'l': if self.input == 'l':
return v != (dt + DAY).month return v == _end_of_month(dt).day
elif self.input.startswith('l'): elif self.input.startswith('l'):
okay = dt.month != (dt + WEEK).month okay = dt.month != (dt + WEEK).month
return okay and (self.any or v in self.allowed) return okay and (self.any or v in self.allowed)

View file

@ -7,7 +7,7 @@ with open('README') as f:
setup( setup(
name='crontab', name='crontab',
version='.12', version='.13',
description='Parse and use crontab schedules in Python', description='Parse and use crontab schedules in Python',
author='Josiah Carlson', author='Josiah Carlson',
author_email='josiah.carlson@gmail.com', author_email='josiah.carlson@gmail.com',

View file

@ -4,13 +4,15 @@ import unittest
from crontab import CronTab from crontab import CronTab
class TestCrontab(unittest.TestCase): class TestCrontab(unittest.TestCase):
def _run_test(self, crontab, max_delay, now=None): def _run_test(self, crontab, max_delay, now=None, min_delay=None):
ct = CronTab(crontab) ct = CronTab(crontab)
now = now or datetime.datetime.now() now = now or datetime.datetime.now()
delay = ct.next(now) delay = ct.next(now)
assert delay is not None assert delay is not None
dd = (crontab, delay, max_delay, now, now+datetime.timedelta(seconds=delay)) dd = (crontab, delay, max_delay, now, now+datetime.timedelta(seconds=delay))
assert delay <= max_delay, dd assert delay <= max_delay, dd
if min_delay is not None:
assert delay >= min_delay, dd
if not crontab.endswith(' 2099'): if not crontab.endswith(' 2099'):
delay2 = ct.previous(now + datetime.timedelta(seconds=delay)) delay2 = ct.previous(now + datetime.timedelta(seconds=delay))
dd = (crontab, delay, max_delay, now, now+datetime.timedelta(seconds=delay)) dd = (crontab, delay, max_delay, now, now+datetime.timedelta(seconds=delay))
@ -80,6 +82,7 @@ class TestCrontab(unittest.TestCase):
self._run_test('0 0 ? 7 L0-1', 24*86400, datetime.datetime(2011, 7, 1)) self._run_test('0 0 ? 7 L0-1', 24*86400, datetime.datetime(2011, 7, 1))
self._run_test('0 0 ? 7 L0-1', 86400, datetime.datetime(2011, 7, 24)) self._run_test('0 0 ? 7 L0-1', 86400, datetime.datetime(2011, 7, 24))
self._run_test('0 0 ? 7 L0-1', 6*86400, datetime.datetime(2011, 7, 25)) self._run_test('0 0 ? 7 L0-1', 6*86400, datetime.datetime(2011, 7, 25))
self._run_test('59 23 L 12 *', 282*86400, datetime.datetime(2012, 3, 25), 280*84400)
def test_impossible(self): def test_impossible(self):
self._run_impossible('0 0 * 7 fri 2011', datetime.datetime(2011, 7, 31)) self._run_impossible('0 0 * 7 fri 2011', datetime.datetime(2011, 7, 31))