summaryrefslogtreecommitdiff
path: root/django/utils/timezone.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/utils/timezone.py')
-rw-r--r--django/utils/timezone.py73
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):