From 06d9b82a27a4e47b435805938af23360e4291fb4 Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Thu, 13 Oct 2011 19:23:45 +0000 Subject: [PATCH] Fixed #16906 -- Format datetimes with str/unicode instead of strftime where possible: it's faster and it works for all dates. Also ensured that datetime_safe is used wherever strftime is called on dates/datetimes that may be before 1900. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16978 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/filters.py | 8 ++++---- django/contrib/auth/tokens.py | 7 +++---- django/contrib/sitemaps/tests/basic.py | 8 ++++---- django/db/backends/__init__.py | 5 ++--- django/db/backends/sqlite3/base.py | 11 +++-------- django/db/models/fields/__init__.py | 8 +++----- tests/regressiontests/admin_filters/tests.py | 6 +++--- 7 files changed, 22 insertions(+), 31 deletions(-) diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py index d356c6a1d1..261ba7a02a 100644 --- a/django/contrib/admin/filters.py +++ b/django/contrib/admin/filters.py @@ -281,9 +281,9 @@ class DateFieldListFilter(FieldListFilter): today = datetime.date.today() one_week_ago = today - datetime.timedelta(days=7) - today_str = (isinstance(self.field, models.DateTimeField) - and today.strftime('%Y-%m-%d 23:59:59') - or today.strftime('%Y-%m-%d')) + today_str = str(today) + if isinstance(self.field, models.DateTimeField): + today_str += ' 23:59:59' self.lookup_kwarg_year = '%s__year' % self.field_path self.lookup_kwarg_month = '%s__month' % self.field_path @@ -299,7 +299,7 @@ class DateFieldListFilter(FieldListFilter): self.lookup_kwarg_day: str(today.day), }), (_('Past 7 days'), { - self.lookup_kwarg_past_7_days_gte: one_week_ago.strftime('%Y-%m-%d'), + self.lookup_kwarg_past_7_days_gte: str(one_week_ago), self.lookup_kwarg_past_7_days_lte: today_str, }), (_('This month'), { diff --git a/django/contrib/auth/tokens.py b/django/contrib/auth/tokens.py index db614135c0..a75ef61e51 100644 --- a/django/contrib/auth/tokens.py +++ b/django/contrib/auth/tokens.py @@ -52,14 +52,13 @@ class PasswordResetTokenGenerator(object): # invalid as soon as it is used. # We limit the hash to 20 chars to keep URL short key_salt = "django.contrib.auth.tokens.PasswordResetTokenGenerator" - value = unicode(user.id) + \ - user.password + user.last_login.strftime('%Y-%m-%d %H:%M:%S') + \ - unicode(timestamp) + value = (unicode(user.id) + user.password + + unicode(user.last_login) + unicode(timestamp)) hash = salted_hmac(key_salt, value).hexdigest()[::2] return "%s-%s" % (ts_b36, hash) def _num_days(self, dt): - return (dt - date(2001,1,1)).days + return (dt - date(2001, 1, 1)).days def _today(self): # Used for mocking in tests diff --git a/django/contrib/sitemaps/tests/basic.py b/django/contrib/sitemaps/tests/basic.py index 2b02b78741..775e0d9736 100644 --- a/django/contrib/sitemaps/tests/basic.py +++ b/django/contrib/sitemaps/tests/basic.py @@ -67,7 +67,7 @@ class SitemapTests(TestCase): %s/location/%snever0.5 -""" % (self.base_url, date.today().strftime('%Y-%m-%d'))) +""" % (self.base_url, date.today())) def test_simple_custom_sitemap(self): "A simple sitemap can be rendered with a custom template" @@ -79,7 +79,7 @@ class SitemapTests(TestCase): %s/location/%snever0.5 -""" % (self.base_url, date.today().strftime('%Y-%m-%d'))) +""" % (self.base_url, date.today())) @skipUnless(settings.USE_I18N, "Internationalization is not enabled") def test_localized_priority(self): @@ -93,7 +93,7 @@ class SitemapTests(TestCase): # haven't been rendered in localized format response = self.client.get('/simple/sitemap.xml') self.assertContains(response, '0.5') - self.assertContains(response, '%s' % date.today().strftime('%Y-%m-%d')) + self.assertContains(response, '%s' % date.today()) deactivate() def test_generic_sitemap(self): @@ -152,7 +152,7 @@ class SitemapTests(TestCase): http://testserver/location/%snever0.5 -""" % date.today().strftime('%Y-%m-%d')) +""" % date.today()) @skipUnless("django.contrib.sites" in settings.INSTALLED_APPS, "django.contrib.sites app not installed.") def test_sitemap_get_urls_no_site_1(self): diff --git a/django/db/backends/__init__.py b/django/db/backends/__init__.py index 9afc143460..5e96fefd05 100644 --- a/django/db/backends/__init__.py +++ b/django/db/backends/__init__.py @@ -9,7 +9,6 @@ from django.conf import settings from django.db import DEFAULT_DB_ALIAS from django.db.backends import util from django.db.transaction import TransactionManagementError -from django.utils import datetime_safe from django.utils.importlib import import_module @@ -718,7 +717,7 @@ class BaseDatabaseOperations(object): """ if value is None: return None - return datetime_safe.new_date(value).strftime('%Y-%m-%d') + return unicode(value) def value_to_db_datetime(self, value): """ @@ -731,7 +730,7 @@ class BaseDatabaseOperations(object): def value_to_db_time(self, value): """ - Transform a datetime value to an object compatible with what is expected + Transform a time value to an object compatible with what is expected by the backend driver for time columns. """ if value is None: diff --git a/django/db/backends/sqlite3/base.py b/django/db/backends/sqlite3/base.py index 49b87a8da8..c437f1517e 100644 --- a/django/db/backends/sqlite3/base.py +++ b/django/db/backends/sqlite3/base.py @@ -320,14 +320,9 @@ def _sqlite_format_dtdelta(dt, conn, days, secs, usecs): dt = dt - delta except (ValueError, TypeError): return None - - if isinstance(dt, datetime.datetime): - rv = dt.strftime("%Y-%m-%d %H:%M:%S") - if dt.microsecond: - rv = "%s.%0.6d" % (rv, dt.microsecond) - else: - rv = dt.strftime("%Y-%m-%d") - return rv + # typecast_timestamp returns a date or a datetime without timezone. + # It will be formatted as "%Y-%m-%d" or "%Y-%m-%d %H:%M:%S[.%f]" + return str(dt) def _sqlite_regexp(re_pattern, re_string): try: diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 67acbbae76..55b993af02 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -16,7 +16,6 @@ from django.utils.functional import curry from django.utils.text import capfirst from django.utils.translation import ugettext_lazy as _ from django.utils.encoding import smart_unicode, force_unicode, smart_str -from django.utils import datetime_safe from django.utils.ipv6 import clean_ipv6_address class NOT_PROVIDED: @@ -725,7 +724,7 @@ class DateField(Field): if val is None: data = '' else: - data = datetime_safe.new_date(val).strftime("%Y-%m-%d") + data = str(val) return data def formfield(self, **kwargs): @@ -803,8 +802,7 @@ class DateTimeField(DateField): if val is None: data = '' else: - d = datetime_safe.new_datetime(val) - data = d.strftime('%Y-%m-%d %H:%M:%S') + data = str(val.replace(microsecond=0, tzinfo=None)) return data def formfield(self, **kwargs): @@ -1234,7 +1232,7 @@ class TimeField(Field): if val is None: data = '' else: - data = val.strftime("%H:%M:%S") + data = str(val.replace(microsecond=0)) return data def formfield(self, **kwargs): diff --git a/tests/regressiontests/admin_filters/tests.py b/tests/regressiontests/admin_filters/tests.py index fdbd4375c1..e276e55a35 100644 --- a/tests/regressiontests/admin_filters/tests.py +++ b/tests/regressiontests/admin_filters/tests.py @@ -188,8 +188,8 @@ class ListFiltersTests(TestCase): self.assertEqual(choice['query_string'], '?date_registered__year=%s' % (self.today.year)) - request = self.request_factory.get('/', {'date_registered__gte': self.one_week_ago.strftime('%Y-%m-%d'), - 'date_registered__lte': self.today.strftime('%Y-%m-%d')}) + request = self.request_factory.get('/', {'date_registered__gte': str(self.one_week_ago), + 'date_registered__lte': str(self.today)}) changelist = self.get_changelist(request, Book, modeladmin) # Make sure the correct queryset is returned @@ -203,7 +203,7 @@ class ListFiltersTests(TestCase): self.assertEqual(choice['selected'], True) self.assertEqual(choice['query_string'], '?date_registered__gte=%s' '&date_registered__lte=%s' - % (self.one_week_ago.strftime('%Y-%m-%d'), self.today.strftime('%Y-%m-%d'))) + % (str(self.one_week_ago), str(self.today))) def test_allvaluesfieldlistfilter(self): modeladmin = BookAdmin(Book, site)