diff --git a/redbeat/schedulers.py b/redbeat/schedulers.py index 6fcbec7..72c9f4f 100644 --- a/redbeat/schedulers.py +++ b/redbeat/schedulers.py @@ -5,7 +5,7 @@ from datetime import datetime -import time +import calendar try: import simplejson as json @@ -15,7 +15,7 @@ from celery.beat import Scheduler, ScheduleEntry from celery.utils.log import get_logger from celery.signals import beat_init -from celery.utils.timeutils import humanize_seconds +from celery.utils.timeutils import humanize_seconds, maybe_make_aware from celery.app import app_or_default from redis.client import StrictRedis @@ -54,7 +54,11 @@ def redis(app=None): def to_timestamp(dt): - return time.mktime(dt.timetuple()) + return calendar.timegm(maybe_make_aware(dt).timetuple()) + + +def from_timestamp(ts): + return datetime.utcfromtimestamp(ts) class RedBeatSchedulerEntry(ScheduleEntry): diff --git a/tests/basecase.py b/tests/basecase.py index f3f9787..cd20a48 100644 --- a/tests/basecase.py +++ b/tests/basecase.py @@ -17,7 +17,7 @@ def setup(self): self.app.redbeat_redis = FakeStrictRedis() self.app.redbeat_redis.flushdb() - def create_entry(self, name=None, task=None, s=None, **kwargs): + def create_entry(self, name=None, task=None, s=None, run_every=60, **kwargs): if name is None: name = 'test' @@ -26,7 +26,7 @@ def create_entry(self, name=None, task=None, s=None, **kwargs): task = 'tasks.test' if s is None: - s = schedule(run_every=60) + s = schedule(run_every=run_every) e = RedBeatSchedulerEntry(name, task, s, app=self.app, **kwargs) diff --git a/tests/test_entry.py b/tests/test_entry.py index c1bcd22..289760b 100644 --- a/tests/test_entry.py +++ b/tests/test_entry.py @@ -5,6 +5,7 @@ from redbeat import RedBeatSchedulerEntry from redbeat.decoder import RedBeatJSONDecoder, RedBeatJSONEncoder +from redbeat.schedulers import to_timestamp, from_timestamp class test_RedBeatEntry(RedBeatCase): @@ -110,3 +111,15 @@ def test_due_at_overdue(self): self.assertLess(last_run_at, due_at) self.assertGreater(due_at, before) + + def test_score(self): + run_every = 61*60 + entry = self.create_entry(run_every=run_every) + entry = entry._next_instance() + + score = entry.score + expected = entry.last_run_at + timedelta(seconds=run_every) + expected = expected.replace(microsecond=0) # discard microseconds, lost in timestamp + + self.assertEqual(score, to_timestamp(expected)) + self.assertEqual(expected, from_timestamp(score)) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..20e1f01 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,15 @@ +from basecase import RedBeatCase +from redbeat.schedulers import to_timestamp, from_timestamp + + +class Test_utils(RedBeatCase): + + def test_roundtrip(self): + now = self.app.now() + + roundtripped = from_timestamp(to_timestamp(now)) + + # we lose microseconds in the roundtrip, so we need to ignore them + now = now.replace(microsecond=0) + + self.assertEqual(now, roundtripped)