mirror of https://github.com/django/django.git
Fixed #17262 -- Refactored tzinfo implementations.
This commit deprecates django.utils.tzinfo in favor of the more recent django.utils.timezone which was introduced when Django gained support for time zones.
This commit is contained in:
parent
9d700322b3
commit
ec2778b445
|
@ -18,7 +18,8 @@ from django.conf import settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'utc', 'get_default_timezone', 'get_current_timezone',
|
'utc', 'get_fixed_timezone',
|
||||||
|
'get_default_timezone', 'get_current_timezone',
|
||||||
'activate', 'deactivate', 'override',
|
'activate', 'deactivate', 'override',
|
||||||
'is_naive', 'is_aware', 'make_aware', 'make_naive',
|
'is_naive', 'is_aware', 'make_aware', 'make_naive',
|
||||||
]
|
]
|
||||||
|
@ -47,19 +48,45 @@ class UTC(tzinfo):
|
||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
class FixedOffset(tzinfo):
|
||||||
|
"""
|
||||||
|
Fixed offset in minutes east from UTC. Taken from Python's docs.
|
||||||
|
|
||||||
|
Kept as close as possible to the reference version. __init__ was changed
|
||||||
|
to make its arguments optional, according to Python's requirement that
|
||||||
|
tzinfo subclasses can be instantiated without arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, offset=None, name=None):
|
||||||
|
if offset is not None:
|
||||||
|
self.__offset = timedelta(minutes=offset)
|
||||||
|
if name is not None:
|
||||||
|
self.__name = name
|
||||||
|
|
||||||
|
def utcoffset(self, dt):
|
||||||
|
return self.__offset
|
||||||
|
|
||||||
|
def tzname(self, dt):
|
||||||
|
return self.__name
|
||||||
|
|
||||||
|
def dst(self, dt):
|
||||||
|
return ZERO
|
||||||
|
|
||||||
class ReferenceLocalTimezone(tzinfo):
|
class ReferenceLocalTimezone(tzinfo):
|
||||||
"""
|
"""
|
||||||
Local time implementation taken from Python's docs.
|
Local time. Taken from Python's docs.
|
||||||
|
|
||||||
Used only when pytz isn't available, and most likely inaccurate. If you're
|
Used only when pytz isn't available, and most likely inaccurate. If you're
|
||||||
having trouble with this class, don't waste your time, just install pytz.
|
having trouble with this class, don't waste your time, just install pytz.
|
||||||
|
|
||||||
Kept identical to the reference version. Subclasses contain improvements.
|
Kept as close as possible to the reference version. __init__ was added to
|
||||||
|
delay the computation of STDOFFSET, DSTOFFSET and DSTDIFF which is
|
||||||
|
performed at import time in the example.
|
||||||
|
|
||||||
|
Subclasses contain further improvements.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# This code is moved in __init__ to execute it as late as possible
|
|
||||||
# See get_default_timezone().
|
|
||||||
self.STDOFFSET = timedelta(seconds=-_time.timezone)
|
self.STDOFFSET = timedelta(seconds=-_time.timezone)
|
||||||
if _time.daylight:
|
if _time.daylight:
|
||||||
self.DSTOFFSET = timedelta(seconds=-_time.altzone)
|
self.DSTOFFSET = timedelta(seconds=-_time.altzone)
|
||||||
|
@ -68,9 +95,6 @@ class ReferenceLocalTimezone(tzinfo):
|
||||||
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
|
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
|
||||||
tzinfo.__init__(self)
|
tzinfo.__init__(self)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<LocalTimezone>"
|
|
||||||
|
|
||||||
def utcoffset(self, dt):
|
def utcoffset(self, dt):
|
||||||
if self._isdst(dt):
|
if self._isdst(dt):
|
||||||
return self.DSTOFFSET
|
return self.DSTOFFSET
|
||||||
|
@ -84,8 +108,7 @@ class ReferenceLocalTimezone(tzinfo):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
def tzname(self, dt):
|
def tzname(self, dt):
|
||||||
is_dst = False if dt is None else self._isdst(dt)
|
return _time.tzname[self._isdst(dt)]
|
||||||
return _time.tzname[is_dst]
|
|
||||||
|
|
||||||
def _isdst(self, dt):
|
def _isdst(self, dt):
|
||||||
tt = (dt.year, dt.month, dt.day,
|
tt = (dt.year, dt.month, dt.day,
|
||||||
|
@ -103,6 +126,10 @@ class LocalTimezone(ReferenceLocalTimezone):
|
||||||
error message is helpful.
|
error message is helpful.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def tzname(self, dt):
|
||||||
|
is_dst = False if dt is None else self._isdst(dt)
|
||||||
|
return _time.tzname[is_dst]
|
||||||
|
|
||||||
def _isdst(self, dt):
|
def _isdst(self, dt):
|
||||||
try:
|
try:
|
||||||
return super(LocalTimezone, self)._isdst(dt)
|
return super(LocalTimezone, self)._isdst(dt)
|
||||||
|
@ -116,6 +143,17 @@ class LocalTimezone(ReferenceLocalTimezone):
|
||||||
utc = pytz.utc if pytz else UTC()
|
utc = pytz.utc if pytz else UTC()
|
||||||
"""UTC time zone as a tzinfo instance."""
|
"""UTC time zone as a tzinfo instance."""
|
||||||
|
|
||||||
|
def get_fixed_timezone(offset):
|
||||||
|
"""
|
||||||
|
Returns a tzinfo instance with a fixed offset from UTC.
|
||||||
|
"""
|
||||||
|
if isinstance(offset, timedelta):
|
||||||
|
offset = offset.seconds // 60
|
||||||
|
sign = '-' if offset < 0 else '+'
|
||||||
|
hhmm = '%02d%02d' % divmod(abs(offset), 60)
|
||||||
|
name = sign + hhmm
|
||||||
|
return FixedOffset(offset, name)
|
||||||
|
|
||||||
# In order to avoid accessing the settings at compile time,
|
# In order to avoid accessing the settings at compile time,
|
||||||
# wrap the expression in a function and cache the result.
|
# wrap the expression in a function and cache the result.
|
||||||
_localtime = None
|
_localtime = None
|
||||||
|
@ -125,8 +163,6 @@ def get_default_timezone():
|
||||||
Returns the default time zone as a tzinfo instance.
|
Returns the default time zone as a tzinfo instance.
|
||||||
|
|
||||||
This is the time zone defined by settings.TIME_ZONE.
|
This is the time zone defined by settings.TIME_ZONE.
|
||||||
|
|
||||||
See also :func:`get_current_timezone`.
|
|
||||||
"""
|
"""
|
||||||
global _localtime
|
global _localtime
|
||||||
if _localtime is None:
|
if _localtime is None:
|
||||||
|
|
|
@ -2,11 +2,18 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import time
|
|
||||||
from datetime import timedelta, tzinfo
|
from datetime import timedelta, tzinfo
|
||||||
|
import time
|
||||||
|
import warnings
|
||||||
|
|
||||||
from django.utils.encoding import force_str, force_text, DEFAULT_LOCALE_ENCODING
|
from django.utils.encoding import force_str, force_text, DEFAULT_LOCALE_ENCODING
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"django.utils.tzinfo will be removed in Django 1.9. "
|
||||||
|
"Use django.utils.timezone instead.",
|
||||||
|
PendingDeprecationWarning)
|
||||||
|
|
||||||
|
|
||||||
# Python's doc say: "A tzinfo subclass must have an __init__() method that can
|
# Python's doc say: "A tzinfo subclass must have an __init__() method that can
|
||||||
# be called with no arguments". FixedOffset and LocalTimezone don't honor this
|
# be called with no arguments". FixedOffset and LocalTimezone don't honor this
|
||||||
# requirement. Defining __getinitargs__ is sufficient to fix copy/deepcopy as
|
# requirement. Defining __getinitargs__ is sufficient to fix copy/deepcopy as
|
||||||
|
@ -15,6 +22,10 @@ from django.utils.encoding import force_str, force_text, DEFAULT_LOCALE_ENCODING
|
||||||
class FixedOffset(tzinfo):
|
class FixedOffset(tzinfo):
|
||||||
"Fixed offset in minutes east from UTC."
|
"Fixed offset in minutes east from UTC."
|
||||||
def __init__(self, offset):
|
def __init__(self, offset):
|
||||||
|
warnings.warn(
|
||||||
|
"django.utils.tzinfo.FixedOffset will be removed in Django 1.9. "
|
||||||
|
"Use django.utils.timezone.get_fixed_timezone instead.",
|
||||||
|
PendingDeprecationWarning)
|
||||||
if isinstance(offset, timedelta):
|
if isinstance(offset, timedelta):
|
||||||
self.__offset = offset
|
self.__offset = offset
|
||||||
offset = self.__offset.seconds // 60
|
offset = self.__offset.seconds // 60
|
||||||
|
@ -48,6 +59,10 @@ class FixedOffset(tzinfo):
|
||||||
class LocalTimezone(tzinfo):
|
class LocalTimezone(tzinfo):
|
||||||
"Proxy timezone information from time module."
|
"Proxy timezone information from time module."
|
||||||
def __init__(self, dt):
|
def __init__(self, dt):
|
||||||
|
warnings.warn(
|
||||||
|
"django.utils.tzinfo.LocalTimezone will be removed in Django 1.9. "
|
||||||
|
"Use django.utils.timezone.get_default_timezone instead.",
|
||||||
|
PendingDeprecationWarning)
|
||||||
tzinfo.__init__(self)
|
tzinfo.__init__(self)
|
||||||
self.__dt = dt
|
self.__dt = dt
|
||||||
self._tzname = self.tzname(dt)
|
self._tzname = self.tzname(dt)
|
||||||
|
|
|
@ -417,6 +417,8 @@ these changes.
|
||||||
|
|
||||||
* ``django.utils.importlib`` will be removed.
|
* ``django.utils.importlib`` will be removed.
|
||||||
|
|
||||||
|
* ``django.utils.tzinfo`` will be removed.
|
||||||
|
|
||||||
* ``django.utils.unittest`` will be removed.
|
* ``django.utils.unittest`` will be removed.
|
||||||
|
|
||||||
* The ``syncdb`` command will be removed.
|
* The ``syncdb`` command will be removed.
|
||||||
|
|
|
@ -927,6 +927,17 @@ For a complete discussion on the usage of the following see the
|
||||||
|
|
||||||
:class:`~datetime.tzinfo` instance that represents UTC.
|
:class:`~datetime.tzinfo` instance that represents UTC.
|
||||||
|
|
||||||
|
.. function:: get_fixed_timezone(offset)
|
||||||
|
|
||||||
|
.. versionadded:: 1.7
|
||||||
|
|
||||||
|
Returns a :class:`~datetime.tzinfo` instance that represents a time zone
|
||||||
|
with a fixed offset from UTC.
|
||||||
|
|
||||||
|
``offset`` is a :class:`datetime.timedelta` or an integer number of
|
||||||
|
minutes. Use positive values for time zones east of UTC and negative
|
||||||
|
values for west of UTC.
|
||||||
|
|
||||||
.. function:: get_default_timezone()
|
.. function:: get_default_timezone()
|
||||||
|
|
||||||
Returns a :class:`~datetime.tzinfo` instance that represents the
|
Returns a :class:`~datetime.tzinfo` instance that represents the
|
||||||
|
@ -1021,6 +1032,9 @@ For a complete discussion on the usage of the following see the
|
||||||
``django.utils.tzinfo``
|
``django.utils.tzinfo``
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
.. deprecated:: 1.7
|
||||||
|
Use :mod:`~django.utils.timezone` instead.
|
||||||
|
|
||||||
.. module:: django.utils.tzinfo
|
.. module:: django.utils.tzinfo
|
||||||
:synopsis: Implementation of ``tzinfo`` classes for use with ``datetime.datetime``.
|
:synopsis: Implementation of ``tzinfo`` classes for use with ``datetime.datetime``.
|
||||||
|
|
||||||
|
@ -1028,6 +1042,12 @@ For a complete discussion on the usage of the following see the
|
||||||
|
|
||||||
Fixed offset in minutes east from UTC.
|
Fixed offset in minutes east from UTC.
|
||||||
|
|
||||||
|
.. deprecated:: 1.7
|
||||||
|
Use :func:`~django.utils.timezone.get_fixed_timezone` instead.
|
||||||
|
|
||||||
.. class:: LocalTimezone
|
.. class:: LocalTimezone
|
||||||
|
|
||||||
Proxy timezone information from time module.
|
Proxy timezone information from time module.
|
||||||
|
|
||||||
|
.. deprecated:: 1.7
|
||||||
|
Use :func:`~django.utils.timezone.get_default_timezone` instead.
|
||||||
|
|
|
@ -308,6 +308,16 @@ For apps with migrations, ``allow_migrate`` will now get passed
|
||||||
without custom attributes, methods or managers. Make sure your ``allow_migrate``
|
without custom attributes, methods or managers. Make sure your ``allow_migrate``
|
||||||
methods are only referring to fields or other items in ``model._meta``.
|
methods are only referring to fields or other items in ``model._meta``.
|
||||||
|
|
||||||
|
pytz may be required
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If your project handles datetimes before 1970 or after 2037 and Django raises
|
||||||
|
a :exc:`~exceptions.ValueError` when encountering them, you will have to
|
||||||
|
install pytz_. You may be affected by this problem if you use Django's time
|
||||||
|
zone-related date formats or :mod:`django.contrib.syndication`.
|
||||||
|
|
||||||
|
.. _pytz: https://pypi.python.org/pypi/pytz/
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -389,6 +399,15 @@ Features deprecated in 1.7
|
||||||
respectively :mod:`logging.config` and :mod:`importlib` provided for Python
|
respectively :mod:`logging.config` and :mod:`importlib` provided for Python
|
||||||
versions prior to 2.7. They have been deprecated.
|
versions prior to 2.7. They have been deprecated.
|
||||||
|
|
||||||
|
``django.utils.tzinfo``
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
``django.utils.tzinfo`` provided two :class:`~datetime.tzinfo` subclasses,
|
||||||
|
``LocalTimezone`` and ``FixedOffset``. They've been deprecated in favor of
|
||||||
|
more correct alternatives provided by :mod:`django.utils.timezone`,
|
||||||
|
:func:`django.utils.timezone.get_default_timezone` and
|
||||||
|
:func:`django.utils.timezone.get_fixed_timezone`.
|
||||||
|
|
||||||
``django.utils.unittest``
|
``django.utils.unittest``
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.tzinfo import FixedOffset
|
|
||||||
|
|
||||||
from .forms import EventForm, EventSplitForm, EventModelForm
|
from .forms import EventForm, EventSplitForm, EventModelForm
|
||||||
from .models import Event, MaybeEvent, Session, SessionEvent, Timestamp, AllDayEvent
|
from .models import Event, MaybeEvent, Session, SessionEvent, Timestamp, AllDayEvent
|
||||||
|
@ -40,8 +39,8 @@ from .models import Event, MaybeEvent, Session, SessionEvent, Timestamp, AllDayE
|
||||||
# 10:20:30 in UTC and 17:20:30 in ICT.
|
# 10:20:30 in UTC and 17:20:30 in ICT.
|
||||||
|
|
||||||
UTC = timezone.utc
|
UTC = timezone.utc
|
||||||
EAT = FixedOffset(180) # Africa/Nairobi
|
EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi
|
||||||
ICT = FixedOffset(420) # Asia/Bangkok
|
ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok
|
||||||
|
|
||||||
TZ_SUPPORT = hasattr(time, 'tzset')
|
TZ_SUPPORT = hasattr(time, 'tzset')
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,10 @@ import unittest
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.tzinfo import FixedOffset
|
|
||||||
|
|
||||||
|
|
||||||
EAT = FixedOffset(180) # Africa/Nairobi
|
EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi
|
||||||
ICT = FixedOffset(420) # Asia/Bangkok
|
ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok
|
||||||
|
|
||||||
|
|
||||||
class TimezoneTests(unittest.TestCase):
|
class TimezoneTests(unittest.TestCase):
|
||||||
|
|
|
@ -4,10 +4,16 @@ import os
|
||||||
import pickle
|
import pickle
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
import warnings
|
||||||
|
|
||||||
from django.utils.tzinfo import FixedOffset, LocalTimezone
|
from django.test.utils import IgnorePendingDeprecationWarningsMixin
|
||||||
|
|
||||||
class TzinfoTests(unittest.TestCase):
|
# Swallow the import-time warning to test the deprecated implementation.
|
||||||
|
with warnings.catch_warnings():
|
||||||
|
warnings.filterwarnings("ignore", category=PendingDeprecationWarning)
|
||||||
|
from django.utils.tzinfo import FixedOffset, LocalTimezone
|
||||||
|
|
||||||
|
class TzinfoTests(IgnorePendingDeprecationWarningsMixin, unittest.TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
|
|
Loading…
Reference in New Issue