mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #27327 -- Simplified time zone handling by requiring pytz.
This commit is contained in:
		| @@ -4,6 +4,8 @@ import warnings | ||||
| from collections import deque | ||||
| from contextlib import contextmanager | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.core.exceptions import ImproperlyConfigured | ||||
| 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.six.moves import _thread as thread | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
| NO_DB_ALIAS = '__no_db__' | ||||
|  | ||||
|  | ||||
| @@ -128,7 +125,6 @@ class BaseDatabaseWrapper(object): | ||||
|         elif self.settings_dict['TIME_ZONE'] is None: | ||||
|             return timezone.utc | ||||
|         else: | ||||
|             # Only this branch requires pytz. | ||||
|             return pytz.timezone(self.settings_dict['TIME_ZONE']) | ||||
|  | ||||
|     @cached_property | ||||
| @@ -207,10 +203,6 @@ class BaseDatabaseWrapper(object): | ||||
|                 raise ImproperlyConfigured( | ||||
|                     "Connection '%s' cannot set TIME_ZONE because its engine " | ||||
|                     "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): | ||||
|         """ | ||||
|   | ||||
| @@ -3,11 +3,6 @@ from django.utils.functional import cached_property | ||||
|  | ||||
| from .base import Database | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|     empty_fetchmany_value = () | ||||
| @@ -56,14 +51,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|  | ||||
|     @cached_property | ||||
|     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. | ||||
|         with self.connection.cursor() as cursor: | ||||
|             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.utils import InterfaceError | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|     empty_fetchmany_value = () | ||||
| @@ -19,7 +14,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|     supports_subqueries_in_group_by = False | ||||
|     supports_transactions = True | ||||
|     supports_timezones = False | ||||
|     has_zoneinfo_database = pytz is not None | ||||
|     supports_bitwise_or = False | ||||
|     has_native_duration_field = True | ||||
|     can_defer_constraint_checks = True | ||||
|   | ||||
| @@ -11,6 +11,8 @@ import decimal | ||||
| import re | ||||
| import warnings | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.db import 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.safestring import SafeBytes | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
| try: | ||||
|     try: | ||||
|         from pysqlite2 import dbapi2 as Database | ||||
|   | ||||
| @@ -7,11 +7,6 @@ from django.utils.functional import cached_property | ||||
|  | ||||
| from .base import Database | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|     # SQLite cannot handle us only partially reading from a cursor's result set | ||||
| @@ -78,7 +73,3 @@ class DatabaseFeatures(BaseDatabaseFeatures): | ||||
|                 has_support = False | ||||
|             cursor.execute('DROP TABLE STDDEV_TEST') | ||||
|         return has_support | ||||
|  | ||||
|     @cached_property | ||||
|     def has_zoneinfo_database(self): | ||||
|         return pytz is not None | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import datetime | ||||
| import uuid | ||||
|  | ||||
| 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.backends import utils as backend_utils | ||||
| 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.duration import duration_string | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| class DatabaseOperations(BaseDatabaseOperations): | ||||
|     def bulk_batch_size(self, fields, objs): | ||||
| @@ -77,27 +72,19 @@ class DatabaseOperations(BaseDatabaseOperations): | ||||
|         # cause a collision with a 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): | ||||
|         self._require_pytz() | ||||
|         return "django_datetime_cast_date(%s, %%s)" % 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] | ||||
|  | ||||
|     def datetime_extract_sql(self, lookup_type, field_name, tzname): | ||||
|         # Same comment as in date_extract_sql. | ||||
|         self._require_pytz() | ||||
|         return "django_datetime_extract('%s', %s, %%s)" % ( | ||||
|             lookup_type.lower(), field_name), [tzname] | ||||
|  | ||||
|     def datetime_trunc_sql(self, lookup_type, field_name, tzname): | ||||
|         # Same comment as in date_trunc_sql. | ||||
|         self._require_pytz() | ||||
|         return "django_datetime_trunc('%s', %s, %%s)" % ( | ||||
|             lookup_type.lower(), field_name), [tzname] | ||||
|  | ||||
|   | ||||
| @@ -191,7 +191,7 @@ class TruncBase(TimezoneMixin, Transform): | ||||
|                 if value is None: | ||||
|                     raise ValueError( | ||||
|                         "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 = timezone.make_aware(value, self.tzinfo) | ||||
|   | ||||
| @@ -1,14 +1,10 @@ | ||||
| from datetime import datetime, tzinfo | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.template import Library, Node, TemplateSyntaxError | ||||
| from django.utils import six, timezone | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| register = Library() | ||||
|  | ||||
|  | ||||
| @@ -44,7 +40,6 @@ def do_timezone(value, arg): | ||||
|     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. | ||||
|     If it is a time zone name, pytz is required. | ||||
|  | ||||
|     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 | ||||
|     if isinstance(arg, tzinfo): | ||||
|         tz = arg | ||||
|     elif isinstance(arg, six.string_types) and pytz is not None: | ||||
|     elif isinstance(arg, six.string_types): | ||||
|         try: | ||||
|             tz = pytz.timezone(arg) | ||||
|         except pytz.UnknownTimeZoneError: | ||||
| @@ -156,8 +151,8 @@ def timezone_tag(parser, token): | ||||
|     Enables a given time zone just for this block. | ||||
|  | ||||
|     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. | ||||
|     If it is ``None``, the default time zone is used within the block. | ||||
|     time zone name, or ``None``. If it is ``None``, the default time zone is | ||||
|     used within the block. | ||||
|  | ||||
|     Sample usage:: | ||||
|  | ||||
|   | ||||
| @@ -1,24 +1,16 @@ | ||||
| """ | ||||
| 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 threading import local | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.utils import lru_cache, six | ||||
| from django.utils.decorators import ContextDecorator | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| __all__ = [ | ||||
|     'utc', 'get_fixed_timezone', | ||||
|     'get_default_timezone', 'get_default_timezone_name', | ||||
| @@ -34,26 +26,6 @@ __all__ = [ | ||||
| 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): | ||||
|     """ | ||||
|     Fixed offset in minutes east from UTC. Taken from Python's docs. | ||||
| @@ -78,79 +50,7 @@ class FixedOffset(tzinfo): | ||||
|     def dst(self, dt): | ||||
|         return ZERO | ||||
|  | ||||
|  | ||||
| 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 = pytz.utc | ||||
| """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. | ||||
|     """ | ||||
|     if isinstance(settings.TIME_ZONE, six.string_types) and pytz is not None: | ||||
|         return pytz.timezone(settings.TIME_ZONE) | ||||
|     else: | ||||
|         # This relies on os.environ['TZ'] being set to settings.TIME_ZONE. | ||||
|         return LocalTimezone() | ||||
|     return pytz.timezone(settings.TIME_ZONE) | ||||
|  | ||||
|  | ||||
| # 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. | ||||
|  | ||||
|     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): | ||||
|         _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) | ||||
|     else: | ||||
|         raise ValueError("Invalid timezone: %r" % timezone) | ||||
| @@ -257,8 +153,8 @@ class override(ContextDecorator): | ||||
|     on exit. | ||||
|  | ||||
|     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. | ||||
|     If it is ``None``, Django enables the default time zone. | ||||
|     time zone name, or ``None``. If it is ``None``, Django enables the default | ||||
|     time zone. | ||||
|     """ | ||||
|     def __init__(self, timezone): | ||||
|         self.timezone = timezone | ||||
|   | ||||
| @@ -117,9 +117,9 @@ Imports | ||||
|  | ||||
|       # try/except | ||||
|       try: | ||||
|           import pytz | ||||
|           import yaml | ||||
|       except ImportError: | ||||
|           pytz = None | ||||
|           yaml = None | ||||
|  | ||||
|       CONSTANT = 'foo' | ||||
|  | ||||
|   | ||||
| @@ -232,7 +232,7 @@ dependencies: | ||||
| *  numpy_ | ||||
| *  Pillow_ | ||||
| *  PyYAML_ | ||||
| *  pytz_ | ||||
| *  pytz_ (required) | ||||
| *  setuptools_ | ||||
| *  memcached_, plus a :ref:`supported Python binding <memcached>` | ||||
| *  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 | ||||
|     ``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`_). | ||||
|     - Oracle: no requirements (see `Choosing a Time Zone File`_). | ||||
|     - MySQL: install pytz_ and load the time zone tables with | ||||
|       `mysql_tzinfo_to_sql`_. | ||||
|     - MySQL: load the time zone tables with `mysql_tzinfo_to_sql`_. | ||||
|  | ||||
|     .. _pytz: http://pytz.sourceforge.net/ | ||||
|     .. _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 | ||||
| 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 | ||||
| (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. | ||||
| @@ -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. | ||||
|  | ||||
| .. _pytz: http://pytz.sourceforge.net/ | ||||
|  | ||||
| .. setting:: USER | ||||
|  | ||||
| ``USER`` | ||||
| @@ -2478,8 +2474,8 @@ See also :setting:`DATE_INPUT_FORMATS` and :setting:`DATETIME_INPUT_FORMATS`. | ||||
|  | ||||
| Default: ``'America/Chicago'`` | ||||
|  | ||||
| A string representing the time zone for this installation, or ``None``. See | ||||
| the `list of time zones`_. | ||||
| A string representing the time zone for this installation. See the `list of | ||||
| time zones`_. | ||||
|  | ||||
| .. note:: | ||||
|     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 | ||||
| to interpret datetimes entered in forms. | ||||
|  | ||||
| Django sets the ``os.environ['TZ']`` variable to the time zone you specify in | ||||
| the :setting:`TIME_ZONE` setting. Thus, all your views and models will | ||||
| On Unix environments (where :func:`time.tzset` is implemented), Django sets the | ||||
| ``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`` | ||||
| environment variable under the following conditions: | ||||
|  | ||||
| * If you're using the manual configuration option as described in | ||||
|   :ref:`manually configuring settings | ||||
|   <settings-without-django-settings-module>`, or | ||||
|  | ||||
| * 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. | ||||
| environment variable if you're using the manual configuration option as | ||||
| described in :ref:`manually configuring settings | ||||
| <settings-without-django-settings-module>`. 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:: | ||||
|     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 | ||||
|     ``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() | ||||
|  | ||||
| @@ -1043,21 +1043,18 @@ appropriate entities. | ||||
|     :class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it | ||||
|     defaults to the :ref:`current time zone <default-current-time-zone>`. | ||||
|  | ||||
|     When pytz_ is installed, the exception ``pytz.AmbiguousTimeError`` | ||||
|     will be raised if you try to make ``value`` aware during a DST transition | ||||
|     where the same time occurs twice (when reverting from DST). Setting | ||||
|     ``is_dst`` to ``True`` or ``False`` will avoid the exception by choosing if | ||||
|     the time is pre-transition or post-transition respectively. | ||||
|     The ``pytz.AmbiguousTimeError`` exception is raised if you try to make | ||||
|     ``value`` aware during a DST transition where the same time occurs twice | ||||
|     (when reverting from DST). Setting ``is_dst`` to ``True`` or ``False`` will | ||||
|     avoid the exception by choosing if the time is pre-transition or | ||||
|     post-transition respectively. | ||||
|  | ||||
|     When pytz_ is installed, the exception ``pytz.NonExistentTimeError`` | ||||
|     will be raised if you try to make ``value`` aware during a DST transition | ||||
|     such that the time never occurred (when entering into DST). Setting | ||||
|     ``is_dst`` to ``True`` or ``False`` will avoid the exception by moving the | ||||
|     hour backwards or forwards by 1 respectively. For example, ``is_dst=True`` | ||||
|     would change a non-existent time of 2:30 to 1:30 and ``is_dst=False`` | ||||
|     would change the time to 3:30. | ||||
|  | ||||
|     ``is_dst`` has no effect when ``pytz`` is not installed. | ||||
|     The ``pytz.NonExistentTimeError`` exception is raised if you try to make | ||||
|     ``value`` aware during a DST transition such that the time never occurred | ||||
|     (when entering into DST). Setting ``is_dst`` to ``True`` or ``False`` will | ||||
|     avoid the exception by moving the hour backwards or forwards by 1 | ||||
|     respectively. For example, ``is_dst=True`` would change a non-existent | ||||
|     time of 2:30 to 1:30 and ``is_dst=False`` would change the time to 3:30. | ||||
|  | ||||
| .. function:: make_naive(value, timezone=None) | ||||
|  | ||||
| @@ -1066,8 +1063,6 @@ appropriate entities. | ||||
|     aware :class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it | ||||
|     defaults to the :ref:`current time zone <default-current-time-zone>`. | ||||
|  | ||||
| .. _pytz: http://pytz.sourceforge.net/ | ||||
|  | ||||
| ``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 | ||||
| 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 | ||||
| ------------- | ||||
|  | ||||
|   | ||||
| @@ -622,7 +622,6 @@ Pygments | ||||
| pysqlite | ||||
| pythonic | ||||
| Pythonista | ||||
| pytz | ||||
| qs | ||||
| Québec | ||||
| 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. | ||||
|  | ||||
| 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, | ||||
| but may not be mandatory depending on your particular database backend, | ||||
| 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: | ||||
| True <USE_TZ>` in your settings file. Time zone support uses pytz_, which is | ||||
| installed when you install Django. | ||||
|  | ||||
| .. code-block:: console | ||||
| .. versionchanged:: 1.11 | ||||
|  | ||||
|     $ pip install pytz | ||||
|     Older versions don't require ``pytz`` or install it automatically. | ||||
|  | ||||
| .. 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. | ||||
|  | ||||
| Unfortunately, during DST transitions, some datetimes don't exist or are | ||||
| ambiguous. In such situations, pytz_ raises an exception. Other | ||||
| :class:`~datetime.tzinfo` implementations, such as the local time zone used as | ||||
| 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. | ||||
| ambiguous. In such situations, pytz_ raises an exception. 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 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. | ||||
|  | ||||
| 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:: | ||||
|  | ||||
| @@ -405,9 +400,8 @@ Code | ||||
| ---- | ||||
|  | ||||
| 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 | ||||
| work. If you create naive datetime objects in your code, Django makes them | ||||
| aware when necessary. | ||||
| file. At this point, things should mostly work. If you create naive datetime | ||||
| objects in your code, Django makes them aware when necessary. | ||||
|  | ||||
| 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 | ||||
| @@ -523,22 +517,7 @@ Setup | ||||
|    one year is 2011-02-28 or 2011-03-01, which depends on your business | ||||
|    requirements.) | ||||
|  | ||||
| 3. **Should I install pytz?** | ||||
|  | ||||
|    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?** | ||||
| 3. **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 | ||||
|    time zone for this database in the :setting:`DATABASES` setting. | ||||
| @@ -653,8 +632,8 @@ Troubleshooting | ||||
|        >>> local.date() | ||||
|        datetime.date(2012, 3, 3) | ||||
|  | ||||
| 4. **I get an error** "``Are time zone definitions for your database and pytz | ||||
|    installed?``" **pytz is installed, so I guess the problem is my database?** | ||||
| 4. **I get an error** "``Are time zone definitions for your database | ||||
|    installed?``" | ||||
|  | ||||
|    If you are using MySQL, see the :ref:`mysql-time-zone-definitions` section | ||||
|    of the MySQL notes for instructions on loading time zone definitions. | ||||
| @@ -700,8 +679,7 @@ Usage | ||||
|        >>> timezone.localtime(timezone.now()) | ||||
|        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 | ||||
|    ``"Europe/Paris"``. | ||||
|    In this example, the current time zone is ``"Europe/Paris"``. | ||||
|  | ||||
| 3. **How can I see all available time zones?** | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							| @@ -47,6 +47,7 @@ setup( | ||||
|     entry_points={'console_scripts': [ | ||||
|         'django-admin = django.core.management:execute_from_command_line', | ||||
|     ]}, | ||||
|     install_requires=['pytz'], | ||||
|     extras_require={ | ||||
|         "bcrypt": ["bcrypt"], | ||||
|         "argon2": ["argon2-cffi >= 16.1.0"], | ||||
|   | ||||
| @@ -5,7 +5,8 @@ import gettext | ||||
| import os | ||||
| from datetime import datetime, timedelta | ||||
| from importlib import import_module | ||||
| from unittest import skipIf | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django import forms | ||||
| from django.conf import settings | ||||
| @@ -23,11 +24,6 @@ from django.utils import six, translation | ||||
| from . import models | ||||
| from .widgetadmin import site as widget_admin_site | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| class TestDataMixin(object): | ||||
|  | ||||
| @@ -794,7 +790,6 @@ class DateTimePickerSeleniumTests(AdminWidgetSeleniumTestCase): | ||||
|                 self.wait_for_text('#calendarin0 caption', expected_caption) | ||||
|  | ||||
|  | ||||
| @skipIf(pytz is None, "this test requires pytz") | ||||
| @override_settings(TIME_ZONE='Asia/Singapore') | ||||
| class DateTimePickerShortcutsSeleniumTests(AdminWidgetSeleniumTestCase): | ||||
|  | ||||
|   | ||||
							
								
								
									
										15
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								tests/cache/tests.py
									
									
									
									
										vendored
									
									
								
							| @@ -1832,17 +1832,16 @@ class CacheI18nTest(TestCase): | ||||
|  | ||||
|     @override_settings(USE_I18N=False, USE_L10N=False, USE_TZ=True) | ||||
|     def test_cache_key_with_non_ascii_tzname(self): | ||||
|         # Regression test for #17476 | ||||
|         class CustomTzName(timezone.UTC): | ||||
|             name = '' | ||||
|  | ||||
|             def tzname(self, dt): | ||||
|                 return self.name | ||||
|         # Timezone-dependent cache keys should use ASCII characters only | ||||
|         # (#17476). The implementation here is a bit odd (timezone.utc is an | ||||
|         # instance, not a class), but it simulates the correct conditions. | ||||
|         class CustomTzName(timezone.utc): | ||||
|             pass | ||||
|  | ||||
|         request = self.factory.get(self.path) | ||||
|         response = HttpResponse() | ||||
|         with timezone.override(CustomTzName()): | ||||
|             CustomTzName.name = 'Hora estándar de Argentina'.encode('UTF-8')  # UTF-8 string | ||||
|         with timezone.override(CustomTzName): | ||||
|             CustomTzName.zone = 'Hora estándar de Argentina'.encode('UTF-8')  # UTF-8 string | ||||
|             sanitized_name = 'Hora_estndar_de_Argentina' | ||||
|             self.assertIn( | ||||
|                 sanitized_name, learn_cache_key(request, response), | ||||
|   | ||||
| @@ -1,18 +1,12 @@ | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| import datetime | ||||
| from unittest import skipIf | ||||
|  | ||||
| from django.test import TestCase, override_settings | ||||
| from django.utils import timezone | ||||
|  | ||||
| from .models import Article, Category, Comment | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| class DateTimesTests(TestCase): | ||||
|     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) | ||||
|     def test_21432(self): | ||||
|         now = timezone.localtime(timezone.now().replace(microsecond=0)) | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| from datetime import datetime | ||||
| from unittest import skipIf | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.db import connection | ||||
| @@ -16,11 +17,6 @@ from django.utils import timezone | ||||
|  | ||||
| from .models import DTModel | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| def microsecond_support(value): | ||||
|     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()))) | ||||
|  | ||||
|  | ||||
| @skipIf(pytz is None, "this test requires pytz") | ||||
| @override_settings(USE_TZ=True, TIME_ZONE='UTC') | ||||
| 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 | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| FILE_SUFFIX_REGEX = '[A-Za-z0-9]{7}' | ||||
|  | ||||
|  | ||||
| @@ -99,10 +93,6 @@ class FileSystemStorageTests(unittest.TestCase): | ||||
|             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): | ||||
|     storage_class = FileSystemStorage | ||||
|  | ||||
| @@ -157,7 +147,6 @@ class FileStorageTests(SimpleTestCase): | ||||
|         # different. | ||||
|         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)): | ||||
|             # At this point the system TZ is +1 and the Django TZ | ||||
|             # is -5. The following will be aware in UTC. | ||||
| @@ -191,7 +180,6 @@ class FileStorageTests(SimpleTestCase): | ||||
|         # different. | ||||
|         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)): | ||||
|             # At this point the system TZ is +1 and the Django TZ | ||||
|             # is -5. | ||||
| @@ -220,7 +208,6 @@ class FileStorageTests(SimpleTestCase): | ||||
|             _dt = timezone.make_aware(dt, now_in_algiers.tzinfo) | ||||
|             self.assertLess(abs(_dt - now_in_algiers), timedelta(seconds=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_file_get_accessed_time(self): | ||||
|         """ | ||||
|         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.assertLess(timezone.now() - self.storage.get_accessed_time(f_name), timedelta(seconds=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     @requires_tz_support | ||||
|     def test_file_get_accessed_time_timezone(self): | ||||
|         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.assertLess(datetime.now() - self.storage.accessed_time(f_name), timedelta(seconds=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_file_get_created_time(self): | ||||
|         """ | ||||
|         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.assertLess(timezone.now() - self.storage.get_created_time(f_name), timedelta(seconds=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     @requires_tz_support | ||||
|     def test_file_get_created_time_timezone(self): | ||||
|         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.assertLess(datetime.now() - self.storage.created_time(f_name), timedelta(seconds=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_file_get_modified_time(self): | ||||
|         """ | ||||
|         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.assertLess(timezone.now() - self.storage.get_modified_time(f_name), timedelta(seconds=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     @requires_tz_support | ||||
|     def test_file_get_modified_time_timezone(self): | ||||
|         self._test_file_time_getter(self.storage.get_modified_time) | ||||
|   | ||||
| @@ -2,7 +2,6 @@ from __future__ import unicode_literals | ||||
|  | ||||
| import datetime | ||||
| from decimal import Decimal | ||||
| from unittest import skipIf | ||||
|  | ||||
| from django.contrib.humanize.templatetags import humanize | ||||
| 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.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 | ||||
| # 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. | ||||
| @@ -174,7 +167,6 @@ class HumanizeTests(SimpleTestCase): | ||||
|         # As 24h of difference they will never be the same | ||||
|         self.assertNotEqual(naturalday_one, naturalday_two) | ||||
|  | ||||
|     @skipIf(pytz is None, "this test requires pytz") | ||||
|     def test_naturalday_uses_localtime(self): | ||||
|         # Regression for #18504 | ||||
|         # This is 2012-03-08HT19:30:00-06:00 in America/Chicago | ||||
|   | ||||
| @@ -8,7 +8,6 @@ Pillow | ||||
| PyYAML | ||||
| # pylibmc/libmemcached can't be built on Windows. | ||||
| pylibmc; sys.platform != 'win32' | ||||
| pytz > dev | ||||
| selenium | ||||
| sqlparse | ||||
| tblib | ||||
|   | ||||
| @@ -22,7 +22,7 @@ from django.test import ( | ||||
|     TransactionTestCase, mock, skipIfDBFeature, skipUnlessDBFeature, | ||||
| ) | ||||
| from django.test.utils import CaptureQueriesContext | ||||
| from django.utils.timezone import UTC | ||||
| from django.utils import timezone | ||||
|  | ||||
| from .fields import ( | ||||
|     CustomManyToManyField, InheritedManyToManyField, MediumBlobField, | ||||
| @@ -2187,7 +2187,7 @@ class SchemaTests(TransactionTestCase): | ||||
|         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_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_tz.now = mock.MagicMock(return_value=now_tz) | ||||
|         # Create the table | ||||
|   | ||||
| @@ -16,11 +16,6 @@ from django.utils.feedgenerator import ( | ||||
|  | ||||
| from .models import Article, Entry | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
| TZ = timezone.get_default_timezone() | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -8,6 +8,8 @@ from contextlib import contextmanager | ||||
| from unittest import SkipTest, skipIf | ||||
| from xml.dom.minidom import parseString | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.contrib.auth.models import User | ||||
| from django.core import serializers | ||||
| from django.core.exceptions import ImproperlyConfigured | ||||
| @@ -33,13 +35,6 @@ from .models import ( | ||||
|     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) | ||||
| # who don't have Daylight Saving Time, so we can represent them easily | ||||
| # 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__gt=dt2).count(), 0) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_query_filter_with_pytz_timezones(self): | ||||
|         tz = pytz.timezone('Europe/Paris') | ||||
|         dt = datetime.datetime(2011, 9, 1, 12, 20, 30, tzinfo=tz) | ||||
| @@ -908,7 +902,6 @@ class TemplateTests(SimpleTestCase): | ||||
|                     expected = results[k1][k2] | ||||
|                     self.assertEqual(actual, expected, '%s / %s: %r != %r' % (k1, k2, actual, expected)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_localtime_filters_with_pytz(self): | ||||
|         """ | ||||
|         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" | ||||
|         ) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_timezone_templatetag_with_pytz(self): | ||||
|         """ | ||||
|         Test the {% timezone %} templatetag with pytz. | ||||
| @@ -996,7 +988,7 @@ class TemplateTests(SimpleTestCase): | ||||
|     def test_timezone_templatetag_invalid_argument(self): | ||||
|         with self.assertRaises(TemplateSyntaxError): | ||||
|             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'})) | ||||
|  | ||||
|     @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 }}") | ||||
|  | ||||
|         self.assertEqual(tpl.render(Context()), "Africa/Nairobi" if pytz else "EAT") | ||||
|         self.assertEqual(tpl.render(Context()), "Africa/Nairobi") | ||||
|         with timezone.override(UTC): | ||||
|             self.assertEqual(tpl.render(Context()), "UTC") | ||||
|  | ||||
| @@ -1019,7 +1011,6 @@ class TemplateTests(SimpleTestCase): | ||||
|         with timezone.override(UTC): | ||||
|             self.assertEqual(tpl.render(Context({'tz': ICT})), "+0700") | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_get_current_timezone_templatetag_with_pytz(self): | ||||
|         """ | ||||
|         Test the {% get_current_timezone %} templatetag with pytz. | ||||
| @@ -1048,7 +1039,7 @@ class TemplateTests(SimpleTestCase): | ||||
|         context = Context() | ||||
|         self.assertEqual(tpl.render(context), "") | ||||
|         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 | ||||
|     def test_date_and_time_template_filters(self): | ||||
| @@ -1068,15 +1059,6 @@ class TemplateTests(SimpleTestCase): | ||||
|         with timezone.override(ICT): | ||||
|             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 | ||||
|     def test_now_template_tag_uses_current_time_zone(self): | ||||
|         # Regression for #17343 | ||||
| @@ -1094,7 +1076,6 @@ class LegacyFormsTests(TestCase): | ||||
|         self.assertTrue(form.is_valid()) | ||||
|         self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 9, 1, 13, 20, 30)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_form_with_non_existent_time(self): | ||||
|         form = EventForm({'dt': '2011-03-27 02:30:00'}) | ||||
|         with timezone.override(pytz.timezone('Europe/Paris')): | ||||
| @@ -1102,7 +1083,6 @@ class LegacyFormsTests(TestCase): | ||||
|             self.assertTrue(form.is_valid()) | ||||
|             self.assertEqual(form.cleaned_data['dt'], datetime.datetime(2011, 3, 27, 2, 30, 0)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_form_with_ambiguous_time(self): | ||||
|         form = EventForm({'dt': '2011-10-30 02:30:00'}) | ||||
|         with timezone.override(pytz.timezone('Europe/Paris')): | ||||
| @@ -1141,7 +1121,6 @@ class NewFormsTests(TestCase): | ||||
|         # Datetime inputs formats don't allow providing a time zone. | ||||
|         self.assertFalse(form.is_valid()) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_form_with_non_existent_time(self): | ||||
|         with timezone.override(pytz.timezone('Europe/Paris')): | ||||
|             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): | ||||
|         with timezone.override(pytz.timezone('Europe/Paris')): | ||||
|             form = EventForm({'dt': '2011-10-30 02:30:00'}) | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| from __future__ import unicode_literals | ||||
|  | ||||
| import sys | ||||
| from datetime import date, datetime | ||||
| from unittest import skipIf | ||||
|  | ||||
| from django.test import SimpleTestCase, override_settings | ||||
| 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, | ||||
| ) | ||||
|  | ||||
| try: | ||||
|     import pytz | ||||
| except ImportError: | ||||
|     pytz = None | ||||
|  | ||||
|  | ||||
| @override_settings(TIME_ZONE='Europe/Copenhagen') | ||||
| class DateFormatTests(SimpleTestCase): | ||||
| @@ -36,18 +29,16 @@ class DateFormatTests(SimpleTestCase): | ||||
|         dt = datetime(2009, 5, 16, 5, 30, 30) | ||||
|         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): | ||||
|         # dt is ambiguous in Europe/Copenhagen. LocalTimezone guesses the | ||||
|         # offset (and gets it wrong 50% of the time) while pytz refuses the | ||||
|         # temptation to guess. In any case, this shouldn't crash. | ||||
|         # dt is ambiguous in Europe/Copenhagen. pytz raises an exception for | ||||
|         # the ambiguity, which results in an empty string. | ||||
|         dt = datetime(2015, 10, 25, 2, 30, 0) | ||||
|  | ||||
|         # Try all formatters that involve self.timezone. | ||||
|         self.assertEqual(format(dt, 'I'), '0' if pytz is None else '') | ||||
|         self.assertEqual(format(dt, 'O'), '+0100' if pytz is None else '') | ||||
|         self.assertEqual(format(dt, 'T'), 'CET' if pytz is None else '') | ||||
|         self.assertEqual(format(dt, 'Z'), '3600' if pytz is None else '') | ||||
|         self.assertEqual(format(dt, 'I'), '') | ||||
|         self.assertEqual(format(dt, 'O'), '') | ||||
|         self.assertEqual(format(dt, 'T'), '') | ||||
|         self.assertEqual(format(dt, 'Z'), '') | ||||
|  | ||||
|     @requires_tz_support | ||||
|     def test_datetime_with_local_tzinfo(self): | ||||
|   | ||||
| @@ -1,21 +1,12 @@ | ||||
| import copy | ||||
| import datetime | ||||
| import pickle | ||||
| import sys | ||||
| import unittest | ||||
|  | ||||
| import pytz | ||||
|  | ||||
| from django.test import SimpleTestCase, mock, override_settings | ||||
| from django.utils import timezone | ||||
|  | ||||
| try: | ||||
|     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") | ||||
| CET = pytz.timezone("Europe/Paris") | ||||
| EAT = timezone.get_fixed_timezone(180)      # Africa/Nairobi | ||||
| ICT = timezone.get_fixed_timezone(420)      # Asia/Bangkok | ||||
|  | ||||
| @@ -24,33 +15,6 @@ PY36 = sys.version_info >= (3, 6) | ||||
|  | ||||
| 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): | ||||
|         with override_settings(USE_TZ=True): | ||||
|             self.assertTrue(timezone.is_aware(timezone.now())) | ||||
| @@ -133,18 +97,6 @@ class TimezoneTests(SimpleTestCase): | ||||
|         finally: | ||||
|             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): | ||||
|         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))) | ||||
| @@ -175,7 +127,6 @@ class TimezoneTests(SimpleTestCase): | ||||
|             with self.assertRaisesMessage(ValueError, 'astimezone() cannot be applied to a naive datetime'): | ||||
|                 timezone.make_naive(*args) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_make_aware2(self): | ||||
|         self.assertEqual( | ||||
|             timezone.make_aware(datetime.datetime(2011, 9, 1, 12, 20, 30), CET), | ||||
| @@ -183,7 +134,6 @@ class TimezoneTests(SimpleTestCase): | ||||
|         with self.assertRaises(ValueError): | ||||
|             timezone.make_aware(CET.localize(datetime.datetime(2011, 9, 1, 12, 20, 30)), CET) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_make_aware_pytz(self): | ||||
|         self.assertEqual( | ||||
|             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): | ||||
|                 timezone.make_naive(datetime.datetime(2011, 9, 1, 12, 20, 30), CET) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_make_aware_pytz_ambiguous(self): | ||||
|         # 2:30 happens twice, once before DST ends and once after | ||||
|         ambiguous = datetime.datetime(2015, 10, 25, 2, 30) | ||||
| @@ -216,7 +165,6 @@ class TimezoneTests(SimpleTestCase): | ||||
|         self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) | ||||
|         self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) | ||||
|  | ||||
|     @requires_pytz | ||||
|     def test_make_aware_pytz_non_existent(self): | ||||
|         # 2:30 never happened due to DST | ||||
|         non_existent = datetime.datetime(2015, 3, 29, 2, 30) | ||||
| @@ -229,9 +177,3 @@ class TimezoneTests(SimpleTestCase): | ||||
|         self.assertEqual(std - dst, datetime.timedelta(hours=1)) | ||||
|         self.assertEqual(std.tzinfo.utcoffset(std), datetime.timedelta(hours=1)) | ||||
|         self.assertEqual(dst.tzinfo.utcoffset(dst), datetime.timedelta(hours=2)) | ||||
|  | ||||
|         # round trip to UTC then back to CET | ||||
|         std = timezone.localtime(timezone.localtime(std, timezone.UTC()), CET) | ||||
|         dst = timezone.localtime(timezone.localtime(dst, timezone.UTC()), CET) | ||||
|         self.assertEqual((std.hour, std.minute), (3, 30)) | ||||
|         self.assertEqual((dst.hour, dst.minute), (1, 30)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user