From 1109ebd7b373e14b68616346ea5dd3e89a8ae2fe Mon Sep 17 00:00:00 2001 From: Aymeric Augustin Date: Fri, 16 May 2014 23:12:59 +0200 Subject: [PATCH] Optimized make_aware/naive by removing redundant checks. Refs #22625. Also added tests with pytz and removed misplaced tests. --- django/utils/timezone.py | 20 ++++++++++++-------- tests/timezones/tests.py | 28 ---------------------------- tests/utils_tests/test_timezone.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/django/utils/timezone.py b/django/utils/timezone.py index 8138767fb2..0c44d4fd4d 100644 --- a/django/utils/timezone.py +++ b/django/utils/timezone.py @@ -306,9 +306,11 @@ def localtime(value, timezone=None): """ if timezone is None: timezone = get_current_timezone() + # If `value` is naive, astimezone() will raise a ValueError, + # so we don't need to perform a redundant check. value = value.astimezone(timezone) if hasattr(timezone, 'normalize'): - # available for pytz time zones + # This method is available for pytz time zones. value = timezone.normalize(value) return value @@ -351,13 +353,15 @@ def make_aware(value, timezone): """ Makes a naive datetime.datetime in a given time zone aware. """ - if is_aware(value): - raise ValueError("make_aware expects a naive value, got %s" % value) if hasattr(timezone, 'localize'): - # available for pytz time zones + # This method is available for pytz time zones. return timezone.localize(value, is_dst=None) else: - # may be wrong around DST changes + # Check that we won't overwrite the timezone of an aware datetime. + if is_aware(value): + raise ValueError( + "make_aware expects a naive datetime, got %s" % value) + # This may be wrong around DST changes! return value.replace(tzinfo=timezone) @@ -365,10 +369,10 @@ def make_naive(value, timezone): """ Makes an aware datetime.datetime naive in a given time zone. """ - if is_naive(value): - raise ValueError("make_naive expects an aware value, got %s" % value) + # If `value` is naive, astimezone() will raise a ValueError, + # so we don't need to perform a redundant check. value = value.astimezone(timezone) if hasattr(timezone, 'normalize'): - # available for pytz time zones + # This method is available for pytz time zones. value = timezone.normalize(value) return value.replace(tzinfo=None) diff --git a/tests/timezones/tests.py b/tests/timezones/tests.py index d16c7f7fd2..ab9ed6b1a1 100644 --- a/tests/timezones/tests.py +++ b/tests/timezones/tests.py @@ -1120,31 +1120,3 @@ class AdminTests(TestCase): with timezone.override(ICT): response = self.client.get(reverse('admin:timezones_timestamp_change', args=(t.pk,))) self.assertContains(response, t.created.astimezone(ICT).isoformat()) - - -@override_settings(TIME_ZONE='Africa/Nairobi') -class UtilitiesTests(TestCase): - - def test_make_aware(self): - self.assertEqual( - timezone.make_aware(datetime.datetime(2011, 9, 1, 13, 20, 30), EAT), - datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT) - ) - self.assertEqual( - timezone.make_aware(datetime.datetime(2011, 9, 1, 10, 20, 30), UTC), - datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC) - ) - - def test_make_naive(self): - self.assertEqual( - timezone.make_naive(datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), EAT), - datetime.datetime(2011, 9, 1, 13, 20, 30) - ) - self.assertEqual( - timezone.make_naive(datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), UTC), - datetime.datetime(2011, 9, 1, 10, 20, 30) - ) - self.assertEqual( - timezone.make_naive(datetime.datetime(2011, 9, 1, 10, 20, 30, tzinfo=UTC), UTC), - datetime.datetime(2011, 9, 1, 10, 20, 30) - ) diff --git a/tests/utils_tests/test_timezone.py b/tests/utils_tests/test_timezone.py index 4b5a39a928..aec58e394f 100644 --- a/tests/utils_tests/test_timezone.py +++ b/tests/utils_tests/test_timezone.py @@ -3,10 +3,17 @@ import datetime import pickle import unittest +try: + import pytz +except ImportError: + pytz = None + from django.test import override_settings from django.utils import timezone +if pytz is not None: + CET = pytz.timezone("Europe/Paris") EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok @@ -19,6 +26,10 @@ class TimezoneTests(unittest.TestCase): local_now = timezone.localtime(now, local_tz) self.assertEqual(local_now.tzinfo, local_tz) + def test_localtime_naive(self): + with self.assertRaises(ValueError): + timezone.localtime(datetime.datetime.now()) + def test_localtime_out_of_range(self): local_tz = timezone.LocalTimezone() long_ago = datetime.datetime(1900, 1, 1, tzinfo=timezone.utc) @@ -96,3 +107,22 @@ class TimezoneTests(unittest.TestCase): datetime.datetime(2011, 9, 1, 13, 20, 30)) with self.assertRaises(ValueError): timezone.make_naive(datetime.datetime(2011, 9, 1, 13, 20, 30), EAT) + + @unittest.skipIf(pytz is None, "this test requires pytz") + def test_make_aware(self): + self.assertEqual( + timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30), CET), + CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30))) + with self.assertRaises(ValueError): + timezone.make_aware(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET) + + @unittest.skipIf(pytz is None, "this test requires pytz") + def test_make_aware_pytz(self): + self.assertEqual( + timezone.make_naive(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET), + datetime.datetime(2011, 9, 1, 12, 20, 30)) + self.assertEqual( + timezone.make_naive(pytz.timezone("Asia/Bangkok").localize(datetime.datetime(2011, 9, 1, 17, 20, 30)), CET), + datetime.datetime(2011, 9, 1, 12, 20, 30)) + with self.assertRaises(ValueError): + timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET)