Skip to content

Commit

Permalink
Took into account DST when computing localtime zones. This wasn't ac… (
Browse files Browse the repository at this point in the history
…#1258)

* Took into account DST when computing localtime zones.  This wasn't accounted for when using non-UTC datetimes with queue.enqueue_at()

* Updates tests with mocked timezones to test both scenarios
  • Loading branch information
Evansbee committed May 24, 2020
1 parent 91a2294 commit bd0fcc1
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 7 deletions.
2 changes: 1 addition & 1 deletion rq/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ def schedule(self, job, scheduled_datetime, pipeline=None):
from datetime import timezone
except ImportError:
raise ValueError('datetime object with no timezone')
tz = timezone(timedelta(seconds=-time.timezone))
tz = timezone(timedelta(seconds=-(time.timezone if time.daylight == 0 else time.altzone)))
scheduled_datetime = scheduled_datetime.replace(tzinfo=tz)

timestamp = calendar.timegm(scheduled_datetime.utctimetuple())
Expand Down
41 changes: 35 additions & 6 deletions tests/test_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,38 @@ def test_schedule(self):
# If we pass in a datetime with no timezone, `schedule()`
# assumes local timezone so depending on your local timezone,
# the timestamp maybe different
registry.schedule(job, datetime(2019, 1, 1))
self.assertEqual(self.testconn.zscore(registry.key, job.id),
1546300800 + time.timezone) # 2019-01-01 UTC in Unix timestamp

# we need to account for the difference between a timezone
# with DST active and without DST active. The time.timezone
# property isn't accurate when time.daylight is non-zero,
# we'll test both.

# first, time.daylight == 0 (not in DST).
# mock the sitatuoin for American/New_York not in DST (UTC - 5)
# time.timezone = 18000
# time.daylight = 0
# time.altzone = 14400
mock_day = mock.patch('time.daylight', 0)
mock_tz = mock.patch('time.timezone', 18000)
mock_atz = mock.patch('time.altzone', 14400)
with mock_tz, mock_day, mock_atz:
registry.schedule(job, datetime(2019, 1, 1))
self.assertEqual(self.testconn.zscore(registry.key, job.id),
1546300800 + 18000) # 2019-01-01 UTC in Unix timestamp

# second, time.daylight != 0 (in DST)
# mock the sitatuoin for American/New_York not in DST (UTC - 4)
# time.timezone = 18000
# time.daylight = 1
# time.altzone = 14400
mock_day = mock.patch('time.daylight', 1)
mock_tz = mock.patch('time.timezone', 18000)
mock_atz = mock.patch('time.altzone', 14400)
with mock_tz, mock_day, mock_atz:
registry.schedule(job, datetime(2019, 1, 1))
self.assertEqual(self.testconn.zscore(registry.key, job.id),
1546300800 + 14400) # 2019-01-01 UTC in Unix timestamp


# Score is always stored in UTC even if datetime is in a different tz
tz = timezone(timedelta(hours=7))
Expand All @@ -99,8 +128,8 @@ def test_should_reacquire_locks(self):
self.assertTrue(scheduler.should_reacquire_locks)
scheduler.acquire_locks()
self.assertIsNotNone(scheduler.lock_acquisition_time)
# scheduler.should_reacquire_locks always returns False if

# scheduler.should_reacquire_locks always returns False if
# scheduler.acquired_locks and scheduler._queue_names are the same
self.assertFalse(scheduler.should_reacquire_locks)
scheduler.lock_acquisition_time = datetime.now() - timedelta(minutes=16)
Expand Down Expand Up @@ -251,7 +280,7 @@ def test_work(self):

p.start()
queue.enqueue_at(datetime(2019, 1, 1, tzinfo=utc), say_hello)
worker.work(burst=False, with_scheduler=True)
worker.work(burst=False, with_scheduler=True)
p.join(1)
self.assertIsNotNone(worker.scheduler)
registry = FinishedJobRegistry(queue=queue)
Expand Down

0 comments on commit bd0fcc1

Please sign in to comment.