From 0beeb95d76c560222a2ae340c7e4aedf81c94ad9 Mon Sep 17 00:00:00 2001 From: Josiah Carlson Date: Tue, 20 Nov 2018 13:49:12 -0800 Subject: [PATCH] Fix for dateutil-related bugs * Should hopefully fix timezone related issues for non-pytz libraries --- crontab/_crontab.py | 21 +++++++++++++-------- setup.py | 2 +- tests/test_crontab.py | 24 +++++++++++++++++++++++- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/crontab/_crontab.py b/crontab/_crontab.py index 0eb2d26..528809e 100644 --- a/crontab/_crontab.py +++ b/crontab/_crontab.py @@ -435,16 +435,16 @@ class CronTab(object): "crontab: %r\n" \ "now: %r", ' '.join(m.input for m in self.matchers), now) + if not delta: + onow = now = datetime(1970, 1, 1) + delay = future - now if tz: - delay += onow.utcoffset() - delay -= tz.localize(future).utcoffset() - - if not delta: - begin = datetime(1970, 1, 1) - delay = future - begin - if tz: - delay -= tz.localize(future).utcoffset() + delay += _fix_none(onow.utcoffset()) + if hasattr(tz, 'localize'): + delay -= _fix_none(tz.localize(future).utcoffset()) + else: + delay -= _fix_none(future.replace(tzinfo=tz).utcoffset()) return delay.days * 86400 + delay.seconds + delay.microseconds / 1000000. @@ -458,3 +458,8 @@ class CronTab(object): if not self._test_match(index, entry): return False return True + +def _fix_none(d, _=timedelta(0)): + if d is None: + return _ + return d diff --git a/setup.py b/setup.py index 7347685..5545920 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ except: setup( name='crontab', - version='0.22.3', + version='0.22.4', description='Parse and use crontab schedules in Python', author='Josiah Carlson', author_email='josiah.carlson@gmail.com', diff --git a/tests/test_crontab.py b/tests/test_crontab.py index 4117173..8c0e97d 100644 --- a/tests/test_crontab.py +++ b/tests/test_crontab.py @@ -4,6 +4,7 @@ import datetime import unittest import pytz +import dateutil.tz from crontab import CronTab @@ -171,7 +172,7 @@ class TestCrontab(unittest.TestCase): self.assertTrue(-3600 <= previous <= 0, previous) ts += datetime.timedelta(seconds=1) - def test_timezones(self): + def test_timezones_pytz(self): s = CronTab('0 9 13 3 * 2016') self.assertEqual(s.next(datetime.datetime(2016, 3, 13), default_utc=True), 32400) @@ -189,6 +190,27 @@ class TestCrontab(unittest.TestCase): self.assertEqual(CronTab('30 1 * * * 2018').next(timezone.localize(datetime.datetime(2018, 11, 4, 1, 15))), 900) self.assertEqual(CronTab('30 1 * * * 2018').next(timezone.localize(datetime.datetime(2018, 11, 4))), 9000) + def test_timezones_dateutil(self): + s = CronTab('0 9 13 3 * 2016') + + self.assertEqual(s.next(datetime.datetime(2016, 3, 13), default_utc=True), 32400) + utc = dateutil.tz.tzutc() + self.assertEqual(s.next(datetime.datetime(2016, 3, 13, tzinfo=utc), default_utc=True), 32400) + + x = datetime.datetime(2016, 3, 13, tzinfo=dateutil.tz.gettz('US/Eastern')) + self.assertEqual(s.next(x), 28800) + + t = CronTab('0 9 * * * 2018') + self.assertEqual(t.next(datetime.datetime(2018, 11, 4), default_utc=True), 32400) + + timezone = dateutil.tz.gettz("America/Los_Angeles") + self.assertEqual(t.next(datetime.datetime(2018, 11, 4, tzinfo=timezone)), 36000) + before = datetime.datetime(2018, 11, 4, 8, 29, tzinfo=utc).astimezone(timezone) + self.assertEqual(CronTab('30 1 * * * 2018').next(before), 60) + before = datetime.datetime(2018, 11, 4, 8, 31, tzinfo=utc).astimezone(timezone) + self.assertEqual(CronTab('30 1 * * * 2018').next(before), 89940) + self.assertEqual(CronTab('30 1 * * * 2018').next(datetime.datetime(2018, 11, 4, 1, 15, tzinfo=timezone)), 900) + self.assertEqual(CronTab('30 1 * * * 2018').next(datetime.datetime(2018, 11, 4, tzinfo=timezone)), 5400) if __name__ == '__main__': unittest.main()