diff options
Diffstat (limited to 'django/utils/timezone.py')
| -rw-r--r-- | django/utils/timezone.py | 73 |
1 files changed, 63 insertions, 10 deletions
diff --git a/django/utils/timezone.py b/django/utils/timezone.py index 0f5d012c59..0c23486c1f 100644 --- a/django/utils/timezone.py +++ b/django/utils/timezone.py @@ -3,13 +3,21 @@ Timezone-related classes and functions. """ import functools +import sys +import warnings + +try: + import zoneinfo +except ImportError: + from backports import zoneinfo + from contextlib import ContextDecorator from datetime import datetime, timedelta, timezone, tzinfo -import pytz from asgiref.local import Local from django.conf import settings +from django.utils.deprecation import RemovedInDjango50Warning __all__ = [ 'utc', 'get_fixed_timezone', @@ -20,14 +28,11 @@ __all__ = [ 'is_aware', 'is_naive', 'make_aware', 'make_naive', ] +# RemovedInDjango50Warning: sentinel for deprecation of is_dst parameters. +NOT_PASSED = object() -# UTC time zone as a tzinfo instance. -utc = pytz.utc -_PYTZ_BASE_CLASSES = (pytz.tzinfo.BaseTzInfo, pytz._FixedOffset) -# In releases prior to 2018.4, pytz.UTC was not a subclass of BaseTzInfo -if not isinstance(pytz.UTC, pytz._FixedOffset): - _PYTZ_BASE_CLASSES = _PYTZ_BASE_CLASSES + (type(pytz.UTC),) +utc = timezone.utc def get_fixed_timezone(offset): @@ -49,7 +54,10 @@ def get_default_timezone(): This is the time zone defined by settings.TIME_ZONE. """ - return pytz.timezone(settings.TIME_ZONE) + if settings.USE_DEPRECATED_PYTZ: + import pytz + return pytz.timezone(settings.TIME_ZONE) + return zoneinfo.ZoneInfo(settings.TIME_ZONE) # This function exists for consistency with get_current_timezone_name @@ -94,7 +102,11 @@ def activate(timezone): if isinstance(timezone, tzinfo): _active.value = timezone elif isinstance(timezone, str): - _active.value = pytz.timezone(timezone) + if settings.USE_DEPRECATED_PYTZ: + import pytz + _active.value = pytz.timezone(timezone) + else: + _active.value = zoneinfo.ZoneInfo(timezone) else: raise ValueError("Invalid timezone: %r" % timezone) @@ -229,8 +241,17 @@ def is_naive(value): return value.utcoffset() is None -def make_aware(value, timezone=None, is_dst=None): +def make_aware(value, timezone=None, is_dst=NOT_PASSED): """Make a naive datetime.datetime in a given time zone aware.""" + if is_dst is NOT_PASSED: + is_dst = None + else: + warnings.warn( + 'The is_dst argument to make_aware(), used by the Trunc() ' + 'database functions and QuerySet.datetimes(), is deprecated as it ' + 'has no effect with zoneinfo time zones.', + RemovedInDjango50Warning, + ) if timezone is None: timezone = get_current_timezone() if _is_pytz_zone(timezone): @@ -255,13 +276,45 @@ def make_naive(value, timezone=None): return value.astimezone(timezone).replace(tzinfo=None) +_PYTZ_IMPORTED = False + + +def _pytz_imported(): + """ + Detects whether or not pytz has been imported without importing pytz. + + Copied from pytz_deprecation_shim with thanks to Paul Ganssle. + """ + global _PYTZ_IMPORTED + + if not _PYTZ_IMPORTED and "pytz" in sys.modules: + _PYTZ_IMPORTED = True + + return _PYTZ_IMPORTED + + def _is_pytz_zone(tz): """Checks if a zone is a pytz zone.""" + # See if pytz was already imported rather than checking + # settings.USE_DEPRECATED_PYTZ to *allow* manually passing a pytz timezone, + # which some of the test cases (at least) rely on. + if not _pytz_imported(): + return False + + # If tz could be pytz, then pytz is needed here. + import pytz + + _PYTZ_BASE_CLASSES = (pytz.tzinfo.BaseTzInfo, pytz._FixedOffset) + # In releases prior to 2018.4, pytz.UTC was not a subclass of BaseTzInfo + if not isinstance(pytz.UTC, pytz._FixedOffset): + _PYTZ_BASE_CLASSES = _PYTZ_BASE_CLASSES + (type(pytz.UTC),) + return isinstance(tz, _PYTZ_BASE_CLASSES) def _datetime_ambiguous_or_imaginary(dt, tz): if _is_pytz_zone(tz): + import pytz try: tz.utcoffset(dt) except (pytz.AmbiguousTimeError, pytz.NonExistentTimeError): |
