Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More DST unit tests (WIP) #32

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions src/croniter/tests/test_croniter.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@
import dateutil.tz


def datetime_tz(*args, **kwargs):
"""
Helpful constructor abstraction for building datetime objects with timezones from different
python modules. Specifically, pytz timezones don't work with the default tzinfo constructor for
many timezones and therefore the use of tz.localize().
"""
try:
tzinfo = kwargs.pop("tzinfo")
if hasattr(tzinfo, "localize"):
dt = datetime(*args, **kwargs)
return tzinfo.localize(dt)
except KeyError:
pass
return datetime(*args, tzinfo=tzinfo, **kwargs)


class CroniterTest(base.TestCase):

def testSecondSec(self):
Expand Down Expand Up @@ -1063,5 +1079,123 @@ def test_dst_issue90_st31ny(self):
'2020-03-29T02:01:00+02:00',
'2020-03-29T03:01:00+02:00'])

def test_bug137_dst_spring_dateutil_forward(self):
"""
From https://github.com/taichino/croniter/issues/137

FAILS: Stuck on time immediately after time change
Keeps returning 2020-03-08T01:00:00-08:00
"""
tz = dateutil.tz.gettz("America/Los_Angeles")
start = datetime_tz(year=2020, month=3, day=7, hour=20, tzinfo=tz)
# DST change happened at 2am on March 8 2020
it = croniter("0 */1 * * *", start)
ret = [it.get_next(datetime).isoformat() for i in range(10)]
self.assertEqual(ret, [
"2020-03-07T21:00:00-08:00",
"2020-03-07T22:00:00-08:00",
"2020-03-07T23:00:00-08:00",
"2020-03-08T00:00:00-08:00",
"2020-03-08T01:00:00-08:00",
"2020-03-08T03:00:00-07:00",
"2020-03-08T04:00:00-07:00",
"2020-03-08T05:00:00-07:00",
"2020-03-08T06:00:00-07:00",
"2020-03-08T07:00:00-07:00"])

def test_bug137_dst_spring_pytz_forward(self):
"""
Same as https://github.com/taichino/croniter/issues/137

FAILS: Returns '2020-03-08T02:00:00-07:00'
"""
tz = pytz.timezone("US/Pacific")
start = datetime_tz(year=2020, month=3, day=7, hour=20, tzinfo=tz)
# DST change happened at 2am on March 8 2020
it = croniter("0 */1 * * *", start)
ret = [it.get_next(datetime).isoformat() for i in range(10)]
self.assertEqual(ret, [
"2020-03-07T21:00:00-08:00",
"2020-03-07T22:00:00-08:00",
"2020-03-07T23:00:00-08:00",
"2020-03-08T00:00:00-08:00",
"2020-03-08T01:00:00-08:00",
"2020-03-08T03:00:00-07:00",
"2020-03-08T04:00:00-07:00",
"2020-03-08T05:00:00-07:00",
"2020-03-08T06:00:00-07:00",
"2020-03-08T07:00:00-07:00"])

def test_bug137_dst_spring_reverse(self):
# Like above, but works fine in reverse order for both dateuil and pytz
dt = dict(year=2020, month=3, day=8, hour=8)
cron = "0 */1 * * *"
expected = [
"2020-03-08T07:00:00-07:00",
"2020-03-08T06:00:00-07:00",
"2020-03-08T05:00:00-07:00",
"2020-03-08T04:00:00-07:00",
"2020-03-08T03:00:00-07:00",
"2020-03-08T01:00:00-08:00",
"2020-03-08T00:00:00-08:00",
"2020-03-07T23:00:00-08:00",
"2020-03-07T22:00:00-08:00",
"2020-03-07T21:00:00-08:00",
]
# pytz
tz = pytz.timezone("US/Pacific")
it = croniter(cron, datetime_tz(tzinfo=tz, **dt), ret_type=datetime)
ret = [it.get_prev().isoformat() for i in range(10)]
self.assertEqual(ret, expected)
# dateutil
tz = dateutil.tz.gettz("America/Los_Angeles")
it = croniter(cron, datetime_tz(tzinfo=tz, **dt), ret_type=datetime)
ret = [it.get_prev().isoformat() for i in range(10)]
self.assertEqual(ret, expected)

def test_hour_wrong_prior_to_dst(self):
# FAILS
tz = pytz.timezone("US/Eastern")
it = croniter("15 2 * * sun", datetime_tz(2020, 2, 22, tzinfo=tz))
ret = [it.get_next(datetime).isoformat() for i in range(8)]
self.assertEqual(ret, [
"2020-02-23T02:15:00-05:00",
"2020-03-01T02:15:00-05:00",
"2020-03-08T03:15:00-04:00",
"2020-03-15T02:15:00-04:00",
"2020-03-22T02:15:00-04:00",
"2020-03-29T02:15:00-04:00",
"2020-04-05T02:15:00-04:00",
"2020-04-12T02:15:00-04:00",
])

def test_extra_hour_day_prio(self):
# Pass
tz = pytz.timezone("US/Eastern")
cron = "0 3 * * *"
start = datetime_tz(2020, 3, 7, tzinfo=tz)
it = croniter(cron, start)
ret = [it.get_next(datetime).isoformat() for i in range(4)]
self.assertEqual(ret, [
"2020-03-07T03:00:00-05:00",
"2020-03-08T03:00:00-04:00",
"2020-03-09T03:00:00-04:00",
"2020-03-10T03:00:00-04:00"])

def tests_dst_skip_day_before(self):
# Pass
tz = pytz.timezone("US/Eastern")
it = croniter("30 4 * * sat", datetime_tz(2020, 3, 7, 2, tzinfo=tz))
ret = it.get_next(datetime).isoformat()
self.assertEqual(ret, "2020-03-07T04:30:00-05:00")

def tests_dst_skip_also_good(self):
# Pass
tz = pytz.timezone("US/Eastern")
it = croniter("30 23 * * fri", datetime_tz(2020, 3, 7, tzinfo=tz))
ret = it.get_next(datetime).isoformat()
self.assertEqual(ret, "2020-03-13T23:30:00-04:00")


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