Fixed #27327 -- Simplified time zone handling by requiring pytz.
This commit is contained in:
parent
d84ffcc22b
commit
414ad25b09
|
@ -4,6 +4,8 @@ import warnings
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.db import DEFAULT_DB_ALIAS
|
from django.db import DEFAULT_DB_ALIAS
|
||||||
|
@ -16,11 +18,6 @@ from django.utils import timezone
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.six.moves import _thread as thread
|
from django.utils.six.moves import _thread as thread
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
NO_DB_ALIAS = '__no_db__'
|
NO_DB_ALIAS = '__no_db__'
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +125,6 @@ class BaseDatabaseWrapper(object):
|
||||||
elif self.settings_dict['TIME_ZONE'] is None:
|
elif self.settings_dict['TIME_ZONE'] is None:
|
||||||
return timezone.utc
|
return timezone.utc
|
||||||
else:
|
else:
|
||||||
# Only this branch requires pytz.
|
|
||||||
return pytz.timezone(self.settings_dict['TIME_ZONE'])
|
return pytz.timezone(self.settings_dict['TIME_ZONE'])
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
@ -207,10 +203,6 @@ class BaseDatabaseWrapper(object):
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
"Connection '%s' cannot set TIME_ZONE because its engine "
|
"Connection '%s' cannot set TIME_ZONE because its engine "
|
||||||
"handles time zones conversions natively." % self.alias)
|
"handles time zones conversions natively." % self.alias)
|
||||||
elif pytz is None:
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
"Connection '%s' cannot set TIME_ZONE because pytz isn't "
|
|
||||||
"installed." % self.alias)
|
|
||||||
|
|
||||||
def ensure_connection(self):
|
def ensure_connection(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -3,11 +3,6 @@ from django.utils.functional import cached_property
|
||||||
|
|
||||||
from .base import Database
|
from .base import Database
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
empty_fetchmany_value = ()
|
empty_fetchmany_value = ()
|
||||||
|
@ -56,14 +51,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def has_zoneinfo_database(self):
|
def has_zoneinfo_database(self):
|
||||||
# MySQL accepts full time zones names (eg. Africa/Nairobi) but rejects
|
|
||||||
# abbreviations (eg. EAT). When pytz isn't installed and the current
|
|
||||||
# time zone is LocalTimezone (the only sensible value in this
|
|
||||||
# context), the current time zone name will be an abbreviation. As a
|
|
||||||
# consequence, MySQL cannot perform time zone conversions reliably.
|
|
||||||
if pytz is None:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Test if the time zone definitions are installed.
|
# Test if the time zone definitions are installed.
|
||||||
with self.connection.cursor() as cursor:
|
with self.connection.cursor() as cursor:
|
||||||
cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1")
|
cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1")
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
from django.db.backends.base.features import BaseDatabaseFeatures
|
from django.db.backends.base.features import BaseDatabaseFeatures
|
||||||
from django.db.utils import InterfaceError
|
from django.db.utils import InterfaceError
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
empty_fetchmany_value = ()
|
empty_fetchmany_value = ()
|
||||||
|
@ -19,7 +14,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
supports_subqueries_in_group_by = False
|
supports_subqueries_in_group_by = False
|
||||||
supports_transactions = True
|
supports_transactions = True
|
||||||
supports_timezones = False
|
supports_timezones = False
|
||||||
has_zoneinfo_database = pytz is not None
|
|
||||||
supports_bitwise_or = False
|
supports_bitwise_or = False
|
||||||
has_native_duration_field = True
|
has_native_duration_field = True
|
||||||
can_defer_constraint_checks = True
|
can_defer_constraint_checks = True
|
||||||
|
|
|
@ -11,6 +11,8 @@ import decimal
|
||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import utils
|
from django.db import utils
|
||||||
from django.db.backends import utils as backend_utils
|
from django.db.backends import utils as backend_utils
|
||||||
|
@ -23,11 +25,6 @@ from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.safestring import SafeBytes
|
from django.utils.safestring import SafeBytes
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
from pysqlite2 import dbapi2 as Database
|
from pysqlite2 import dbapi2 as Database
|
||||||
|
|
|
@ -7,11 +7,6 @@ from django.utils.functional import cached_property
|
||||||
|
|
||||||
from .base import Database
|
from .base import Database
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
# SQLite cannot handle us only partially reading from a cursor's result set
|
# SQLite cannot handle us only partially reading from a cursor's result set
|
||||||
|
@ -78,7 +73,3 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
has_support = False
|
has_support = False
|
||||||
cursor.execute('DROP TABLE STDDEV_TEST')
|
cursor.execute('DROP TABLE STDDEV_TEST')
|
||||||
return has_support
|
return has_support
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def has_zoneinfo_database(self):
|
|
||||||
return pytz is not None
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import datetime
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import FieldError, ImproperlyConfigured
|
from django.core.exceptions import FieldError
|
||||||
from django.db import utils
|
from django.db import utils
|
||||||
from django.db.backends import utils as backend_utils
|
from django.db.backends import utils as backend_utils
|
||||||
from django.db.backends.base.operations import BaseDatabaseOperations
|
from django.db.backends.base.operations import BaseDatabaseOperations
|
||||||
|
@ -13,11 +13,6 @@ from django.utils import six, timezone
|
||||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||||
from django.utils.duration import duration_string
|
from django.utils.duration import duration_string
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseOperations(BaseDatabaseOperations):
|
class DatabaseOperations(BaseDatabaseOperations):
|
||||||
def bulk_batch_size(self, fields, objs):
|
def bulk_batch_size(self, fields, objs):
|
||||||
|
@ -77,27 +72,19 @@ class DatabaseOperations(BaseDatabaseOperations):
|
||||||
# cause a collision with a field name).
|
# cause a collision with a field name).
|
||||||
return "django_time_trunc('%s', %s)" % (lookup_type.lower(), field_name)
|
return "django_time_trunc('%s', %s)" % (lookup_type.lower(), field_name)
|
||||||
|
|
||||||
def _require_pytz(self):
|
|
||||||
if settings.USE_TZ and pytz is None:
|
|
||||||
raise ImproperlyConfigured("This query requires pytz, but it isn't installed.")
|
|
||||||
|
|
||||||
def datetime_cast_date_sql(self, field_name, tzname):
|
def datetime_cast_date_sql(self, field_name, tzname):
|
||||||
self._require_pytz()
|
|
||||||
return "django_datetime_cast_date(%s, %%s)" % field_name, [tzname]
|
return "django_datetime_cast_date(%s, %%s)" % field_name, [tzname]
|
||||||
|
|
||||||
def datetime_cast_time_sql(self, field_name, tzname):
|
def datetime_cast_time_sql(self, field_name, tzname):
|
||||||
self._require_pytz()
|
|
||||||
return "django_datetime_cast_time(%s, %%s)" % field_name, [tzname]
|
return "django_datetime_cast_time(%s, %%s)" % field_name, [tzname]
|
||||||
|
|
||||||
def datetime_extract_sql(self, lookup_type, field_name, tzname):
|
def datetime_extract_sql(self, lookup_type, field_name, tzname):
|
||||||
# Same comment as in date_extract_sql.
|
# Same comment as in date_extract_sql.
|
||||||
self._require_pytz()
|
|
||||||
return "django_datetime_extract('%s', %s, %%s)" % (
|
return "django_datetime_extract('%s', %s, %%s)" % (
|
||||||
lookup_type.lower(), field_name), [tzname]
|
lookup_type.lower(), field_name), [tzname]
|
||||||
|
|
||||||
def datetime_trunc_sql(self, lookup_type, field_name, tzname):
|
def datetime_trunc_sql(self, lookup_type, field_name, tzname):
|
||||||
# Same comment as in date_trunc_sql.
|
# Same comment as in date_trunc_sql.
|
||||||
self._require_pytz()
|
|
||||||
return "django_datetime_trunc('%s', %s, %%s)" % (
|
return "django_datetime_trunc('%s', %s, %%s)" % (
|
||||||
lookup_type.lower(), field_name), [tzname]
|
lookup_type.lower(), field_name), [tzname]
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@ class TruncBase(TimezoneMixin, Transform):
|
||||||
if value is None:
|
if value is None:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Database returned an invalid datetime value. "
|
"Database returned an invalid datetime value. "
|
||||||
"Are time zone definitions for your database and pytz installed?"
|
"Are time zone definitions for your database installed?"
|
||||||
)
|
)
|
||||||
value = value.replace(tzinfo=None)
|
value = value.replace(tzinfo=None)
|
||||||
value = timezone.make_aware(value, self.tzinfo)
|
value = timezone.make_aware(value, self.tzinfo)
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
from datetime import datetime, tzinfo
|
from datetime import datetime, tzinfo
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.template import Library, Node, TemplateSyntaxError
|
from django.template import Library, Node, TemplateSyntaxError
|
||||||
from django.utils import six, timezone
|
from django.utils import six, timezone
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,7 +40,6 @@ def do_timezone(value, arg):
|
||||||
Converts a datetime to local time in a given time zone.
|
Converts a datetime to local time in a given time zone.
|
||||||
|
|
||||||
The argument must be an instance of a tzinfo subclass or a time zone name.
|
The argument must be an instance of a tzinfo subclass or a time zone name.
|
||||||
If it is a time zone name, pytz is required.
|
|
||||||
|
|
||||||
Naive datetimes are assumed to be in local time in the default time zone.
|
Naive datetimes are assumed to be in local time in the default time zone.
|
||||||
"""
|
"""
|
||||||
|
@ -64,7 +59,7 @@ def do_timezone(value, arg):
|
||||||
# Obtain a tzinfo instance
|
# Obtain a tzinfo instance
|
||||||
if isinstance(arg, tzinfo):
|
if isinstance(arg, tzinfo):
|
||||||
tz = arg
|
tz = arg
|
||||||
elif isinstance(arg, six.string_types) and pytz is not None:
|
elif isinstance(arg, six.string_types):
|
||||||
try:
|
try:
|
||||||
tz = pytz.timezone(arg)
|
tz = pytz.timezone(arg)
|
||||||
except pytz.UnknownTimeZoneError:
|
except pytz.UnknownTimeZoneError:
|
||||||
|
@ -156,8 +151,8 @@ def timezone_tag(parser, token):
|
||||||
Enables a given time zone just for this block.
|
Enables a given time zone just for this block.
|
||||||
|
|
||||||
The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
|
The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
|
||||||
time zone name, or ``None``. If is it a time zone name, pytz is required.
|
time zone name, or ``None``. If it is ``None``, the default time zone is
|
||||||
If it is ``None``, the default time zone is used within the block.
|
used within the block.
|
||||||
|
|
||||||
Sample usage::
|
Sample usage::
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,16 @@
|
||||||
"""
|
"""
|
||||||
Timezone-related classes and functions.
|
Timezone-related classes and functions.
|
||||||
|
|
||||||
This module uses pytz when it's available and fallbacks when it isn't.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
import time as _time
|
|
||||||
from datetime import datetime, timedelta, tzinfo
|
from datetime import datetime, timedelta, tzinfo
|
||||||
from threading import local
|
from threading import local
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import lru_cache, six
|
from django.utils import lru_cache, six
|
||||||
from django.utils.decorators import ContextDecorator
|
from django.utils.decorators import ContextDecorator
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'utc', 'get_fixed_timezone',
|
'utc', 'get_fixed_timezone',
|
||||||
'get_default_timezone', 'get_default_timezone_name',
|
'get_default_timezone', 'get_default_timezone_name',
|
||||||
|
@ -34,26 +26,6 @@ __all__ = [
|
||||||
ZERO = timedelta(0)
|
ZERO = timedelta(0)
|
||||||
|
|
||||||
|
|
||||||
class UTC(tzinfo):
|
|
||||||
"""
|
|
||||||
UTC implementation taken from Python's docs.
|
|
||||||
|
|
||||||
Used only when pytz isn't available.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "<UTC>"
|
|
||||||
|
|
||||||
def utcoffset(self, dt):
|
|
||||||
return ZERO
|
|
||||||
|
|
||||||
def tzname(self, dt):
|
|
||||||
return "UTC"
|
|
||||||
|
|
||||||
def dst(self, dt):
|
|
||||||
return ZERO
|
|
||||||
|
|
||||||
|
|
||||||
class FixedOffset(tzinfo):
|
class FixedOffset(tzinfo):
|
||||||
"""
|
"""
|
||||||
Fixed offset in minutes east from UTC. Taken from Python's docs.
|
Fixed offset in minutes east from UTC. Taken from Python's docs.
|
||||||
|
@ -78,79 +50,7 @@ class FixedOffset(tzinfo):
|
||||||
def dst(self, dt):
|
def dst(self, dt):
|
||||||
return ZERO
|
return ZERO
|
||||||
|
|
||||||
|
utc = pytz.utc
|
||||||
class ReferenceLocalTimezone(tzinfo):
|
|
||||||
"""
|
|
||||||
Local time. Taken from Python's docs.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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):
|
|
||||||
self.STDOFFSET = timedelta(seconds=-_time.timezone)
|
|
||||||
if _time.daylight:
|
|
||||||
self.DSTOFFSET = timedelta(seconds=-_time.altzone)
|
|
||||||
else:
|
|
||||||
self.DSTOFFSET = self.STDOFFSET
|
|
||||||
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
|
|
||||||
tzinfo.__init__(self)
|
|
||||||
|
|
||||||
def utcoffset(self, dt):
|
|
||||||
if self._isdst(dt):
|
|
||||||
return self.DSTOFFSET
|
|
||||||
else:
|
|
||||||
return self.STDOFFSET
|
|
||||||
|
|
||||||
def dst(self, dt):
|
|
||||||
if self._isdst(dt):
|
|
||||||
return self.DSTDIFF
|
|
||||||
else:
|
|
||||||
return ZERO
|
|
||||||
|
|
||||||
def tzname(self, dt):
|
|
||||||
return _time.tzname[self._isdst(dt)]
|
|
||||||
|
|
||||||
def _isdst(self, dt):
|
|
||||||
tt = (dt.year, dt.month, dt.day,
|
|
||||||
dt.hour, dt.minute, dt.second,
|
|
||||||
dt.weekday(), 0, 0)
|
|
||||||
stamp = _time.mktime(tt)
|
|
||||||
tt = _time.localtime(stamp)
|
|
||||||
return tt.tm_isdst > 0
|
|
||||||
|
|
||||||
|
|
||||||
class LocalTimezone(ReferenceLocalTimezone):
|
|
||||||
"""
|
|
||||||
Slightly improved local time implementation focusing on correctness.
|
|
||||||
|
|
||||||
It still crashes on dates before 1970 or after 2038, but at least the
|
|
||||||
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):
|
|
||||||
try:
|
|
||||||
return super(LocalTimezone, self)._isdst(dt)
|
|
||||||
except (OverflowError, ValueError) as exc:
|
|
||||||
exc_type = type(exc)
|
|
||||||
exc_value = exc_type(
|
|
||||||
"Unsupported value: %r. You should install pytz." % dt)
|
|
||||||
exc_value.__cause__ = exc
|
|
||||||
if not hasattr(exc, '__traceback__'):
|
|
||||||
exc.__traceback__ = sys.exc_info()[2]
|
|
||||||
six.reraise(exc_type, exc_value, sys.exc_info()[2])
|
|
||||||
|
|
||||||
utc = pytz.utc if pytz else UTC()
|
|
||||||
"""UTC time zone as a tzinfo instance."""
|
"""UTC time zone as a tzinfo instance."""
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,11 +75,7 @@ def get_default_timezone():
|
||||||
|
|
||||||
This is the time zone defined by settings.TIME_ZONE.
|
This is the time zone defined by settings.TIME_ZONE.
|
||||||
"""
|
"""
|
||||||
if isinstance(settings.TIME_ZONE, six.string_types) and pytz is not None:
|
return pytz.timezone(settings.TIME_ZONE)
|
||||||
return pytz.timezone(settings.TIME_ZONE)
|
|
||||||
else:
|
|
||||||
# This relies on os.environ['TZ'] being set to settings.TIME_ZONE.
|
|
||||||
return LocalTimezone()
|
|
||||||
|
|
||||||
|
|
||||||
# This function exists for consistency with get_current_timezone_name
|
# This function exists for consistency with get_current_timezone_name
|
||||||
|
@ -228,11 +124,11 @@ def activate(timezone):
|
||||||
Sets the time zone for the current thread.
|
Sets the time zone for the current thread.
|
||||||
|
|
||||||
The ``timezone`` argument must be an instance of a tzinfo subclass or a
|
The ``timezone`` argument must be an instance of a tzinfo subclass or a
|
||||||
time zone name. If it is a time zone name, pytz is required.
|
time zone name.
|
||||||
"""
|
"""
|
||||||
if isinstance(timezone, tzinfo):
|
if isinstance(timezone, tzinfo):
|
||||||
_active.value = timezone
|
_active.value = timezone
|
||||||
elif isinstance(timezone, six.string_types) and pytz is not None:
|
elif isinstance(timezone, six.string_types):
|
||||||
_active.value = pytz.timezone(timezone)
|
_active.value = pytz.timezone(timezone)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid timezone: %r" % timezone)
|
raise ValueError("Invalid timezone: %r" % timezone)
|
||||||
|
@ -257,8 +153,8 @@ class override(ContextDecorator):
|
||||||
on exit.
|
on exit.
|
||||||
|
|
||||||
The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
|
The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
|
||||||
time zone name, or ``None``. If is it a time zone name, pytz is required.
|
time zone name, or ``None``. If it is ``None``, Django enables the default
|
||||||
If it is ``None``, Django enables the default time zone.
|
time zone.
|
||||||
"""
|
"""
|
||||||
def __init__(self, timezone):
|
def __init__(self, timezone):
|
||||||
self.timezone = timezone
|
self.timezone = timezone
|
||||||
|
|
|
@ -117,9 +117,9 @@ Imports
|
||||||
|
|
||||||
# try/except
|
# try/except
|
||||||
try:
|
try:
|
||||||
import pytz
|
import yaml
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pytz = None
|
yaml = None
|
||||||
|
|
||||||
CONSTANT = 'foo'
|
CONSTANT = 'foo'
|
||||||
|
|
||||||
|
|
|
@ -232,7 +232,7 @@ dependencies:
|
||||||
* numpy_
|
* numpy_
|
||||||
* Pillow_
|
* Pillow_
|
||||||
* PyYAML_
|
* PyYAML_
|
||||||
* pytz_
|
* pytz_ (required)
|
||||||
* setuptools_
|
* setuptools_
|
||||||
* memcached_, plus a :ref:`supported Python binding <memcached>`
|
* memcached_, plus a :ref:`supported Python binding <memcached>`
|
||||||
* mock_ (for Python 2)
|
* mock_ (for Python 2)
|
||||||
|
|
|
@ -758,11 +758,11 @@ object. If it's ``None``, Django uses the :ref:`current time zone
|
||||||
As a consequence, your database must be able to interpret the value of
|
As a consequence, your database must be able to interpret the value of
|
||||||
``tzinfo.tzname(None)``. This translates into the following requirements:
|
``tzinfo.tzname(None)``. This translates into the following requirements:
|
||||||
|
|
||||||
- SQLite: install pytz_ — conversions are actually performed in Python.
|
- SQLite: no requirements. Conversions are performed in Python with pytz_
|
||||||
|
(installed when you install Django).
|
||||||
- PostgreSQL: no requirements (see `Time Zones`_).
|
- PostgreSQL: no requirements (see `Time Zones`_).
|
||||||
- Oracle: no requirements (see `Choosing a Time Zone File`_).
|
- Oracle: no requirements (see `Choosing a Time Zone File`_).
|
||||||
- MySQL: install pytz_ and load the time zone tables with
|
- MySQL: load the time zone tables with `mysql_tzinfo_to_sql`_.
|
||||||
`mysql_tzinfo_to_sql`_.
|
|
||||||
|
|
||||||
.. _pytz: http://pytz.sourceforge.net/
|
.. _pytz: http://pytz.sourceforge.net/
|
||||||
.. _Time Zones: https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-TIMEZONES
|
.. _Time Zones: https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-TIMEZONES
|
||||||
|
|
|
@ -607,8 +607,6 @@ This allows interacting with third-party databases that store datetimes in
|
||||||
local time rather than UTC. To avoid issues around DST changes, you shouldn't
|
local time rather than UTC. To avoid issues around DST changes, you shouldn't
|
||||||
set this option for databases managed by Django.
|
set this option for databases managed by Django.
|
||||||
|
|
||||||
Setting this option requires installing pytz_.
|
|
||||||
|
|
||||||
When :setting:`USE_TZ` is ``True`` and the database doesn't support time zones
|
When :setting:`USE_TZ` is ``True`` and the database doesn't support time zones
|
||||||
(e.g. SQLite, MySQL, Oracle), Django reads and writes datetimes in local time
|
(e.g. SQLite, MySQL, Oracle), Django reads and writes datetimes in local time
|
||||||
according to this option if it is set and in UTC if it isn't.
|
according to this option if it is set and in UTC if it isn't.
|
||||||
|
@ -618,8 +616,6 @@ PostgreSQL), it is an error to set this option.
|
||||||
|
|
||||||
When :setting:`USE_TZ` is ``False``, it is an error to set this option.
|
When :setting:`USE_TZ` is ``False``, it is an error to set this option.
|
||||||
|
|
||||||
.. _pytz: http://pytz.sourceforge.net/
|
|
||||||
|
|
||||||
.. setting:: USER
|
.. setting:: USER
|
||||||
|
|
||||||
``USER``
|
``USER``
|
||||||
|
@ -2478,8 +2474,8 @@ See also :setting:`DATE_INPUT_FORMATS` and :setting:`DATETIME_INPUT_FORMATS`.
|
||||||
|
|
||||||
Default: ``'America/Chicago'``
|
Default: ``'America/Chicago'``
|
||||||
|
|
||||||
A string representing the time zone for this installation, or ``None``. See
|
A string representing the time zone for this installation. See the `list of
|
||||||
the `list of time zones`_.
|
time zones`_.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Since Django was first released with the :setting:`TIME_ZONE` set to
|
Since Django was first released with the :setting:`TIME_ZONE` set to
|
||||||
|
@ -2496,22 +2492,15 @@ will store all datetimes. When :setting:`USE_TZ` is ``True``, this is the
|
||||||
default time zone that Django will use to display datetimes in templates and
|
default time zone that Django will use to display datetimes in templates and
|
||||||
to interpret datetimes entered in forms.
|
to interpret datetimes entered in forms.
|
||||||
|
|
||||||
Django sets the ``os.environ['TZ']`` variable to the time zone you specify in
|
On Unix environments (where :func:`time.tzset` is implemented), Django sets the
|
||||||
the :setting:`TIME_ZONE` setting. Thus, all your views and models will
|
``os.environ['TZ']`` variable to the time zone you specify in the
|
||||||
|
:setting:`TIME_ZONE` setting. Thus, all your views and models will
|
||||||
automatically operate in this time zone. However, Django won't set the ``TZ``
|
automatically operate in this time zone. However, Django won't set the ``TZ``
|
||||||
environment variable under the following conditions:
|
environment variable if you're using the manual configuration option as
|
||||||
|
described in :ref:`manually configuring settings
|
||||||
* If you're using the manual configuration option as described in
|
<settings-without-django-settings-module>`. If Django doesn't set the ``TZ``
|
||||||
:ref:`manually configuring settings
|
environment variable, it's up to you to ensure your processes are running in
|
||||||
<settings-without-django-settings-module>`, or
|
the correct environment.
|
||||||
|
|
||||||
* If you specify ``TIME_ZONE = None``. This will cause Django to fall back to
|
|
||||||
using the system timezone. However, this is discouraged when :setting:`USE_TZ
|
|
||||||
= True <USE_TZ>`, because it makes conversions between local time and UTC
|
|
||||||
less reliable.
|
|
||||||
|
|
||||||
If Django doesn't set the ``TZ`` environment variable, it's up to you
|
|
||||||
to ensure your processes are running in the correct environment.
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Django cannot reliably use alternate time zones in a Windows environment.
|
Django cannot reliably use alternate time zones in a Windows environment.
|
||||||
|
|
|
@ -966,7 +966,7 @@ appropriate entities.
|
||||||
|
|
||||||
Sets the :ref:`current time zone <default-current-time-zone>`. The
|
Sets the :ref:`current time zone <default-current-time-zone>`. The
|
||||||
``timezone`` argument must be an instance of a :class:`~datetime.tzinfo`
|
``timezone`` argument must be an instance of a :class:`~datetime.tzinfo`
|
||||||
subclass or, if pytz_ is available, a time zone name.
|
subclass or a time zone name.
|
||||||
|
|
||||||
.. function:: deactivate()
|
.. function:: deactivate()
|
||||||
|
|
||||||
|
@ -1043,21 +1043,18 @@ appropriate entities.
|
||||||
:class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it
|
:class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it
|
||||||
defaults to the :ref:`current time zone <default-current-time-zone>`.
|
defaults to the :ref:`current time zone <default-current-time-zone>`.
|
||||||
|
|
||||||
When pytz_ is installed, the exception ``pytz.AmbiguousTimeError``
|
The ``pytz.AmbiguousTimeError`` exception is raised if you try to make
|
||||||
will be raised if you try to make ``value`` aware during a DST transition
|
``value`` aware during a DST transition where the same time occurs twice
|
||||||
where the same time occurs twice (when reverting from DST). Setting
|
(when reverting from DST). Setting ``is_dst`` to ``True`` or ``False`` will
|
||||||
``is_dst`` to ``True`` or ``False`` will avoid the exception by choosing if
|
avoid the exception by choosing if the time is pre-transition or
|
||||||
the time is pre-transition or post-transition respectively.
|
post-transition respectively.
|
||||||
|
|
||||||
When pytz_ is installed, the exception ``pytz.NonExistentTimeError``
|
The ``pytz.NonExistentTimeError`` exception is raised if you try to make
|
||||||
will be raised if you try to make ``value`` aware during a DST transition
|
``value`` aware during a DST transition such that the time never occurred
|
||||||
such that the time never occurred (when entering into DST). Setting
|
(when entering into DST). Setting ``is_dst`` to ``True`` or ``False`` will
|
||||||
``is_dst`` to ``True`` or ``False`` will avoid the exception by moving the
|
avoid the exception by moving the hour backwards or forwards by 1
|
||||||
hour backwards or forwards by 1 respectively. For example, ``is_dst=True``
|
respectively. For example, ``is_dst=True`` would change a non-existent
|
||||||
would change a non-existent time of 2:30 to 1:30 and ``is_dst=False``
|
time of 2:30 to 1:30 and ``is_dst=False`` would change the time to 3:30.
|
||||||
would change the time to 3:30.
|
|
||||||
|
|
||||||
``is_dst`` has no effect when ``pytz`` is not installed.
|
|
||||||
|
|
||||||
.. function:: make_naive(value, timezone=None)
|
.. function:: make_naive(value, timezone=None)
|
||||||
|
|
||||||
|
@ -1066,8 +1063,6 @@ appropriate entities.
|
||||||
aware :class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it
|
aware :class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it
|
||||||
defaults to the :ref:`current time zone <default-current-time-zone>`.
|
defaults to the :ref:`current time zone <default-current-time-zone>`.
|
||||||
|
|
||||||
.. _pytz: http://pytz.sourceforge.net/
|
|
||||||
|
|
||||||
``django.utils.translation``
|
``django.utils.translation``
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
|
|
@ -468,6 +468,27 @@ To prevent typos from passing silently,
|
||||||
arguments are model fields. This should be backwards-incompatible only in the
|
arguments are model fields. This should be backwards-incompatible only in the
|
||||||
fact that it might expose a bug in your project.
|
fact that it might expose a bug in your project.
|
||||||
|
|
||||||
|
``pytz`` is a required dependency and support for ``settings.TIME_ZONE = None`` is removed
|
||||||
|
------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
To simplify Django's timezone handling, ``pytz`` is now a required dependency.
|
||||||
|
It's automatically installed along with Django.
|
||||||
|
|
||||||
|
Support for ``settings.TIME_ZONE = None`` is removed as the behavior isn't
|
||||||
|
commonly used and is questionably useful. If you want to automatically detect
|
||||||
|
the timezone based on the system timezone, you can use `tzlocal
|
||||||
|
<https://pypi.python.org/pypi/tzlocal>`_::
|
||||||
|
|
||||||
|
from tzlocal import get_localzone
|
||||||
|
|
||||||
|
TIME_ZONE = get_localzone().zone
|
||||||
|
|
||||||
|
This works similar to ``settings.TIME_ZONE = None`` except that it also sets
|
||||||
|
``os.environ['TZ']``. `Let us know
|
||||||
|
<https://groups.google.com/d/topic/django-developers/OAV3FChfuPM/discussion>`__
|
||||||
|
if there's a use case where you find you can't adapt your code to set a
|
||||||
|
``TIME_ZONE``.
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
@ -622,7 +622,6 @@ Pygments
|
||||||
pysqlite
|
pysqlite
|
||||||
pythonic
|
pythonic
|
||||||
Pythonista
|
Pythonista
|
||||||
pytz
|
|
||||||
qs
|
qs
|
||||||
Québec
|
Québec
|
||||||
queryset
|
queryset
|
||||||
|
|
|
@ -26,14 +26,12 @@ to this problem is to use UTC in the code and use local time only when
|
||||||
interacting with end users.
|
interacting with end users.
|
||||||
|
|
||||||
Time zone support is disabled by default. To enable it, set :setting:`USE_TZ =
|
Time zone support is disabled by default. To enable it, set :setting:`USE_TZ =
|
||||||
True <USE_TZ>` in your settings file. Installing pytz_ is highly recommended,
|
True <USE_TZ>` in your settings file. Time zone support uses pytz_, which is
|
||||||
but may not be mandatory depending on your particular database backend,
|
installed when you install Django.
|
||||||
operating system and time zone. If you encounter an exception querying dates
|
|
||||||
or times, please try installing it before filing a bug. It's as simple as:
|
|
||||||
|
|
||||||
.. code-block:: console
|
.. versionchanged:: 1.11
|
||||||
|
|
||||||
$ pip install pytz
|
Older versions don't require ``pytz`` or install it automatically.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -113,11 +111,8 @@ receives one, it attempts to make it aware by interpreting it in the
|
||||||
:ref:`default time zone <default-current-time-zone>` and raises a warning.
|
:ref:`default time zone <default-current-time-zone>` and raises a warning.
|
||||||
|
|
||||||
Unfortunately, during DST transitions, some datetimes don't exist or are
|
Unfortunately, during DST transitions, some datetimes don't exist or are
|
||||||
ambiguous. In such situations, pytz_ raises an exception. Other
|
ambiguous. In such situations, pytz_ raises an exception. That's why you should
|
||||||
:class:`~datetime.tzinfo` implementations, such as the local time zone used as
|
always create aware datetime objects when time zone support is enabled.
|
||||||
a fallback when pytz_ isn't installed, may raise an exception or return
|
|
||||||
inaccurate results. That's why you should always create aware datetime objects
|
|
||||||
when time zone support is enabled.
|
|
||||||
|
|
||||||
In practice, this is rarely an issue. Django gives you aware datetime objects
|
In practice, this is rarely an issue. Django gives you aware datetime objects
|
||||||
in the models and forms, and most often, new datetime objects are created from
|
in the models and forms, and most often, new datetime objects are created from
|
||||||
|
@ -360,7 +355,7 @@ For example::
|
||||||
Forces conversion of a single value to an arbitrary timezone.
|
Forces conversion of a single value to an arbitrary timezone.
|
||||||
|
|
||||||
The argument must be an instance of a :class:`~datetime.tzinfo` subclass or a
|
The argument must be an instance of a :class:`~datetime.tzinfo` subclass or a
|
||||||
time zone name. If it is a time zone name, pytz_ is required.
|
time zone name.
|
||||||
|
|
||||||
For example::
|
For example::
|
||||||
|
|
||||||
|
@ -405,9 +400,8 @@ Code
|
||||||
----
|
----
|
||||||
|
|
||||||
The first step is to add :setting:`USE_TZ = True <USE_TZ>` to your settings
|
The first step is to add :setting:`USE_TZ = True <USE_TZ>` to your settings
|
||||||
file and install pytz_ (if possible). At this point, things should mostly
|
file. At this point, things should mostly work. If you create naive datetime
|
||||||
work. If you create naive datetime objects in your code, Django makes them
|
objects in your code, Django makes them aware when necessary.
|
||||||
aware when necessary.
|
|
||||||
|
|
||||||
However, these conversions may fail around DST transitions, which means you
|
However, these conversions may fail around DST transitions, which means you
|
||||||
aren't getting the full benefits of time zone support yet. Also, you're likely
|
aren't getting the full benefits of time zone support yet. Also, you're likely
|
||||||
|
@ -523,22 +517,7 @@ Setup
|
||||||
one year is 2011-02-28 or 2011-03-01, which depends on your business
|
one year is 2011-02-28 or 2011-03-01, which depends on your business
|
||||||
requirements.)
|
requirements.)
|
||||||
|
|
||||||
3. **Should I install pytz?**
|
3. **How do I interact with a database that stores datetimes in local time?**
|
||||||
|
|
||||||
Yes. Django has a policy of not requiring external dependencies, and for
|
|
||||||
this reason pytz_ is optional. However, it's much safer to install it.
|
|
||||||
|
|
||||||
As soon as you activate time zone support, Django needs a definition of the
|
|
||||||
default time zone. When pytz is available, Django loads this definition
|
|
||||||
from the `tz database`_. This is the most accurate solution. Otherwise, it
|
|
||||||
relies on the difference between local time and UTC, as reported by the
|
|
||||||
operating system, to compute conversions. This is less reliable, especially
|
|
||||||
around DST transitions.
|
|
||||||
|
|
||||||
Furthermore, if you want to support users in more than one time zone, pytz
|
|
||||||
is the reference for time zone definitions.
|
|
||||||
|
|
||||||
4. **How do I interact with a database that stores datetimes in local time?**
|
|
||||||
|
|
||||||
Set the :setting:`TIME_ZONE <DATABASE-TIME_ZONE>` option to the appropriate
|
Set the :setting:`TIME_ZONE <DATABASE-TIME_ZONE>` option to the appropriate
|
||||||
time zone for this database in the :setting:`DATABASES` setting.
|
time zone for this database in the :setting:`DATABASES` setting.
|
||||||
|
@ -653,8 +632,8 @@ Troubleshooting
|
||||||
>>> local.date()
|
>>> local.date()
|
||||||
datetime.date(2012, 3, 3)
|
datetime.date(2012, 3, 3)
|
||||||
|
|
||||||
4. **I get an error** "``Are time zone definitions for your database and pytz
|
4. **I get an error** "``Are time zone definitions for your database
|
||||||
installed?``" **pytz is installed, so I guess the problem is my database?**
|
installed?``"
|
||||||
|
|
||||||
If you are using MySQL, see the :ref:`mysql-time-zone-definitions` section
|
If you are using MySQL, see the :ref:`mysql-time-zone-definitions` section
|
||||||
of the MySQL notes for instructions on loading time zone definitions.
|
of the MySQL notes for instructions on loading time zone definitions.
|
||||||
|
@ -700,8 +679,7 @@ Usage
|
||||||
>>> timezone.localtime(timezone.now())
|
>>> timezone.localtime(timezone.now())
|
||||||
datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
|
datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
|
||||||
|
|
||||||
In this example, pytz_ is installed and the current time zone is
|
In this example, the current time zone is ``"Europe/Paris"``.
|
||||||
``"Europe/Paris"``.
|
|
||||||
|
|
||||||
3. **How can I see all available time zones?**
|
3. **How can I see all available time zones?**
|
||||||
|
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -47,6 +47,7 @@ setup(
|
||||||
entry_points={'console_scripts': [
|
entry_points={'console_scripts': [
|
||||||
'django-admin = django.core.management:execute_from_command_line',
|
'django-admin = django.core.management:execute_from_command_line',
|
||||||
]},
|
]},
|
||||||
|
install_requires=['pytz'],
|
||||||
extras_require={
|
extras_require={
|
||||||
"bcrypt": ["bcrypt"],
|
"bcrypt": ["bcrypt"],
|
||||||
"argon2": ["argon2-cffi >= 16.1.0"],
|
"argon2": ["argon2-cffi >= 16.1.0"],
|
||||||
|
|
|
@ -5,7 +5,8 @@ import gettext
|
||||||
import os
|
import os
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from unittest import skipIf
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -23,11 +24,6 @@ from django.utils import six, translation
|
||||||
from . import models
|
from . import models
|
||||||
from .widgetadmin import site as widget_admin_site
|
from .widgetadmin import site as widget_admin_site
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
class TestDataMixin(object):
|
class TestDataMixin(object):
|
||||||
|
|
||||||
|
@ -794,7 +790,6 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase):
|
||||||
self.wait_for_text('#calendarin0 caption', expected_caption)
|
self.wait_for_text('#calendarin0 caption', expected_caption)
|
||||||
|
|
||||||
|
|
||||||
@skipIf(pytz is None, "this test requires pytz")
|
|
||||||
@override_settings(TIME_ZONE='Asia/Singapore')
|
@override_settings(TIME_ZONE='Asia/Singapore')
|
||||||
class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase):
|
class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase):
|
||||||
|
|
||||||
|
|
|
@ -1832,17 +1832,16 @@ class CacheI18nTest(TestCase):
|
||||||
|
|
||||||
@override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True)
|
@override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True)
|
||||||
def test_cache_key_with_non_ascii_tzname(self):
|
def test_cache_key_with_non_ascii_tzname(self):
|
||||||
# Regression test for #17476
|
# Timezone-dependent cache keys should use ASCII characters only
|
||||||
class CustomTzName(timezone.UTC):
|
# (#17476). The implementation here is a bit odd (timezone.utc is an
|
||||||
name = ''
|
# instance, not a class), but it simulates the correct conditions.
|
||||||
|
class CustomTzName(timezone.utc):
|
||||||
def tzname(self, dt):
|
pass
|
||||||
return self.name
|
|
||||||
|
|
||||||
request = self.factory.get(self.path)
|
request = self.factory.get(self.path)
|
||||||
response = HttpResponse()
|
response = HttpResponse()
|
||||||
with timezone.override(CustomTzName()):
|
with timezone.override(CustomTzName):
|
||||||
CustomTzName.name = 'Hora estándar de Argentina'.encode('UTF-8') # UTF-8 string
|
CustomTzName.zone = 'Hora estándar de Argentina'.encode('UTF-8') # UTF-8 string
|
||||||
sanitized_name = 'Hora_estndar_de_Argentina'
|
sanitized_name = 'Hora_estndar_de_Argentina'
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
sanitized_name, learn_cache_key(request, response),
|
sanitized_name, learn_cache_key(request, response),
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from unittest import skipIf
|
|
||||||
|
|
||||||
from django.test import TestCase, override_settings
|
from django.test import TestCase, override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from .models import Article, Category, Comment
|
from .models import Article, Category, Comment
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
class DateTimesTests(TestCase):
|
class DateTimesTests(TestCase):
|
||||||
def test_related_model_traverse(self):
|
def test_related_model_traverse(self):
|
||||||
|
@ -84,7 +78,6 @@ class DateTimesTests(TestCase):
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipIf(pytz is None, "this test requires pytz")
|
|
||||||
@override_settings(USE_TZ=True)
|
@override_settings(USE_TZ=True)
|
||||||
def test_21432(self):
|
def test_21432(self):
|
||||||
now = timezone.localtime(timezone.now().replace(microsecond=0))
|
now = timezone.localtime(timezone.now().replace(microsecond=0))
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from unittest import skipIf
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
|
@ -16,11 +17,6 @@ from django.utils import timezone
|
||||||
|
|
||||||
from .models import DTModel
|
from .models import DTModel
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
def microsecond_support(value):
|
def microsecond_support(value):
|
||||||
return value if connection.features.supports_microsecond_precision else value.replace(microsecond=0)
|
return value if connection.features.supports_microsecond_precision else value.replace(microsecond=0)
|
||||||
|
@ -659,7 +655,6 @@ class DateFunctionTests(TestCase):
|
||||||
list(DTModel.objects.annotate(truncated=TruncSecond('start_date', output_field=DateField())))
|
list(DTModel.objects.annotate(truncated=TruncSecond('start_date', output_field=DateField())))
|
||||||
|
|
||||||
|
|
||||||
@skipIf(pytz is None, "this test requires pytz")
|
|
||||||
@override_settings(USE_TZ=True, TIME_ZONE='UTC')
|
@override_settings(USE_TZ=True, TIME_ZONE='UTC')
|
||||||
class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
class DateFunctionWithTimeZoneTests(DateFunctionTests):
|
||||||
|
|
||||||
|
|
|
@ -32,12 +32,6 @@ from django.utils.six.moves.urllib.request import urlopen
|
||||||
|
|
||||||
from .models import Storage, temp_storage, temp_storage_location
|
from .models import Storage, temp_storage, temp_storage_location
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
FILE_SUFFIX_REGEX = '[A-Za-z0-9]{7}'
|
FILE_SUFFIX_REGEX = '[A-Za-z0-9]{7}'
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,10 +93,6 @@ class FileSystemStorageTests(unittest.TestCase):
|
||||||
storage.url(storage.base_url)
|
storage.url(storage.base_url)
|
||||||
|
|
||||||
|
|
||||||
# Tests for TZ-aware time methods need pytz.
|
|
||||||
requires_pytz = unittest.skipIf(pytz is None, "this test requires pytz")
|
|
||||||
|
|
||||||
|
|
||||||
class FileStorageTests(SimpleTestCase):
|
class FileStorageTests(SimpleTestCase):
|
||||||
storage_class = FileSystemStorage
|
storage_class = FileSystemStorage
|
||||||
|
|
||||||
|
@ -157,7 +147,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
# different.
|
# different.
|
||||||
now_in_algiers = timezone.make_aware(datetime.now())
|
now_in_algiers = timezone.make_aware(datetime.now())
|
||||||
|
|
||||||
# Use a fixed offset timezone so we don't need pytz.
|
|
||||||
with timezone.override(timezone.get_fixed_timezone(-300)):
|
with timezone.override(timezone.get_fixed_timezone(-300)):
|
||||||
# At this point the system TZ is +1 and the Django TZ
|
# At this point the system TZ is +1 and the Django TZ
|
||||||
# is -5. The following will be aware in UTC.
|
# is -5. The following will be aware in UTC.
|
||||||
|
@ -191,7 +180,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
# different.
|
# different.
|
||||||
now_in_algiers = timezone.make_aware(datetime.now())
|
now_in_algiers = timezone.make_aware(datetime.now())
|
||||||
|
|
||||||
# Use a fixed offset timezone so we don't need pytz.
|
|
||||||
with timezone.override(timezone.get_fixed_timezone(-300)):
|
with timezone.override(timezone.get_fixed_timezone(-300)):
|
||||||
# At this point the system TZ is +1 and the Django TZ
|
# At this point the system TZ is +1 and the Django TZ
|
||||||
# is -5.
|
# is -5.
|
||||||
|
@ -220,7 +208,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
_dt = timezone.make_aware(dt, now_in_algiers.tzinfo)
|
_dt = timezone.make_aware(dt, now_in_algiers.tzinfo)
|
||||||
self.assertLess(abs(_dt - now_in_algiers), timedelta(seconds=2))
|
self.assertLess(abs(_dt - now_in_algiers), timedelta(seconds=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_file_get_accessed_time(self):
|
def test_file_get_accessed_time(self):
|
||||||
"""
|
"""
|
||||||
File storage returns a Datetime object for the last accessed time of
|
File storage returns a Datetime object for the last accessed time of
|
||||||
|
@ -236,7 +223,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
self.assertEqual(atime, datetime.fromtimestamp(os.path.getatime(self.storage.path(f_name))))
|
self.assertEqual(atime, datetime.fromtimestamp(os.path.getatime(self.storage.path(f_name))))
|
||||||
self.assertLess(timezone.now() - self.storage.get_accessed_time(f_name), timedelta(seconds=2))
|
self.assertLess(timezone.now() - self.storage.get_accessed_time(f_name), timedelta(seconds=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
@requires_tz_support
|
@requires_tz_support
|
||||||
def test_file_get_accessed_time_timezone(self):
|
def test_file_get_accessed_time_timezone(self):
|
||||||
self._test_file_time_getter(self.storage.get_accessed_time)
|
self._test_file_time_getter(self.storage.get_accessed_time)
|
||||||
|
@ -256,7 +242,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
self.assertEqual(atime, datetime.fromtimestamp(os.path.getatime(self.storage.path(f_name))))
|
self.assertEqual(atime, datetime.fromtimestamp(os.path.getatime(self.storage.path(f_name))))
|
||||||
self.assertLess(datetime.now() - self.storage.accessed_time(f_name), timedelta(seconds=2))
|
self.assertLess(datetime.now() - self.storage.accessed_time(f_name), timedelta(seconds=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_file_get_created_time(self):
|
def test_file_get_created_time(self):
|
||||||
"""
|
"""
|
||||||
File storage returns a datetime for the creation time of a file.
|
File storage returns a datetime for the creation time of a file.
|
||||||
|
@ -271,7 +256,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
self.assertEqual(ctime, datetime.fromtimestamp(os.path.getctime(self.storage.path(f_name))))
|
self.assertEqual(ctime, datetime.fromtimestamp(os.path.getctime(self.storage.path(f_name))))
|
||||||
self.assertLess(timezone.now() - self.storage.get_created_time(f_name), timedelta(seconds=2))
|
self.assertLess(timezone.now() - self.storage.get_created_time(f_name), timedelta(seconds=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
@requires_tz_support
|
@requires_tz_support
|
||||||
def test_file_get_created_time_timezone(self):
|
def test_file_get_created_time_timezone(self):
|
||||||
self._test_file_time_getter(self.storage.get_created_time)
|
self._test_file_time_getter(self.storage.get_created_time)
|
||||||
|
@ -291,7 +275,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
self.assertEqual(ctime, datetime.fromtimestamp(os.path.getctime(self.storage.path(f_name))))
|
self.assertEqual(ctime, datetime.fromtimestamp(os.path.getctime(self.storage.path(f_name))))
|
||||||
self.assertLess(datetime.now() - self.storage.created_time(f_name), timedelta(seconds=2))
|
self.assertLess(datetime.now() - self.storage.created_time(f_name), timedelta(seconds=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_file_get_modified_time(self):
|
def test_file_get_modified_time(self):
|
||||||
"""
|
"""
|
||||||
File storage returns a datetime for the last modified time of a file.
|
File storage returns a datetime for the last modified time of a file.
|
||||||
|
@ -306,7 +289,6 @@ class FileStorageTests(SimpleTestCase):
|
||||||
self.assertEqual(mtime, datetime.fromtimestamp(os.path.getmtime(self.storage.path(f_name))))
|
self.assertEqual(mtime, datetime.fromtimestamp(os.path.getmtime(self.storage.path(f_name))))
|
||||||
self.assertLess(timezone.now() - self.storage.get_modified_time(f_name), timedelta(seconds=2))
|
self.assertLess(timezone.now() - self.storage.get_modified_time(f_name), timedelta(seconds=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
@requires_tz_support
|
@requires_tz_support
|
||||||
def test_file_get_modified_time_timezone(self):
|
def test_file_get_modified_time_timezone(self):
|
||||||
self._test_file_time_getter(self.storage.get_modified_time)
|
self._test_file_time_getter(self.storage.get_modified_time)
|
||||||
|
|
|
@ -2,7 +2,6 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from unittest import skipIf
|
|
||||||
|
|
||||||
from django.contrib.humanize.templatetags import humanize
|
from django.contrib.humanize.templatetags import humanize
|
||||||
from django.template import Context, Template, defaultfilters
|
from django.template import Context, Template, defaultfilters
|
||||||
|
@ -12,12 +11,6 @@ from django.utils.html import escape
|
||||||
from django.utils.timezone import get_fixed_timezone, utc
|
from django.utils.timezone import get_fixed_timezone, utc
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
# Mock out datetime in some tests so they don't fail occasionally when they
|
# Mock out datetime in some tests so they don't fail occasionally when they
|
||||||
# run too slow. Use a fixed datetime for datetime.now(). DST change in
|
# run too slow. Use a fixed datetime for datetime.now(). DST change in
|
||||||
# America/Chicago (the default time zone) happened on March 11th in 2012.
|
# America/Chicago (the default time zone) happened on March 11th in 2012.
|
||||||
|
@ -174,7 +167,6 @@ class HumanizeTests(SimpleTestCase):
|
||||||
# As 24h of difference they will never be the same
|
# As 24h of difference they will never be the same
|
||||||
self.assertNotEqual(naturalday_one, naturalday_two)
|
self.assertNotEqual(naturalday_one, naturalday_two)
|
||||||
|
|
||||||
@skipIf(pytz is None, "this test requires pytz")
|
|
||||||
def test_naturalday_uses_localtime(self):
|
def test_naturalday_uses_localtime(self):
|
||||||
# Regression for #18504
|
# Regression for #18504
|
||||||
# This is 2012-03-08HT19:30:00-06:00 in America/Chicago
|
# This is 2012-03-08HT19:30:00-06:00 in America/Chicago
|
||||||
|
|
|
@ -8,7 +8,6 @@ Pillow
|
||||||
PyYAML
|
PyYAML
|
||||||
# pylibmc/libmemcached can't be built on Windows.
|
# pylibmc/libmemcached can't be built on Windows.
|
||||||
pylibmc; sys.platform != 'win32'
|
pylibmc; sys.platform != 'win32'
|
||||||
pytz > dev
|
|
||||||
selenium
|
selenium
|
||||||
sqlparse
|
sqlparse
|
||||||
tblib
|
tblib
|
||||||
|
|
|
@ -22,7 +22,7 @@ from django.test import (
|
||||||
TransactionTestCase, mock, skipIfDBFeature, skipUnlessDBFeature,
|
TransactionTestCase, mock, skipIfDBFeature, skipUnlessDBFeature,
|
||||||
)
|
)
|
||||||
from django.test.utils import CaptureQueriesContext
|
from django.test.utils import CaptureQueriesContext
|
||||||
from django.utils.timezone import UTC
|
from django.utils import timezone
|
||||||
|
|
||||||
from .fields import (
|
from .fields import (
|
||||||
CustomManyToManyField, InheritedManyToManyField, MediumBlobField,
|
CustomManyToManyField, InheritedManyToManyField, MediumBlobField,
|
||||||
|
@ -2187,7 +2187,7 @@ class SchemaTests(TransactionTestCase):
|
||||||
TimeField if auto_now or auto_add_now is set (#25005).
|
TimeField if auto_now or auto_add_now is set (#25005).
|
||||||
"""
|
"""
|
||||||
now = datetime.datetime(month=1, day=1, year=2000, hour=1, minute=1)
|
now = datetime.datetime(month=1, day=1, year=2000, hour=1, minute=1)
|
||||||
now_tz = datetime.datetime(month=1, day=1, year=2000, hour=1, minute=1, tzinfo=UTC())
|
now_tz = datetime.datetime(month=1, day=1, year=2000, hour=1, minute=1, tzinfo=timezone.utc)
|
||||||
mocked_datetime.now = mock.MagicMock(return_value=now)
|
mocked_datetime.now = mock.MagicMock(return_value=now)
|
||||||
mocked_tz.now = mock.MagicMock(return_value=now_tz)
|
mocked_tz.now = mock.MagicMock(return_value=now_tz)
|
||||||
# Create the table
|
# Create the table
|
||||||
|
|
|
@ -16,11 +16,6 @@ from django.utils.feedgenerator import (
|
||||||
|
|
||||||
from .models import Article, Entry
|
from .models import Article, Entry
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
TZ = timezone.get_default_timezone()
|
TZ = timezone.get_default_timezone()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ from contextlib import contextmanager
|
||||||
from unittest import SkipTest, skipIf
|
from unittest import SkipTest, skipIf
|
||||||
from xml.dom.minidom import parseString
|
from xml.dom.minidom import parseString
|
||||||
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core import serializers
|
from django.core import serializers
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
@ -33,13 +35,6 @@ from .models import (
|
||||||
AllDayEvent, Event, MaybeEvent, Session, SessionEvent, Timestamp,
|
AllDayEvent, Event, MaybeEvent, Session, SessionEvent, Timestamp,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
requires_pytz = skipIf(pytz is None, "this test requires pytz")
|
|
||||||
|
|
||||||
# These tests use the EAT (Eastern Africa Time) and ICT (Indochina Time)
|
# These tests use the EAT (Eastern Africa Time) and ICT (Indochina Time)
|
||||||
# who don't have Daylight Saving Time, so we can represent them easily
|
# who don't have Daylight Saving Time, so we can represent them easily
|
||||||
# with FixedOffset, and use them directly as tzinfo in the constructors.
|
# with FixedOffset, and use them directly as tzinfo in the constructors.
|
||||||
|
@ -363,7 +358,6 @@ class NewDatabaseTests(TestCase):
|
||||||
self.assertEqual(Event.objects.filter(dt__gte=dt2).count(), 1)
|
self.assertEqual(Event.objects.filter(dt__gte=dt2).count(), 1)
|
||||||
self.assertEqual(Event.objects.filter(dt__gt=dt2).count(), 0)
|
self.assertEqual(Event.objects.filter(dt__gt=dt2).count(), 0)
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_query_filter_with_pytz_timezones(self):
|
def test_query_filter_with_pytz_timezones(self):
|
||||||
tz = pytz.timezone('Europe/Paris')
|
tz = pytz.timezone('Europe/Paris')
|
||||||
dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=tz)
|
dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=tz)
|
||||||
|
@ -908,7 +902,6 @@ class TemplateTests(SimpleTestCase):
|
||||||
expected = results[k1][k2]
|
expected = results[k1][k2]
|
||||||
self.assertEqual(actual, expected, '%s / %s: %r != %r' % (k1, k2, actual, expected))
|
self.assertEqual(actual, expected, '%s / %s: %r != %r' % (k1, k2, actual, expected))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_localtime_filters_with_pytz(self):
|
def test_localtime_filters_with_pytz(self):
|
||||||
"""
|
"""
|
||||||
Test the |localtime, |utc, and |timezone filters with pytz.
|
Test the |localtime, |utc, and |timezone filters with pytz.
|
||||||
|
@ -976,7 +969,6 @@ class TemplateTests(SimpleTestCase):
|
||||||
"2011-09-01T13:20:30+03:00|2011-09-01T17:20:30+07:00|2011-09-01T13:20:30+03:00"
|
"2011-09-01T13:20:30+03:00|2011-09-01T17:20:30+07:00|2011-09-01T13:20:30+03:00"
|
||||||
)
|
)
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_timezone_templatetag_with_pytz(self):
|
def test_timezone_templatetag_with_pytz(self):
|
||||||
"""
|
"""
|
||||||
Test the {% timezone %} templatetag with pytz.
|
Test the {% timezone %} templatetag with pytz.
|
||||||
|
@ -996,7 +988,7 @@ class TemplateTests(SimpleTestCase):
|
||||||
def test_timezone_templatetag_invalid_argument(self):
|
def test_timezone_templatetag_invalid_argument(self):
|
||||||
with self.assertRaises(TemplateSyntaxError):
|
with self.assertRaises(TemplateSyntaxError):
|
||||||
Template("{% load tz %}{% timezone %}{% endtimezone %}").render()
|
Template("{% load tz %}{% timezone %}{% endtimezone %}").render()
|
||||||
with self.assertRaises(ValueError if pytz is None else pytz.UnknownTimeZoneError):
|
with self.assertRaises(pytz.UnknownTimeZoneError):
|
||||||
Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(Context({'tz': 'foobar'}))
|
Template("{% load tz %}{% timezone tz %}{% endtimezone %}").render(Context({'tz': 'foobar'}))
|
||||||
|
|
||||||
@skipIf(sys.platform.startswith('win'), "Windows uses non-standard time zone names")
|
@skipIf(sys.platform.startswith('win'), "Windows uses non-standard time zone names")
|
||||||
|
@ -1006,7 +998,7 @@ class TemplateTests(SimpleTestCase):
|
||||||
"""
|
"""
|
||||||
tpl = Template("{% load tz %}{% get_current_timezone as time_zone %}{{ time_zone }}")
|
tpl = Template("{% load tz %}{% get_current_timezone as time_zone %}{{ time_zone }}")
|
||||||
|
|
||||||
self.assertEqual(tpl.render(Context()), "Africa/Nairobi" if pytz else "EAT")
|
self.assertEqual(tpl.render(Context()), "Africa/Nairobi")
|
||||||
with timezone.override(UTC):
|
with timezone.override(UTC):
|
||||||
self.assertEqual(tpl.render(Context()), "UTC")
|
self.assertEqual(tpl.render(Context()), "UTC")
|
||||||
|
|
||||||
|
@ -1019,7 +1011,6 @@ class TemplateTests(SimpleTestCase):
|
||||||
with timezone.override(UTC):
|
with timezone.override(UTC):
|
||||||
self.assertEqual(tpl.render(Context({'tz': ICT})), "+0700")
|
self.assertEqual(tpl.render(Context({'tz': ICT})), "+0700")
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_get_current_timezone_templatetag_with_pytz(self):
|
def test_get_current_timezone_templatetag_with_pytz(self):
|
||||||
"""
|
"""
|
||||||
Test the {% get_current_timezone %} templatetag with pytz.
|
Test the {% get_current_timezone %} templatetag with pytz.
|
||||||
|
@ -1048,7 +1039,7 @@ class TemplateTests(SimpleTestCase):
|
||||||
context = Context()
|
context = Context()
|
||||||
self.assertEqual(tpl.render(context), "")
|
self.assertEqual(tpl.render(context), "")
|
||||||
request_context = RequestContext(HttpRequest(), processors=[context_processors.tz])
|
request_context = RequestContext(HttpRequest(), processors=[context_processors.tz])
|
||||||
self.assertEqual(tpl.render(request_context), "Africa/Nairobi" if pytz else "EAT")
|
self.assertEqual(tpl.render(request_context), "Africa/Nairobi")
|
||||||
|
|
||||||
@requires_tz_support
|
@requires_tz_support
|
||||||
def test_date_and_time_template_filters(self):
|
def test_date_and_time_template_filters(self):
|
||||||
|
@ -1068,15 +1059,6 @@ class TemplateTests(SimpleTestCase):
|
||||||
with timezone.override(ICT):
|
with timezone.override(ICT):
|
||||||
self.assertEqual(tpl.render(ctx), "2011-09-01 at 20:20:20")
|
self.assertEqual(tpl.render(ctx), "2011-09-01 at 20:20:20")
|
||||||
|
|
||||||
def test_localtime_with_time_zone_setting_set_to_none(self):
|
|
||||||
# Regression for #17274
|
|
||||||
tpl = Template("{% load tz %}{{ dt }}")
|
|
||||||
ctx = Context({'dt': datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=EAT)})
|
|
||||||
|
|
||||||
with self.settings(TIME_ZONE=None):
|
|
||||||
# the actual value depends on the system time zone of the host
|
|
||||||
self.assertTrue(tpl.render(ctx).startswith("2011"))
|
|
||||||
|
|
||||||
@requires_tz_support
|
@requires_tz_support
|
||||||
def test_now_template_tag_uses_current_time_zone(self):
|
def test_now_template_tag_uses_current_time_zone(self):
|
||||||
# Regression for #17343
|
# Regression for #17343
|
||||||
|
@ -1094,7 +1076,6 @@ class LegacyFormsTests(TestCase):
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 13, 20, 30))
|
self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 13, 20, 30))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_form_with_non_existent_time(self):
|
def test_form_with_non_existent_time(self):
|
||||||
form = EventForm({'dt': '2011-03-27 02:30:00'})
|
form = EventForm({'dt': '2011-03-27 02:30:00'})
|
||||||
with timezone.override(pytz.timezone('Europe/Paris')):
|
with timezone.override(pytz.timezone('Europe/Paris')):
|
||||||
|
@ -1102,7 +1083,6 @@ class LegacyFormsTests(TestCase):
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 3, 27, 2, 30, 0))
|
self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 3, 27, 2, 30, 0))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_form_with_ambiguous_time(self):
|
def test_form_with_ambiguous_time(self):
|
||||||
form = EventForm({'dt': '2011-10-30 02:30:00'})
|
form = EventForm({'dt': '2011-10-30 02:30:00'})
|
||||||
with timezone.override(pytz.timezone('Europe/Paris')):
|
with timezone.override(pytz.timezone('Europe/Paris')):
|
||||||
|
@ -1141,7 +1121,6 @@ class NewFormsTests(TestCase):
|
||||||
# Datetime inputs formats don't allow providing a time zone.
|
# Datetime inputs formats don't allow providing a time zone.
|
||||||
self.assertFalse(form.is_valid())
|
self.assertFalse(form.is_valid())
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_form_with_non_existent_time(self):
|
def test_form_with_non_existent_time(self):
|
||||||
with timezone.override(pytz.timezone('Europe/Paris')):
|
with timezone.override(pytz.timezone('Europe/Paris')):
|
||||||
form = EventForm({'dt': '2011-03-27 02:30:00'})
|
form = EventForm({'dt': '2011-03-27 02:30:00'})
|
||||||
|
@ -1153,7 +1132,6 @@ class NewFormsTests(TestCase):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_form_with_ambiguous_time(self):
|
def test_form_with_ambiguous_time(self):
|
||||||
with timezone.override(pytz.timezone('Europe/Paris')):
|
with timezone.override(pytz.timezone('Europe/Paris')):
|
||||||
form = EventForm({'dt': '2011-10-30 02:30:00'})
|
form = EventForm({'dt': '2011-10-30 02:30:00'})
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import sys
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from unittest import skipIf
|
|
||||||
|
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
from django.test.utils import TZ_SUPPORT, requires_tz_support
|
from django.test.utils import TZ_SUPPORT, requires_tz_support
|
||||||
|
@ -12,11 +10,6 @@ from django.utils.timezone import (
|
||||||
get_default_timezone, get_fixed_timezone, make_aware, utc,
|
get_default_timezone, get_fixed_timezone, make_aware, utc,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
|
|
||||||
@override_settings(TIME_ZONE='Europe/Copenhagen')
|
@override_settings(TIME_ZONE='Europe/Copenhagen')
|
||||||
class DateFormatTests(SimpleTestCase):
|
class DateFormatTests(SimpleTestCase):
|
||||||
|
@ -36,18 +29,16 @@ class DateFormatTests(SimpleTestCase):
|
||||||
dt = datetime(2009, 5, 16, 5, 30, 30)
|
dt = datetime(2009, 5, 16, 5, 30, 30)
|
||||||
self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U'))), dt)
|
self.assertEqual(datetime.fromtimestamp(int(format(dt, 'U'))), dt)
|
||||||
|
|
||||||
@skipIf(sys.platform.startswith('win') and not pytz, "Test requires pytz on Windows")
|
|
||||||
def test_naive_ambiguous_datetime(self):
|
def test_naive_ambiguous_datetime(self):
|
||||||
# dt is ambiguous in Europe/Copenhagen. LocalTimezone guesses the
|
# dt is ambiguous in Europe/Copenhagen. pytz raises an exception for
|
||||||
# offset (and gets it wrong 50% of the time) while pytz refuses the
|
# the ambiguity, which results in an empty string.
|
||||||
# temptation to guess. In any case, this shouldn't crash.
|
|
||||||
dt = datetime(2015, 10, 25, 2, 30, 0)
|
dt = datetime(2015, 10, 25, 2, 30, 0)
|
||||||
|
|
||||||
# Try all formatters that involve self.timezone.
|
# Try all formatters that involve self.timezone.
|
||||||
self.assertEqual(format(dt, 'I'), '0' if pytz is None else '')
|
self.assertEqual(format(dt, 'I'), '')
|
||||||
self.assertEqual(format(dt, 'O'), '+0100' if pytz is None else '')
|
self.assertEqual(format(dt, 'O'), '')
|
||||||
self.assertEqual(format(dt, 'T'), 'CET' if pytz is None else '')
|
self.assertEqual(format(dt, 'T'), '')
|
||||||
self.assertEqual(format(dt, 'Z'), '3600' if pytz is None else '')
|
self.assertEqual(format(dt, 'Z'), '')
|
||||||
|
|
||||||
@requires_tz_support
|
@requires_tz_support
|
||||||
def test_datetime_with_local_tzinfo(self):
|
def test_datetime_with_local_tzinfo(self):
|
||||||
|
|
|
@ -1,21 +1,12 @@
|
||||||
import copy
|
|
||||||
import datetime
|
import datetime
|
||||||
import pickle
|
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
|
||||||
|
import pytz
|
||||||
|
|
||||||
from django.test import SimpleTestCase, mock, override_settings
|
from django.test import SimpleTestCase, mock, override_settings
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
try:
|
CET = pytz.timezone("Europe/Paris")
|
||||||
import pytz
|
|
||||||
except ImportError:
|
|
||||||
pytz = None
|
|
||||||
|
|
||||||
requires_pytz = unittest.skipIf(pytz is None, "this test requires pytz")
|
|
||||||
|
|
||||||
if pytz is not None:
|
|
||||||
CET = pytz.timezone("Europe/Paris")
|
|
||||||
EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi
|
EAT = timezone.get_fixed_timezone(180) # Africa/Nairobi
|
||||||
ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok
|
ICT = timezone.get_fixed_timezone(420) # Asia/Bangkok
|
||||||
|
|
||||||
|
@ -24,33 +15,6 @@ PY36 = sys.version_info >= (3, 6)
|
||||||
|
|
||||||
class TimezoneTests(SimpleTestCase):
|
class TimezoneTests(SimpleTestCase):
|
||||||
|
|
||||||
def test_localtime(self):
|
|
||||||
now = datetime.datetime.utcnow().replace(tzinfo=timezone.utc)
|
|
||||||
local_tz = timezone.LocalTimezone()
|
|
||||||
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):
|
|
||||||
now = datetime.datetime.now()
|
|
||||||
if PY36:
|
|
||||||
self.assertEqual(timezone.localtime(now), now.replace(tzinfo=timezone.LocalTimezone()))
|
|
||||||
else:
|
|
||||||
with self.assertRaisesMessage(ValueError, 'astimezone() cannot be applied to a naive datetime'):
|
|
||||||
timezone.localtime(now)
|
|
||||||
|
|
||||||
def test_localtime_out_of_range(self):
|
|
||||||
local_tz = timezone.LocalTimezone()
|
|
||||||
long_ago = datetime.datetime(1900, 1, 1, tzinfo=timezone.utc)
|
|
||||||
try:
|
|
||||||
timezone.localtime(long_ago, local_tz)
|
|
||||||
except (OverflowError, ValueError) as exc:
|
|
||||||
self.assertIn("install pytz", exc.args[0])
|
|
||||||
else:
|
|
||||||
self.skipTest("Failed to trigger an OverflowError or ValueError")
|
|
||||||
|
|
||||||
def test_now(self):
|
def test_now(self):
|
||||||
with override_settings(USE_TZ=True):
|
with override_settings(USE_TZ=True):
|
||||||
self.assertTrue(timezone.is_aware(timezone.now()))
|
self.assertTrue(timezone.is_aware(timezone.now()))
|
||||||
|
@ -133,18 +97,6 @@ class TimezoneTests(SimpleTestCase):
|
||||||
finally:
|
finally:
|
||||||
timezone.deactivate()
|
timezone.deactivate()
|
||||||
|
|
||||||
def test_copy(self):
|
|
||||||
self.assertIsInstance(copy.copy(timezone.UTC()), timezone.UTC)
|
|
||||||
self.assertIsInstance(copy.copy(timezone.LocalTimezone()), timezone.LocalTimezone)
|
|
||||||
|
|
||||||
def test_deepcopy(self):
|
|
||||||
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(timezone.UTC())), timezone.UTC)
|
|
||||||
self.assertIsInstance(pickle.loads(pickle.dumps(timezone.LocalTimezone())), timezone.LocalTimezone)
|
|
||||||
|
|
||||||
def test_is_aware(self):
|
def test_is_aware(self):
|
||||||
self.assertTrue(timezone.is_aware(datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)))
|
self.assertTrue(timezone.is_aware(datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT)))
|
||||||
self.assertFalse(timezone.is_aware(datetime.datetime(2011, 9, 1, 13, 20, 30)))
|
self.assertFalse(timezone.is_aware(datetime.datetime(2011, 9, 1, 13, 20, 30)))
|
||||||
|
@ -175,7 +127,6 @@ class TimezoneTests(SimpleTestCase):
|
||||||
with self.assertRaisesMessage(ValueError, 'astimezone() cannot be applied to a naive datetime'):
|
with self.assertRaisesMessage(ValueError, 'astimezone() cannot be applied to a naive datetime'):
|
||||||
timezone.make_naive(*args)
|
timezone.make_naive(*args)
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_make_aware2(self):
|
def test_make_aware2(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30), CET),
|
timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30), CET),
|
||||||
|
@ -183,7 +134,6 @@ class TimezoneTests(SimpleTestCase):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
timezone.make_aware(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET)
|
timezone.make_aware(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET)
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_make_aware_pytz(self):
|
def test_make_aware_pytz(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
timezone.make_naive(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET),
|
timezone.make_naive(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET),
|
||||||
|
@ -202,7 +152,6 @@ class TimezoneTests(SimpleTestCase):
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET)
|
timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET)
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_make_aware_pytz_ambiguous(self):
|
def test_make_aware_pytz_ambiguous(self):
|
||||||
# 2:30 happens twice, once before DST ends and once after
|
# 2:30 happens twice, once before DST ends and once after
|
||||||
ambiguous = datetime.datetime(2015, 10, 25, 2, 30)
|
ambiguous = datetime.datetime(2015, 10, 25, 2, 30)
|
||||||
|
@ -216,7 +165,6 @@ class TimezoneTests(SimpleTestCase):
|
||||||
self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1))
|
self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1))
|
||||||
self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2))
|
self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2))
|
||||||
|
|
||||||
@requires_pytz
|
|
||||||
def test_make_aware_pytz_non_existent(self):
|
def test_make_aware_pytz_non_existent(self):
|
||||||
# 2:30 never happened due to DST
|
# 2:30 never happened due to DST
|
||||||
non_existent = datetime.datetime(2015, 3, 29, 2, 30)
|
non_existent = datetime.datetime(2015, 3, 29, 2, 30)
|
||||||
|
@ -229,9 +177,3 @@ class TimezoneTests(SimpleTestCase):
|
||||||
self.assertEqual(std - dst, datetime.timedelta(hours=1))
|
self.assertEqual(std - dst, datetime.timedelta(hours=1))
|
||||||
self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1))
|
self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1))
|
||||||
self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2))
|
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…
Reference in New Issue