Permalink
Browse files

Fixed timezone support in Django 1.4 by conditionally converting time…

…zone aware datetime instances into naive and/or convert naive instances into aware ones. Refs #96.
  • Loading branch information...
1 parent 3b3b0ca commit d437b5abbf634d3f280b582c962f5d5a45558872 @jezdez jezdez committed Jan 10, 2012
View
@@ -13,3 +13,7 @@ erl_crash.dump
*.db
Documentation/
*.sqlite
+.tox/
+cover/
+coverage.xml
+nosetests.xml
View
@@ -18,6 +18,8 @@
from celery.utils.timeutils import maybe_timedelta
+from .utils import now
+
class TxIsolationWarning(UserWarning):
pass
@@ -102,7 +104,7 @@ class ResultManager(ExtendedManager):
def get_all_expired(self, expires):
"""Get all expired task results."""
- return self.filter(date_done__lt=datetime.now() - expires)
+ return self.filter(date_done__lt=now() - expires)
def delete_expired(self, expires):
"""Delete all expired taskset results."""
@@ -210,7 +212,7 @@ class TaskStateManager(ExtendedManager):
def active(self):
return self.filter(hidden=False)
- def expired(self, states, expires, nowfun=datetime.now):
+ def expired(self, states, expires, nowfun=now):
return self.filter(state__in=states,
tstamp__lte=nowfun() - maybe_timedelta(expires))
View
@@ -18,6 +18,7 @@
from celery.utils.timeutils import timedelta_seconds
from . import managers
+from .utils import now
HEARTBEAT_EXPIRE = 150 # 2 minutes, 30 seconds
TASK_STATE_CHOICES = zip(states.ALL_STATES, states.ALL_STATES)
@@ -155,9 +156,8 @@ class PeriodicTasks(models.Model):
@classmethod
def changed(cls, instance, **kwargs):
if not instance.no_changes:
- now = datetime.now()
cls.objects.update_or_create(ident=1,
- defaults={"last_update": now})
+ defaults={"last_update": now()})
@classmethod
def last_change(cls):
View
@@ -15,6 +15,7 @@
from .models import (PeriodicTask, PeriodicTasks,
CrontabSchedule, IntervalSchedule)
+from .utils import now, make_naive
class ModelEntry(ScheduleEntry):
@@ -53,10 +54,10 @@ def is_due(self):
return self.schedule.is_due(self.last_run_at)
def _default_now(self):
- return datetime.now()
+ return now()
def next(self):
- self.model.last_run_at = datetime.now()
+ self.model.last_run_at = now()
self.model.total_run_count += 1
self.model.no_changes = True
return self.__class__(self.model)
@@ -93,7 +94,7 @@ def from_entry(cls, name, skip_fields=("relative", "options"), **entry):
defaults=fields))
def __repr__(self):
- return "<ModelEntry: %s %s(*%s, **%s) {%s}" % (safe_str(self.name),
+ return "<ModelEntry: %s %s(*%s, **%s) {%s}>" % (safe_str(self.name),
self.task,
safe_repr(self.args),
safe_repr(self.kwargs),
@@ -139,10 +140,10 @@ def schedule_changed(self):
pass # not in transaction management.
ts = self.Changes.last_change()
- if not ts or ts < self._last_timestamp:
+ if not ts or ts < make_naive(self._last_timestamp):
return False
- self._last_timestamp = datetime.now()
+ self._last_timestamp = now()
return True
def reserve(self, entry):
@@ -9,6 +9,7 @@
from celery.utils import gen_unique_id
from djcelery.backends.database import DatabaseBackend
+from djcelery.utils import now
from djcelery.tests.utils import unittest
@@ -89,8 +90,7 @@ def test_cleanup(self):
self.assertEqual(b.TaskModel._default_manager.count(), 3)
- then = datetime.now() - \
- current_app.conf.CELERY_TASK_RESULT_EXPIRES * 2
+ then = now() - current_app.conf.CELERY_TASK_RESULT_EXPIRES * 2
# Have to avoid save() because it applies the auto_now=True.
b.TaskModel._default_manager.filter(task_id__in=ids[:-1]) \
.update(date_done=then)
@@ -8,6 +8,7 @@
from djcelery.models import TaskMeta, TaskSetMeta
from djcelery.tests.utils import unittest
+from djcelery.utils import now
class TestModels(unittest.TestCase):
@@ -43,7 +44,7 @@ def test_taskmeta(self):
# Have to avoid save() because it applies the auto_now=True.
TaskMeta.objects.filter(task_id=m1.task_id).update(
- date_done=datetime.now() - timedelta(days=10))
+ date_done=now() - timedelta(days=10))
expired = TaskMeta.objects.get_all_expired(
current_app.conf.CELERY_TASK_RESULT_EXPIRES)
@@ -69,7 +70,7 @@ def test_tasksetmeta(self):
# Have to avoid save() because it applies the auto_now=True.
TaskSetMeta.objects.filter(taskset_id=m1.taskset_id).update(
- date_done=datetime.now() - timedelta(days=10))
+ date_done=now() - timedelta(days=10))
expired = TaskSetMeta.objects.get_all_expired(
current_app.conf.CELERY_TASK_RESULT_EXPIRES)
@@ -11,6 +11,7 @@
from djcelery.app import app
from djcelery.models import PeriodicTask, IntervalSchedule, CrontabSchedule
from djcelery.models import PeriodicTasks
+from djcelery.utils import now, make_aware
from djcelery.tests.utils import unittest
@@ -85,12 +86,12 @@ def test_entry(self):
"exchange": "foo",
"routing_key": "cpu"}, e.options)
- now = datetime.now()
+ right_now = now()
m2 = create_model_interval(schedule(timedelta(seconds=10)),
- last_run_at=now)
+ last_run_at=right_now)
self.assertTrue(m2.last_run_at)
e2 = self.Entry(m2)
- self.assertIs(e2.last_run_at, now)
+ self.assertIs(e2.last_run_at, right_now)
e3 = e2.next()
self.assertGreater(e3.last_run_at, e2.last_run_at)
@@ -173,7 +174,7 @@ def test_sync_saves_last_run_at(self):
self.s.sync()
e2 = self.s.schedule[self.m2.name]
- self.assertEqual(e2.last_run_at, last_run2)
+ self.assertEqual(make_aware(e2.last_run_at), last_run2)
def test_sync_syncs_before_save(self):
@@ -195,7 +196,7 @@ def test_sync_syncs_before_save(self):
# and also sync the dirty objects.
e3 = self.s.schedule[self.m2.name]
self.assertEqual(self.s.flushed, 3)
- self.assertEqual(e3.last_run_at, e2.last_run_at)
+ self.assertEqual(make_aware(e3.last_run_at), e2.last_run_at)
self.assertListEqual(e3.args, [16, 16])
def test_sync_not_dirty(self):
@@ -10,6 +10,7 @@
from djcelery import snapshot
from djcelery import models
+from djcelery.utils import now
from djcelery.tests.utils import unittest
_next_id = count(0).next
@@ -71,7 +72,7 @@ def test_handle_task_received(self):
self.assertEqual(mt.name, task.name)
self.assertTrue(unicode(mt))
self.assertTrue(repr(mt))
- mt.eta = datetime.now()
+ mt.eta = now()
self.assertIn("eta", unicode(mt))
self.assertIn(mt, models.TaskState.objects.active())
View
@@ -2,6 +2,7 @@
from datetime import datetime
+from django.conf import settings
from django.utils.translation import ungettext, ugettext as _
JUST_NOW = _("just now")
@@ -26,16 +27,38 @@ def _un(singular__plural, n=None):
singular, plural = singular__plural
return ungettext(singular, plural, n)
+try:
+ from django.utils import timezone
+
+ def make_aware(value):
+ if getattr(settings, "USE_TZ", False):
+ default_tz = timezone.get_default_timezone()
+ value = timezone.make_aware(value, default_tz)
+ return value
+
+ def make_naive(value):
+ if getattr(settings, "USE_TZ", False):
+ default_tz = timezone.get_default_timezone()
+ value = timezone.make_naive(value, default_tz)
+ return value
+
+ def now():
+ return timezone.localtime(timezone.now())
+
+except ImportError:
+ now = datetime.now
+ make_aware = make_naive = lambda x: x
+
def naturaldate(date):
"""Convert datetime into a human natural date string."""
if not date:
return ''
- now = datetime.now()
- today = datetime(now.year, now.month, now.day)
- delta = now - date
+ right_now = now()
+ today = datetime(right_now.year, right_now.month, right_now.day, tzinfo=right_now.tzinfo)
+ delta = right_now - date
delta_midnight = today - date
days = delta.days
View
@@ -67,3 +67,5 @@
)
CELERY_SEND_TASK_ERROR_EMAILS = False
+
+USE_TZ = True
View
@@ -26,3 +26,11 @@ deps = -r{toxinidir}/requirements/default.txt
commands = {toxinidir}/contrib/release/removepyc.sh {toxinidir}
env TOXINIDIR="{toxinidir}" python setup.py citest
+
+[testenv:py27-1.4.X]
+basepython = python2.7
+deps = -r{toxinidir}/requirements/default.txt
+ -r{toxinidir}/requirements/test.txt
+ https://github.com/django/django/zipball/master
+commands = {toxinidir}/contrib/release/removepyc.sh {toxinidir}
+ env TOXINIDIR="{toxinidir}" python setup.py citest

0 comments on commit d437b5a

Please sign in to comment.