Fixed #17992 -- Added a public API for localtime.
Thanks Bradley Ayers for the report.
This commit is contained in:
parent
5aa51fa999
commit
3e8b40f479
|
@ -290,19 +290,15 @@ class DateFieldListFilter(FieldListFilter):
|
|||
now = timezone.now()
|
||||
# When time zone support is enabled, convert "now" to the user's time
|
||||
# zone so Django's definition of "Today" matches what the user expects.
|
||||
if now.tzinfo is not None:
|
||||
current_tz = timezone.get_current_timezone()
|
||||
now = now.astimezone(current_tz)
|
||||
if hasattr(current_tz, 'normalize'):
|
||||
# available for pytz time zones
|
||||
now = current_tz.normalize(now)
|
||||
if timezone.is_aware(now):
|
||||
now = timezone.localtime(now)
|
||||
|
||||
if isinstance(field, models.DateTimeField):
|
||||
today = now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
else: # field is a models.DateField
|
||||
today = now.date()
|
||||
tomorrow = today + datetime.timedelta(days=1)
|
||||
|
||||
|
||||
self.lookup_kwarg_since = '%s__gte' % field_path
|
||||
self.lookup_kwarg_until = '%s__lt' % field_path
|
||||
self.links = (
|
||||
|
|
|
@ -325,7 +325,7 @@ def display_for_field(value, field):
|
|||
elif value is None:
|
||||
return EMPTY_CHANGELIST_VALUE
|
||||
elif isinstance(field, models.DateTimeField):
|
||||
return formats.localize(timezone.localtime(value))
|
||||
return formats.localize(timezone.template_localtime(value))
|
||||
elif isinstance(field, (models.DateField, models.TimeField)):
|
||||
return formats.localize(value)
|
||||
elif isinstance(field, models.DecimalField):
|
||||
|
@ -345,7 +345,7 @@ def display_for_value(value, boolean=False):
|
|||
elif value is None:
|
||||
return EMPTY_CHANGELIST_VALUE
|
||||
elif isinstance(value, datetime.datetime):
|
||||
return formats.localize(timezone.localtime(value))
|
||||
return formats.localize(timezone.template_localtime(value))
|
||||
elif isinstance(value, (datetime.date, datetime.time)):
|
||||
return formats.localize(value)
|
||||
elif isinstance(value, (decimal.Decimal, float, int, long)):
|
||||
|
|
|
@ -18,7 +18,7 @@ from django.utils.safestring import (SafeData, EscapeData, mark_safe,
|
|||
from django.utils.formats import localize
|
||||
from django.utils.html import escape
|
||||
from django.utils.module_loading import module_has_submodule
|
||||
from django.utils.timezone import localtime
|
||||
from django.utils.timezone import template_localtime
|
||||
|
||||
|
||||
TOKEN_TEXT = 0
|
||||
|
@ -592,7 +592,7 @@ class FilterExpression(object):
|
|||
else:
|
||||
arg_vals.append(arg.resolve(context))
|
||||
if getattr(func, 'expects_localtime', False):
|
||||
obj = localtime(obj, context.use_tz)
|
||||
obj = template_localtime(obj, context.use_tz)
|
||||
if getattr(func, 'needs_autoescape', False):
|
||||
new_obj = func(obj, autoescape=context.autoescape, *arg_vals)
|
||||
else:
|
||||
|
@ -853,7 +853,7 @@ def _render_value_in_context(value, context):
|
|||
means escaping, if required, and conversion to a unicode object. If value
|
||||
is a string, it is expected to have already been translated.
|
||||
"""
|
||||
value = localtime(value, use_tz=context.use_tz)
|
||||
value = template_localtime(value, use_tz=context.use_tz)
|
||||
value = localize(value, use_l10n=context.use_l10n)
|
||||
value = force_unicode(value)
|
||||
if ((context.autoescape and not isinstance(value, SafeData)) or
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.utils.encoding import force_unicode
|
|||
from django.utils.html import escape
|
||||
from django.utils.safestring import SafeData, EscapeData
|
||||
from django.utils.formats import localize
|
||||
from django.utils.timezone import localtime
|
||||
from django.utils.timezone import template_localtime
|
||||
|
||||
|
||||
class DebugLexer(Lexer):
|
||||
|
@ -82,7 +82,7 @@ class DebugVariableNode(VariableNode):
|
|||
def render(self, context):
|
||||
try:
|
||||
output = self.filter_expression.resolve(context)
|
||||
output = localtime(output, use_tz=context.use_tz)
|
||||
output = template_localtime(output, use_tz=context.use_tz)
|
||||
output = localize(output, use_l10n=context.use_l10n)
|
||||
output = force_unicode(output)
|
||||
except UnicodeDecodeError:
|
||||
|
|
|
@ -72,11 +72,7 @@ def do_timezone(value, arg):
|
|||
else:
|
||||
return ''
|
||||
|
||||
# Convert and prevent further conversion
|
||||
result = value.astimezone(tz)
|
||||
if hasattr(tz, 'normalize'):
|
||||
# available for pytz time zones
|
||||
result = tz.normalize(result)
|
||||
result = timezone.localtime(value, tz)
|
||||
|
||||
# HACK: the convert_to_local_time flag will prevent
|
||||
# automatic conversion of the value to local time.
|
||||
|
|
|
@ -206,7 +206,7 @@ class override(object):
|
|||
|
||||
# Templates
|
||||
|
||||
def localtime(value, use_tz=None):
|
||||
def template_localtime(value, use_tz=None):
|
||||
"""
|
||||
Checks if value is a datetime and converts it to local time if necessary.
|
||||
|
||||
|
@ -215,20 +215,30 @@ def localtime(value, use_tz=None):
|
|||
|
||||
This function is designed for use by the template engine.
|
||||
"""
|
||||
if (isinstance(value, datetime)
|
||||
should_convert = (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)):
|
||||
timezone = get_current_timezone()
|
||||
value = value.astimezone(timezone)
|
||||
if hasattr(timezone, 'normalize'):
|
||||
# available for pytz time zones
|
||||
value = timezone.normalize(value)
|
||||
return value
|
||||
and getattr(value, 'convert_to_local_time', True))
|
||||
return localtime(value) if should_convert else value
|
||||
|
||||
|
||||
# Utilities
|
||||
|
||||
def localtime(value, timezone=None):
|
||||
"""
|
||||
Converts an aware datetime.datetime to local time.
|
||||
|
||||
Local time is defined by the current time zone, unless another time zone
|
||||
is specified.
|
||||
"""
|
||||
if timezone is None:
|
||||
timezone = get_current_timezone()
|
||||
value = value.astimezone(timezone)
|
||||
if hasattr(timezone, 'normalize'):
|
||||
# available for pytz time zones
|
||||
value = timezone.normalize(value)
|
||||
return value
|
||||
|
||||
def now():
|
||||
"""
|
||||
Returns an aware or naive datetime.datetime, depending on settings.USE_TZ.
|
||||
|
|
|
@ -666,6 +666,16 @@ For a complete discussion on the usage of the following see the
|
|||
``None``, the :ref:`current time zone <default-current-time-zone>` is unset
|
||||
on entry with :func:`deactivate()` instead.
|
||||
|
||||
.. versionadded:: 1.5
|
||||
|
||||
.. function:: localtime(value, timezone=None)
|
||||
|
||||
Converts an aware :class:`~datetime.datetime` to a different time zone,
|
||||
by default the :ref:`current time zone <default-current-time-zone>`.
|
||||
|
||||
This function doesn't work on naive datetimes; use :func:`make_aware`
|
||||
instead.
|
||||
|
||||
.. function:: now()
|
||||
|
||||
Returns an aware or naive :class:`~datetime.datetime` that represents the
|
||||
|
|
|
@ -41,6 +41,9 @@ Django 1.5 also includes several smaller improvements worth noting:
|
|||
* The template engine now interprets ``True``, ``False`` and ``None`` as the
|
||||
corresponding Python objects.
|
||||
|
||||
* :mod:`django.utils.timezone` provides a helper for converting aware
|
||||
datetimes between time zones, see :func:`~django.utils.timezone.localtime`.
|
||||
|
||||
Backwards incompatible changes in 1.5
|
||||
=====================================
|
||||
|
||||
|
|
|
@ -1,18 +1,33 @@
|
|||
import copy
|
||||
import datetime
|
||||
import pickle
|
||||
from django.utils.timezone import UTC, LocalTimezone
|
||||
from django.test.utils import override_settings
|
||||
from django.utils import timezone
|
||||
from django.utils import unittest
|
||||
|
||||
|
||||
class TimezoneTests(unittest.TestCase):
|
||||
|
||||
def test_localtime(self):
|
||||
now = datetime.datetime.utcnow().replace(tzinfo=timezone.utc)
|
||||
local_tz = timezone.LocalTimezone()
|
||||
local_now = timezone.localtime(now, local_tz)
|
||||
self.assertEqual(local_now.tzinfo, local_tz)
|
||||
|
||||
def test_now(self):
|
||||
with override_settings(USE_TZ=True):
|
||||
self.assertTrue(timezone.is_aware(timezone.now()))
|
||||
with override_settings(USE_TZ=False):
|
||||
self.assertTrue(timezone.is_naive(timezone.now()))
|
||||
|
||||
def test_copy(self):
|
||||
self.assertIsInstance(copy.copy(UTC()), UTC)
|
||||
self.assertIsInstance(copy.copy(LocalTimezone()), LocalTimezone)
|
||||
self.assertIsInstance(copy.copy(timezone.UTC()), timezone.UTC)
|
||||
self.assertIsInstance(copy.copy(timezone.LocalTimezone()), timezone.LocalTimezone)
|
||||
|
||||
def test_deepcopy(self):
|
||||
self.assertIsInstance(copy.deepcopy(UTC()), UTC)
|
||||
self.assertIsInstance(copy.deepcopy(LocalTimezone()), LocalTimezone)
|
||||
self.assertIsInstance(copy.deepcopy(timezone.UTC()), timezone.UTC)
|
||||
self.assertIsInstance(copy.deepcopy(timezone.LocalTimezone()), timezone.LocalTimezone)
|
||||
|
||||
def test_pickling_unpickling(self):
|
||||
self.assertIsInstance(pickle.loads(pickle.dumps(UTC())), UTC)
|
||||
self.assertIsInstance(pickle.loads(pickle.dumps(LocalTimezone())), LocalTimezone)
|
||||
self.assertIsInstance(pickle.loads(pickle.dumps(timezone.UTC())), timezone.UTC)
|
||||
self.assertIsInstance(pickle.loads(pickle.dumps(timezone.LocalTimezone())), timezone.LocalTimezone)
|
||||
|
|
Loading…
Reference in New Issue