Loading django/utils/timezone.py +2 −2 Original line number Diff line number Diff line Loading @@ -347,7 +347,7 @@ def is_naive(value): return value.tzinfo is None or value.tzinfo.utcoffset(value) is None def make_aware(value, timezone=None): def make_aware(value, timezone=None, is_dst=None): """ Makes a naive datetime.datetime in a given time zone aware. """ Loading @@ -355,7 +355,7 @@ def make_aware(value, timezone=None): timezone = get_current_timezone() if hasattr(timezone, 'localize'): # This method is available for pytz time zones. return timezone.localize(value, is_dst=None) return timezone.localize(value, is_dst=is_dst) else: # Check that we won't overwrite the timezone of an aware datetime. if is_aware(value): Loading docs/ref/utils.txt +20 −3 Original line number Diff line number Diff line Loading @@ -947,20 +947,37 @@ appropriate entities. Returns ``True`` if ``value`` is naive, ``False`` if it is aware. This function assumes that ``value`` is a :class:`~datetime.datetime`. .. function:: make_aware(value, timezone=None) .. function:: make_aware(value, timezone=None, is_dst=None) Returns an aware :class:`~datetime.datetime` that represents the same point in time as ``value`` in ``timezone``, ``value`` being a naive :class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it defaults to the :ref:`current time zone <default-current-time-zone>`. This function can raise an exception if ``value`` doesn't exist or is ambiguous because of DST transitions. When pytz_ is installed, the exception ``pytz.AmbiguousTimeError`` will be raised if you try to make ``value`` aware during a DST transition where the same time occurs twice (when reverting from DST). Setting ``is_dst`` to ``True`` or ``False`` will avoid the exception by choosing if the time is pre-transition or post-transition respectively. When pytz_ is installed, the exception ``pytz.NonExistentTimeError`` will be raised if you try to make ``value`` aware during a DST transition such that the time never occurred (when entering into DST). Setting ``is_dst`` to ``True`` or ``False`` will avoid the exception by moving the hour backwards or forwards by 1 respectively. For example, ``is_dst=True`` would change a non-existent time of 2:30 to 1:30 and ``is_dst=False`` would change the time to 3:30. ``is_dst`` has no effect when ``pytz`` is not installed. .. versionchanged:: 1.8 In older versions of Django, ``timezone`` was a required argument. .. versionchanged:: 1.9 The ``is_dst`` argument was added. .. function:: make_naive(value, timezone=None) Returns an naive :class:`~datetime.datetime` that represents in Loading docs/releases/1.9.txt +3 −0 Original line number Diff line number Diff line Loading @@ -159,6 +159,9 @@ Internationalization * The :func:`django.views.i18n.javascript_catalog` view now works correctly if used multiple times with different configurations on the same page. * The :func:`django.utils.timezone.make_aware` function gained an ``is_dst`` argument to help resolve ambiguous times during DST transitions. Management Commands ^^^^^^^^^^^^^^^^^^^ Loading tests/utils_tests/test_timezone.py +34 −0 Original line number Diff line number Diff line Loading @@ -155,3 +155,37 @@ class TimezoneTests(unittest.TestCase): datetime.datetime(2011, 9, 1, 12, 20, 30)) with self.assertRaises(ValueError): timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET) @unittest.skipIf(pytz is None, "this test requires pytz") def test_make_aware_pytz_ambiguous(self): # 2:30 happens twice, once before DST ends and once after ambiguous = datetime.datetime(2015, 10, 25, 2, 30) with self.assertRaises(pytz.AmbiguousTimeError): timezone.make_aware(ambiguous, timezone=CET) std = timezone.make_aware(ambiguous, timezone=CET, is_dst=False) dst = timezone.make_aware(ambiguous, timezone=CET, is_dst=True) self.assertEqual(std - dst, datetime.timedelta(hours=1)) self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) @unittest.skipIf(pytz is None, "this test requires pytz") def test_make_aware_pytz_non_existent(self): # 2:30 never happened due to DST non_existent = datetime.datetime(2015, 3, 29, 2, 30) with self.assertRaises(pytz.NonExistentTimeError): timezone.make_aware(non_existent, timezone=CET) std = timezone.make_aware(non_existent, timezone=CET, is_dst=False) dst = timezone.make_aware(non_existent, timezone=CET, is_dst=True) self.assertEqual(std - dst, datetime.timedelta(hours=1)) self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) # round trip to UTC then back to CET std = timezone.localtime(timezone.localtime(std, timezone.UTC()), CET) dst = timezone.localtime(timezone.localtime(dst, timezone.UTC()), CET) self.assertEqual((std.hour, std.minute), (3, 30)) self.assertEqual((dst.hour, dst.minute), (1, 30)) Loading
django/utils/timezone.py +2 −2 Original line number Diff line number Diff line Loading @@ -347,7 +347,7 @@ def is_naive(value): return value.tzinfo is None or value.tzinfo.utcoffset(value) is None def make_aware(value, timezone=None): def make_aware(value, timezone=None, is_dst=None): """ Makes a naive datetime.datetime in a given time zone aware. """ Loading @@ -355,7 +355,7 @@ def make_aware(value, timezone=None): timezone = get_current_timezone() if hasattr(timezone, 'localize'): # This method is available for pytz time zones. return timezone.localize(value, is_dst=None) return timezone.localize(value, is_dst=is_dst) else: # Check that we won't overwrite the timezone of an aware datetime. if is_aware(value): Loading
docs/ref/utils.txt +20 −3 Original line number Diff line number Diff line Loading @@ -947,20 +947,37 @@ appropriate entities. Returns ``True`` if ``value`` is naive, ``False`` if it is aware. This function assumes that ``value`` is a :class:`~datetime.datetime`. .. function:: make_aware(value, timezone=None) .. function:: make_aware(value, timezone=None, is_dst=None) Returns an aware :class:`~datetime.datetime` that represents the same point in time as ``value`` in ``timezone``, ``value`` being a naive :class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it defaults to the :ref:`current time zone <default-current-time-zone>`. This function can raise an exception if ``value`` doesn't exist or is ambiguous because of DST transitions. When pytz_ is installed, the exception ``pytz.AmbiguousTimeError`` will be raised if you try to make ``value`` aware during a DST transition where the same time occurs twice (when reverting from DST). Setting ``is_dst`` to ``True`` or ``False`` will avoid the exception by choosing if the time is pre-transition or post-transition respectively. When pytz_ is installed, the exception ``pytz.NonExistentTimeError`` will be raised if you try to make ``value`` aware during a DST transition such that the time never occurred (when entering into DST). Setting ``is_dst`` to ``True`` or ``False`` will avoid the exception by moving the hour backwards or forwards by 1 respectively. For example, ``is_dst=True`` would change a non-existent time of 2:30 to 1:30 and ``is_dst=False`` would change the time to 3:30. ``is_dst`` has no effect when ``pytz`` is not installed. .. versionchanged:: 1.8 In older versions of Django, ``timezone`` was a required argument. .. versionchanged:: 1.9 The ``is_dst`` argument was added. .. function:: make_naive(value, timezone=None) Returns an naive :class:`~datetime.datetime` that represents in Loading
docs/releases/1.9.txt +3 −0 Original line number Diff line number Diff line Loading @@ -159,6 +159,9 @@ Internationalization * The :func:`django.views.i18n.javascript_catalog` view now works correctly if used multiple times with different configurations on the same page. * The :func:`django.utils.timezone.make_aware` function gained an ``is_dst`` argument to help resolve ambiguous times during DST transitions. Management Commands ^^^^^^^^^^^^^^^^^^^ Loading
tests/utils_tests/test_timezone.py +34 −0 Original line number Diff line number Diff line Loading @@ -155,3 +155,37 @@ class TimezoneTests(unittest.TestCase): datetime.datetime(2011, 9, 1, 12, 20, 30)) with self.assertRaises(ValueError): timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET) @unittest.skipIf(pytz is None, "this test requires pytz") def test_make_aware_pytz_ambiguous(self): # 2:30 happens twice, once before DST ends and once after ambiguous = datetime.datetime(2015, 10, 25, 2, 30) with self.assertRaises(pytz.AmbiguousTimeError): timezone.make_aware(ambiguous, timezone=CET) std = timezone.make_aware(ambiguous, timezone=CET, is_dst=False) dst = timezone.make_aware(ambiguous, timezone=CET, is_dst=True) self.assertEqual(std - dst, datetime.timedelta(hours=1)) self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) @unittest.skipIf(pytz is None, "this test requires pytz") def test_make_aware_pytz_non_existent(self): # 2:30 never happened due to DST non_existent = datetime.datetime(2015, 3, 29, 2, 30) with self.assertRaises(pytz.NonExistentTimeError): timezone.make_aware(non_existent, timezone=CET) std = timezone.make_aware(non_existent, timezone=CET, is_dst=False) dst = timezone.make_aware(non_existent, timezone=CET, is_dst=True) self.assertEqual(std - dst, datetime.timedelta(hours=1)) self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) # round trip to UTC then back to CET std = timezone.localtime(timezone.localtime(std, timezone.UTC()), CET) dst = timezone.localtime(timezone.localtime(dst, timezone.UTC()), CET) self.assertEqual((std.hour, std.minute), (3, 30)) self.assertEqual((dst.hour, dst.minute), (1, 30))