Skip to content

Commit 94cd878

Browse files
authored
Fix: timezone info occasionally removed from cron job execution time (#383)
* Expose the bug in tests * Do not remove timezone when incrementing month in _get_next_dt
1 parent 5769e10 commit 94cd878

File tree

2 files changed

+71
-21
lines changed

2 files changed

+71
-21
lines changed

arq/cron.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ def _get_next_dt(dt_: datetime, options: Options) -> Optional[datetime]: # noqa
6767
micro = max(dt_.microsecond - options.microsecond, 0)
6868
if field == 'month':
6969
if dt_.month == 12:
70-
return datetime(dt_.year + 1, 1, 1)
70+
return datetime(dt_.year + 1, 1, 1, tzinfo=dt_.tzinfo)
7171
else:
72-
return datetime(dt_.year, dt_.month + 1, 1)
72+
return datetime(dt_.year, dt_.month + 1, 1, tzinfo=dt_.tzinfo)
7373
elif field in ('day', 'weekday'):
7474
return (
7575
dt_

tests/test_cron.py

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import asyncio
22
import logging
33
import re
4-
from datetime import datetime, timedelta
4+
from datetime import datetime, timedelta, timezone
55
from random import random
66

77
import pytest
@@ -12,37 +12,87 @@
1212
from arq.constants import in_progress_key_prefix
1313
from arq.cron import cron, next_cron
1414

15+
tz = timezone(offset=timedelta(hours=3))
16+
1517

1618
@pytest.mark.parametrize(
1719
'previous,expected,kwargs',
1820
[
19-
(datetime(2016, 6, 1, 12, 10, 10), datetime(2016, 6, 1, 12, 10, 20, microsecond=123_456), dict(second=20)),
20-
(datetime(2016, 6, 1, 12, 10, 10), datetime(2016, 6, 1, 12, 11, 0, microsecond=123_456), dict(minute=11)),
21-
(datetime(2016, 6, 1, 12, 10, 10), datetime(2016, 6, 1, 12, 10, 20), dict(second=20, microsecond=0)),
22-
(datetime(2016, 6, 1, 12, 10, 10), datetime(2016, 6, 1, 12, 11, 0), dict(minute=11, microsecond=0)),
2321
(
24-
datetime(2016, 6, 1, 12, 10, 11),
25-
datetime(2017, 6, 1, 12, 10, 10, microsecond=123_456),
22+
datetime(2016, 6, 1, 12, 10, 10, tzinfo=tz),
23+
datetime(2016, 6, 1, 12, 10, 20, microsecond=123_456, tzinfo=tz),
24+
dict(second=20),
25+
),
26+
(
27+
datetime(2016, 6, 1, 12, 10, 10, tzinfo=tz),
28+
datetime(2016, 6, 1, 12, 11, 0, microsecond=123_456, tzinfo=tz),
29+
dict(minute=11),
30+
),
31+
(
32+
datetime(2016, 6, 1, 12, 10, 10, tzinfo=tz),
33+
datetime(2016, 6, 1, 12, 10, 20, tzinfo=tz),
34+
dict(second=20, microsecond=0),
35+
),
36+
(
37+
datetime(2016, 6, 1, 12, 10, 10, tzinfo=tz),
38+
datetime(2016, 6, 1, 12, 11, 0, tzinfo=tz),
39+
dict(minute=11, microsecond=0),
40+
),
41+
(
42+
datetime(2016, 6, 1, 12, 10, 11, tzinfo=tz),
43+
datetime(2017, 6, 1, 12, 10, 10, microsecond=123_456, tzinfo=tz),
2644
dict(month=6, day=1, hour=12, minute=10, second=10),
2745
),
2846
(
29-
datetime(2016, 6, 1, 12, 10, 10, microsecond=1),
30-
datetime(2016, 7, 1, 12, 10, 10),
47+
datetime(2016, 6, 1, 12, 10, 10, microsecond=1, tzinfo=tz),
48+
datetime(2016, 7, 1, 12, 10, 10, tzinfo=tz),
3149
dict(day=1, hour=12, minute=10, second=10, microsecond=0),
3250
),
33-
(datetime(2032, 1, 31, 0, 0, 0), datetime(2032, 2, 28, 0, 0, 0, microsecond=123_456), dict(day=28)),
34-
(datetime(2032, 1, 1, 0, 5), datetime(2032, 1, 1, 4, 0, microsecond=123_456), dict(hour=4)),
35-
(datetime(2032, 1, 1, 0, 0), datetime(2032, 1, 1, 4, 2, microsecond=123_456), dict(hour=4, minute={2, 4, 6})),
36-
(datetime(2032, 1, 1, 0, 5), datetime(2032, 1, 1, 4, 2, microsecond=123_456), dict(hour=4, minute={2, 4, 6})),
37-
(datetime(2032, 2, 5, 0, 0, 0), datetime(2032, 3, 31, 0, 0, 0, microsecond=123_456), dict(day=31)),
3851
(
39-
datetime(2001, 1, 1, 0, 0, 0), # Monday
40-
datetime(2001, 1, 7, 0, 0, 0, microsecond=123_456),
52+
datetime(2032, 1, 31, 0, 0, 0, tzinfo=tz),
53+
datetime(2032, 2, 28, 0, 0, 0, microsecond=123_456, tzinfo=tz),
54+
dict(day=28),
55+
),
56+
(
57+
datetime(2032, 1, 1, 0, 5, tzinfo=tz),
58+
datetime(2032, 1, 1, 4, 0, microsecond=123_456, tzinfo=tz),
59+
dict(hour=4),
60+
),
61+
(
62+
datetime(2032, 1, 1, 0, 0, tzinfo=tz),
63+
datetime(2032, 1, 1, 4, 2, microsecond=123_456, tzinfo=tz),
64+
dict(hour=4, minute={2, 4, 6}),
65+
),
66+
(
67+
datetime(2032, 1, 1, 0, 5, tzinfo=tz),
68+
datetime(2032, 1, 1, 4, 2, microsecond=123_456, tzinfo=tz),
69+
dict(hour=4, minute={2, 4, 6}),
70+
),
71+
(
72+
datetime(2032, 2, 5, 0, 0, 0, tzinfo=tz),
73+
datetime(2032, 3, 31, 0, 0, 0, microsecond=123_456, tzinfo=tz),
74+
dict(day=31),
75+
),
76+
(
77+
datetime(2001, 1, 1, 0, 0, 0, tzinfo=tz), # Monday
78+
datetime(2001, 1, 7, 0, 0, 0, microsecond=123_456, tzinfo=tz),
4179
dict(weekday='Sun'), # Sunday
4280
),
43-
(datetime(2001, 1, 1, 0, 0, 0), datetime(2001, 1, 7, 0, 0, 0, microsecond=123_456), dict(weekday=6)), # Sunday
44-
(datetime(2001, 1, 1, 0, 0, 0), datetime(2001, 11, 7, 0, 0, 0, microsecond=123_456), dict(month=11, weekday=2)),
45-
(datetime(2001, 1, 1, 0, 0, 0), datetime(2001, 1, 3, 0, 0, 0, microsecond=123_456), dict(weekday='wed')),
81+
(
82+
datetime(2001, 1, 1, 0, 0, 0, tzinfo=tz),
83+
datetime(2001, 1, 7, 0, 0, 0, microsecond=123_456, tzinfo=tz),
84+
dict(weekday=6),
85+
), # Sunday
86+
(
87+
datetime(2001, 1, 1, 0, 0, 0, tzinfo=tz),
88+
datetime(2001, 11, 7, 0, 0, 0, microsecond=123_456, tzinfo=tz),
89+
dict(month=11, weekday=2),
90+
),
91+
(
92+
datetime(2001, 1, 1, 0, 0, 0, tzinfo=tz),
93+
datetime(2001, 1, 3, 0, 0, 0, microsecond=123_456, tzinfo=tz),
94+
dict(weekday='wed'),
95+
),
4696
],
4797
)
4898
def test_next_cron(previous, expected, kwargs):

0 commit comments

Comments
 (0)