Skip to content

Commit c5b7434

Browse files
committed
Fixed time zone issue and added a test case
1 parent 22a8d7c commit c5b7434

File tree

4 files changed

+56
-12
lines changed

4 files changed

+56
-12
lines changed

django_celery_beat/models.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,10 @@ def from_schedule(cls, schedule):
390390
except MultipleObjectsReturned:
391391
return cls.objects.filter(**spec).first()
392392

393-
def due_start_time(self, start_time):
393+
def due_start_time(self, start_time, tz):
394+
if str(start_time.tzinfo) != str(tz):
395+
start_time = start_time.astimezone(tz)
394396
start, ends_in, now = self.schedule.remaining_delta(start_time)
395-
396-
same_tz = str(start.tzinfo) == str(now.tzinfo)
397-
different_offset = now.utcoffset() != start.utcoffset()
398-
399-
if same_tz and different_offset:
400-
start = start.replace(tzinfo=now.tzinfo)
401-
402397
return start + ends_in
403398

404399

@@ -675,9 +670,8 @@ def scheduler(self):
675670
def schedule(self):
676671
return self.scheduler.schedule
677672

678-
@property
679-
def due_start_time(self):
673+
def due_start_time(self, tz):
680674
if self.crontab:
681-
return self.crontab.due_start_time(self.start_time)
675+
return self.crontab.due_start_time(self.start_time, tz)
682676
else:
683677
return self.start_time

django_celery_beat/schedulers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ def is_due(self):
116116
if now < self.model.start_time:
117117
# The datetime is before the start date - don't run.
118118
# send a delay to retry on start_time
119+
now_tz = now.tzinfo
119120
delay = math.ceil(
120-
(self.model.due_start_time - now).total_seconds()
121+
(self.model.due_start_time(now_tz) - now).total_seconds()
121122
)
122123

123124
return schedules.schedstate(False, delay)

requirements/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ pytest-django>=4.5.2,<5.0
22
pytest>=6.2.5,<9.0
33
pytest-timeout
44
ephem
5+
pytz

t/unit/test_schedulers.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from time import monotonic
77

88
import pytest
9+
import pytz
910
from celery.schedules import crontab, schedule, solar
1011
from django.contrib.admin.sites import AdminSite
1112
from django.contrib.messages.storage.fallback import FallbackStorage
@@ -821,6 +822,53 @@ def test_crontab_with_start_time_after_crontab(self, app):
821822
assert not is_due
822823
assert next_check == pytest.approx(expected_delay, abs=60)
823824

825+
def test_crontab_with_start_time_different_time_zone(self, app):
826+
now = app.now()
827+
828+
delay_minutes = 2
829+
830+
test_start_time = now + timedelta(minutes=delay_minutes)
831+
832+
crontab_time = test_start_time + timedelta(minutes=delay_minutes)
833+
834+
tz = pytz.timezone('Asia/Shanghai')
835+
test_start_time = test_start_time.astimezone(tz)
836+
837+
task = self.create_model_crontab(
838+
crontab(minute=f'{crontab_time.minute}'),
839+
start_time=test_start_time)
840+
841+
entry = EntryTrackSave(task, app=app)
842+
843+
is_due, next_check = entry.is_due()
844+
845+
expected_delay = 2 * delay_minutes * 60
846+
847+
assert not is_due
848+
assert next_check == pytest.approx(expected_delay, abs=60)
849+
850+
now = app.now()
851+
852+
crontab_time = now + timedelta(minutes=delay_minutes)
853+
854+
test_start_time = crontab_time + timedelta(minutes=delay_minutes)
855+
856+
tz = pytz.timezone('Asia/Shanghai')
857+
test_start_time = test_start_time.astimezone(tz)
858+
859+
task = self.create_model_crontab(
860+
crontab(minute=f'{crontab_time.minute}'),
861+
start_time=test_start_time)
862+
863+
entry = EntryTrackSave(task, app=app)
864+
865+
is_due, next_check = entry.is_due()
866+
867+
expected_delay = delay_minutes * 60 + 3600
868+
869+
assert not is_due
870+
assert next_check == pytest.approx(expected_delay, abs=60)
871+
824872
def test_crontab_with_start_time_tick(self, app):
825873
PeriodicTask.objects.all().delete()
826874
s = self.Scheduler(app=self.app)

0 commit comments

Comments
 (0)