Fixed #25181 -- Added localdate() function to get date in a different time zone.

Thanks Konrad Świat for the original patch.
This commit is contained in:
Jon Dufresne 2016-08-31 17:19:33 -07:00 committed by GitHub
parent d8ef5b0e65
commit ff1e7b4eb4
4 changed files with 65 additions and 5 deletions

View File

@ -299,13 +299,18 @@ def template_localtime(value, use_tz=None):
# Utilities
def localtime(value, timezone=None):
def localtime(value=None, timezone=None):
"""
Converts an aware datetime.datetime to local time.
Only aware datetimes are allowed. When value is omitted, it defaults to
now().
Local time is defined by the current time zone, unless another time zone
is specified.
"""
if value is None:
value = now()
if timezone is None:
timezone = get_current_timezone()
# If `value` is naive, astimezone() will raise a ValueError,
@ -317,6 +322,19 @@ def localtime(value, timezone=None):
return value
def localdate(value=None, timezone=None):
"""
Convert an aware datetime to local time and return the value's date.
Only aware datetimes are allowed. When value is omitted, it defaults to
now().
Local time is defined by the current time zone, unless another time zone is
specified.
"""
return localtime(value, timezone).date()
def now():
"""
Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.

View File

@ -792,6 +792,6 @@ def timezone_today():
Return the current date in the current time zone.
"""
if settings.USE_TZ:
return timezone.localtime(timezone.now()).date()
return timezone.localdate()
else:
return datetime.date.today()

View File

@ -974,14 +974,32 @@ appropriate entities.
``override`` is also usable as a function decorator.
.. function:: localtime(value, timezone=None)
.. function:: localtime(value=None, timezone=None)
Converts an aware :class:`~datetime.datetime` to a different time zone,
by default the :ref:`current time zone <default-current-time-zone>`.
When ``value`` is omitted, it defaults to :func:`now`.
This function doesn't work on naive datetimes; use :func:`make_aware`
instead.
.. versionchanged:: 1.11
In older versions, ``value`` is a required argument.
.. function:: localdate(value=None, timezone=None)
.. versionadded:: 1.11
Uses :func:`localtime` to convert an aware :class:`~datetime.datetime` to a
:meth:`~datetime.datetime.date` in a different time zone, by default the
:ref:`current time zone <default-current-time-zone>`.
When ``value`` is omitted, it defaults to :func:`now`.
This function doesn't work on naive datetimes.
.. function:: now()
Returns a :class:`~datetime.datetime` that represents the

View File

@ -4,7 +4,7 @@ import pickle
import sys
import unittest
from django.test import SimpleTestCase, override_settings
from django.test import SimpleTestCase, mock, override_settings
from django.utils import timezone
try:
@ -27,7 +27,10 @@ class TimezoneTests(SimpleTestCase):
def test_localtime(self):
now = datetime.datetime.utcnow().replace(tzinfo=timezone.utc)
local_tz = timezone.LocalTimezone()
local_now = timezone.localtime(now, local_tz)
with timezone.override(local_tz):
local_now = timezone.localtime(now)
self.assertEqual(local_now.tzinfo, local_tz)
local_now = timezone.localtime(now, timezone=local_tz)
self.assertEqual(local_now.tzinfo, local_tz)
def test_localtime_naive(self):
@ -54,6 +57,27 @@ class TimezoneTests(SimpleTestCase):
with override_settings(USE_TZ=False):
self.assertTrue(timezone.is_naive(timezone.now()))
def test_localdate(self):
naive = datetime.datetime(2015, 1, 1, 0, 0, 1)
if PY36:
self.assertEqual(timezone.localdate(naive), datetime.date(2015, 1, 1))
self.assertEqual(timezone.localdate(naive, timezone=EAT), datetime.date(2015, 1, 1))
else:
with self.assertRaisesMessage(ValueError, 'astimezone() cannot be applied to a naive datetime'):
timezone.localdate(naive)
with self.assertRaisesMessage(ValueError, 'astimezone() cannot be applied to a naive datetime'):
timezone.localdate(naive, timezone=EAT)
aware = datetime.datetime(2015, 1, 1, 0, 0, 1, tzinfo=ICT)
self.assertEqual(timezone.localdate(aware, timezone=EAT), datetime.date(2014, 12, 31))
with timezone.override(EAT):
self.assertEqual(timezone.localdate(aware), datetime.date(2014, 12, 31))
with mock.patch('django.utils.timezone.now', return_value=aware):
self.assertEqual(timezone.localdate(timezone=EAT), datetime.date(2014, 12, 31))
with timezone.override(EAT):
self.assertEqual(timezone.localdate(), datetime.date(2014, 12, 31))
def test_override(self):
default = timezone.get_default_timezone()
try: