Skip to content

Commit

Permalink
Optimized make_aware/naive by removing redundant checks. Refs #22625.
Browse files Browse the repository at this point in the history
Also added tests with pytz and removed misplaced tests.
  • Loading branch information
aaugustin committed May 16, 2014
1 parent fa89acf commit 1109ebd
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 36 deletions.
20 changes: 12 additions & 8 deletions django/utils/timezone.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -351,24 +353,26 @@ 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)


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)
28 changes: 0 additions & 28 deletions tests/timezones/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1120,31 +1120,3 @@ def test_change_readonly_in_other_timezone(self):
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)
)
30 changes: 30 additions & 0 deletions tests/utils_tests/test_timezone.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@
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

Expand All @@ -19,6 +26,10 @@ def test_localtime(self):
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)
Expand Down Expand Up @@ -96,3 +107,22 @@ def test_make_naive(self):
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)

0 comments on commit 1109ebd

Please sign in to comment.