1. Mikhail Korobov
  2. django-qsstats-magic

Commits

Mikhail Korobov  committed a297493

django 1.4 timezone support

  • Participants
  • Parent commits 6a5e7c3
  • Branches default

Comments (0)

Files changed (5)

File qsstats/__init__.py

View file
 import datetime
 from dateutil.relativedelta import relativedelta
 from dateutil.parser import parse
+
 from django.db.models import Count
 from django.db import DatabaseError, transaction
 from django.conf import settings
 
-from qsstats.utils import get_bounds, _to_datetime, _parse_interval, get_interval_sql
+from qsstats.utils import get_bounds, _to_datetime, _parse_interval, get_interval_sql, _remove_time
+from qsstats import compat
 from qsstats.exceptions import *
 
 class QuerySetStats(object):
                         filter(**kwargs).order_by().values('d').\
                         annotate(agg=aggregate)
 
-        def to_dt(d): # leave dates as-is
-            return parse(d, yearfirst=True) if isinstance(d, basestring) else d
+        today = _remove_time(compat.now())
+        def to_dt(d):
+            if isinstance(d, basestring):
+                return parse(d, yearfirst=True, default=today)
+            return d
 
         data = dict((to_dt(item['d']), item['agg']) for item in aggregate_data)
 
         return self.pivot(dt, 'lte', date_field, aggregate)
 
     def until_now(self, date_field=None, aggregate=None):
-        return self.pivot(datetime.datetime.now(), 'lte', date_field, aggregate)
+        return self.pivot(compat.now(), 'lte', date_field, aggregate)
 
     def after(self, dt, date_field=None, aggregate=None):
         return self.pivot(dt, 'gte', date_field, aggregate)
 
     def after_now(self, date_field=None, aggregate=None):
-        return self.pivot(datetime.datetime.now(), 'gte', date_field, aggregate)
+        return self.pivot(compat.now(), 'gte', date_field, aggregate)
 
     def pivot(self, dt, operator=None, date_field=None, aggregate=None):
         operator = operator or self.operator
 
     # Utility functions
     def update_today(self):
-        self.today = datetime.date.today()
+        _now = compat.now()
+        self.today = _remove_time(_now)
         return self.today
 
     def _aggregate(self, date_field=None, aggregate=None, filter=None):

File qsstats/compat.py

View file
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+
+import datetime
+try:
+    from django.utils.timezone import now
+except ImportError:
+    now = datetime.datetime.now

File qsstats/tests.py

View file
+from __future__ import absolute_import
 import datetime
 
 from django.test import TestCase
 from django.contrib.auth.models import User
 from qsstats import QuerySetStats, InvalidInterval, DateFieldMissing, QuerySetMissing
+from qsstats import compat
+from .utils import _remove_time
 
 class QuerySetStatsTestCase(TestCase):
     def test_basic_today(self):
         # We should only see a single user
         self.assertEqual(qss.this_day(), 1)
 
-    def test_time_series(self):
-        today = datetime.date.today()
+    def assertTimeSeriesWorks(self, today):
         seven_days_ago = today - datetime.timedelta(days=7)
         for j in range(1,8):
             for i in range(0,j):
         time_series = qss.time_series(seven_days_ago, today)
         self.assertEqual([t[1] for t in time_series], [0, 1, 2, 3, 4, 5, 6, 7])
 
+    def test_time_series(self):
+        _now = compat.now()
+        today = _remove_time(_now)
+        self.assertTimeSeriesWorks(today)
+
+    def test_time_series_naive(self):
+        self.assertTimeSeriesWorks(datetime.date.today())
+
     def test_until(self):
-        today = datetime.date.today()
+        now = compat.now()
+        today = _remove_time(now)
         yesterday = today - datetime.timedelta(days=1)
-        now = datetime.datetime.now()
 
         u = User.objects.create_user('u', 'u@example.com')
         u.date_joined = today
         self.assertEqual(qss.until_now(), 1)
 
     def test_after(self):
-        today = datetime.date.today()
+        now = compat.now()
+        today = _remove_time(now)
         tomorrow = today + datetime.timedelta(days=1)
-        now = datetime.datetime.now()
 
         u = User.objects.create_user('u', 'u@example.com')
         u.date_joined = today

File qsstats/utils.py

View file
 import re
 from dateutil.relativedelta import relativedelta, MO
 from qsstats.exceptions import InvalidInterval, UnsupportedEngine
+from qsstats import compat
 
-def _to_date(dt):
-    return datetime.date(dt.year, dt.month, dt.day)
+def _remove_time(dt):
+    tzinfo = getattr(dt, 'tzinfo', compat.now().tzinfo)
+    return datetime.datetime(dt.year, dt.month, dt.day, tzinfo=tzinfo)
 
 def _to_datetime(dt):
     if isinstance(dt, datetime.datetime):
         return dt
-    return datetime.datetime(dt.year, dt.month, dt.day)
+    return _remove_time(dt)
 
 def _parse_interval(interval):
     num = 1
 def get_bounds(dt, interval):
     ''' Returns interval bounds the datetime is in. '''
 
-    day = _to_datetime(_to_date(dt))
+    day = _to_datetime(_remove_time(dt))
     dt = _to_datetime(dt)
 
     if interval == 'minute':
-        begin = datetime.datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute)
+        begin = datetime.datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, tzinfo=dt.tzinfo)
         end = begin + relativedelta(minutes=1)
     elif interval == 'hour':
-        begin = datetime.datetime(dt.year, dt.month, dt.day, dt.hour)
+        begin = datetime.datetime(dt.year, dt.month, dt.day, dt.hour, tzinfo=dt.tzinfo)
         end = begin + relativedelta(hours=1)
     elif interval == 'day':
         begin = day
         begin = day - relativedelta(weekday=MO(-1))
         end = begin + datetime.timedelta(days=7)
     elif interval == 'month':
-        begin = datetime.datetime(dt.year, dt.month, 1)
+        begin = datetime.datetime(dt.year, dt.month, 1, tzinfo=dt.tzinfo)
         end = begin + relativedelta(months=1)
     elif interval == 'year':
-        begin = datetime.datetime(dt.year, 1, 1)
-        end = datetime.datetime(dt.year+1, 1, 1)
+        begin = datetime.datetime(dt.year, 1, 1, tzinfo=dt.tzinfo)
+        end = datetime.datetime(dt.year+1, 1, 1, tzinfo=dt.tzinfo)
     else:
         raise InvalidInterval('Inverval not supported.')
     end = end - relativedelta(microseconds=1)

File tox.ini

View file
 [tox]
-envlist = py25,py26,py27,pypy,py_django13,py_django12,postgres,mysql,postgres_tz,mysql_tz,sqlite_tz
+envlist = py25, py26, py27, pypy, py_django13, py_django12, postgres, mysql, postgres_tz, mysql_tz, sqlite_tz, mysql_tz_nopytz, postgres_tz_nopytz, sqlite_tz_nopytz
 
 [testenv]
 deps=
     django == 1.4
 
 commands=
-    django-admin.py test qsstats --settings=test_settings.sqlite
+    django-admin.py test qsstats --settings=test_settings.sqlite []
 
 
 
     psycopg2
 
 commands=
-    django-admin.py test qsstats --settings=test_settings.postgres
+    django-admin.py test qsstats --settings=test_settings.postgres []
 
 [testenv:postgres_tz]
 deps=
     python-dateutil == 1.5
     django == 1.4
     psycopg2
+    pytz
 
 commands=
-    django-admin.py test qsstats --settings=test_settings.postgres_tz
+    django-admin.py test qsstats --settings=test_settings.postgres_tz []
+
+[testenv:postgres_tz_nopytz]
+deps=
+    python-dateutil == 1.5
+    django == 1.4
+    psycopg2
+
+commands=
+    django-admin.py test qsstats --settings=test_settings.postgres_tz []
+
+
 
 
 [testenv:mysql]
     mysql-python
 
 commands=
-    django-admin.py test qsstats --settings=test_settings.mysql
+    django-admin.py test qsstats --settings=test_settings.mysql []
 
 [testenv:mysql_tz]
 deps=
     python-dateutil == 1.5
     django == 1.4
+    pytz
+    mysql-python
+
+commands=
+    django-admin.py test qsstats --settings=test_settings.mysql_tz []
+
+[testenv:mysql_tz_nopytz]
+deps=
+    python-dateutil == 1.5
+    django == 1.4
     mysql-python
 
 commands=
-    django-admin.py test qsstats --settings=test_settings.mysql_tz
+    django-admin.py test qsstats --settings=test_settings.mysql_tz []
+
+
 
 
 [testenv:sqlite_tz]
 deps=
     python-dateutil == 1.5
     django == 1.4
+    pytz
 
 commands=
-    django-admin.py test qsstats --settings=test_settings.sqlite_tz
+    django-admin.py test qsstats --settings=test_settings.sqlite_tz []
 
+[testenv:sqlite_tz_nopytz]
+deps=
+    python-dateutil == 1.5
+    django == 1.4
+
+commands=
+    django-admin.py test qsstats --settings=test_settings.sqlite_tz []
+