From 3a6040246f16f92c7a45e606822d6940d94eae2a Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Thu, 28 Jun 2018 09:26:41 -0400 Subject: [PATCH] [2.1.x] Fixed #29514 -- Reverted "Used datetime.timezone.utc instead of pytz.utc for better performance." This reverts commit 27ca5ce19f5f184018a61611c1bc319113b1d107 due to a regression. Backport of 2ec151e35da93047acfeea1b79c27010f2cb8594 from master --- django/contrib/sessions/backends/file.py | 5 ++++- django/core/files/storage.py | 6 +++++- django/db/migrations/serializer.py | 2 +- django/utils/feedgenerator.py | 3 ++- django/utils/timezone.py | 14 ++++++++------ 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/django/contrib/sessions/backends/file.py b/django/contrib/sessions/backends/file.py index 9948edf4cf..fe34dea56e 100644 --- a/django/contrib/sessions/backends/file.py +++ b/django/contrib/sessions/backends/file.py @@ -59,7 +59,10 @@ class SessionStore(SessionBase): Return the modification time of the file storing the session's content. """ modification = os.stat(self._key_to_file()).st_mtime - return datetime.datetime.fromtimestamp(modification, timezone.utc if settings.USE_TZ else None) + if settings.USE_TZ: + modification = datetime.datetime.utcfromtimestamp(modification) + return modification.replace(tzinfo=timezone.utc) + return datetime.datetime.fromtimestamp(modification) def _expiry_date(self, session_data): """ diff --git a/django/core/files/storage.py b/django/core/files/storage.py index 1e499ebb1d..30788d6d75 100644 --- a/django/core/files/storage.py +++ b/django/core/files/storage.py @@ -336,7 +336,11 @@ class FileSystemStorage(Storage): If timezone support is enabled, make an aware datetime object in UTC; otherwise make a naive one in the local timezone. """ - return datetime.fromtimestamp(ts, timezone.utc if settings.USE_TZ else None) + if settings.USE_TZ: + # Safe to use .replace() because UTC doesn't have DST + return datetime.utcfromtimestamp(ts).replace(tzinfo=timezone.utc) + else: + return datetime.fromtimestamp(ts) def get_accessed_time(self, name): return self._datetime_from_timestamp(os.path.getatime(self.path(name))) diff --git a/django/db/migrations/serializer.py b/django/db/migrations/serializer.py index 66370cc1d4..9b251e54cd 100644 --- a/django/db/migrations/serializer.py +++ b/django/db/migrations/serializer.py @@ -50,7 +50,7 @@ class DatetimeSerializer(BaseSerializer): def serialize(self): if self.value.tzinfo is not None and self.value.tzinfo != utc: self.value = self.value.astimezone(utc) - value_repr = repr(self.value).replace("datetime.timezone(datetime.timedelta(0), 'UTC')", 'utc') + value_repr = repr(self.value).replace("", "utc") if isinstance(self.value, datetime_safe.datetime): value_repr = "datetime.%s" % value_repr imports = ["import datetime"] diff --git a/django/utils/feedgenerator.py b/django/utils/feedgenerator.py index 319a017e8c..e49f534a19 100644 --- a/django/utils/feedgenerator.py +++ b/django/utils/feedgenerator.py @@ -173,7 +173,8 @@ class SyndicationFeed: if latest_date is None or item_date > latest_date: latest_date = item_date - return latest_date or datetime.datetime.now(utc) + # datetime.now(tz=utc) is slower, as documented in django.utils.timezone.now + return latest_date or datetime.datetime.utcnow().replace(tzinfo=utc) class Enclosure: diff --git a/django/utils/timezone.py b/django/utils/timezone.py index 9870cd03a9..c1f0d70bc1 100644 --- a/django/utils/timezone.py +++ b/django/utils/timezone.py @@ -2,10 +2,9 @@ Timezone-related classes and functions. """ -import datetime import functools from contextlib import ContextDecorator -from datetime import timedelta, tzinfo +from datetime import datetime, timedelta, tzinfo from threading import local import pytz @@ -53,8 +52,7 @@ class FixedOffset(tzinfo): # UTC time zone as a tzinfo instance. -# (Use utc = datetime.timezone.utc here when PY35 isn't supported.) -utc = datetime.timezone(ZERO, 'UTC') +utc = pytz.utc def get_fixed_timezone(offset): @@ -174,7 +172,7 @@ def template_localtime(value, use_tz=None): This function is designed for use by the template engine. """ should_convert = ( - isinstance(value, datetime.datetime) and + isinstance(value, datetime) and (settings.USE_TZ if use_tz is None else use_tz) and not is_naive(value) and getattr(value, 'convert_to_local_time', True) @@ -221,7 +219,11 @@ def now(): """ Return an aware or naive datetime.datetime, depending on settings.USE_TZ. """ - return datetime.datetime.now(utc if settings.USE_TZ else None) + if settings.USE_TZ: + # timeit shows that datetime.now(tz=utc) is 24% slower + return datetime.utcnow().replace(tzinfo=utc) + else: + return datetime.now() # By design, these four functions don't perform any checks on their arguments.