Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/utils/timezone.py: 6%
126 statements
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:13 +0000
« prev ^ index » next coverage.py v7.0.5, created at 2023-01-17 06:13 +0000
1"""
2Timezone-related classes and functions.
3"""
5import functools
6import sys
7import warnings
9try:
10 import zoneinfo
11except ImportError:
12 from backports import zoneinfo
14from contextlib import ContextDecorator
15from datetime import datetime, timedelta, timezone, tzinfo
17from asgiref.local import Local
19from django.conf import settings
20from django.utils.deprecation import RemovedInDjango50Warning
22__all__ = [ # noqa for utc RemovedInDjango50Warning.
23 "utc",
24 "get_fixed_timezone",
25 "get_default_timezone",
26 "get_default_timezone_name",
27 "get_current_timezone",
28 "get_current_timezone_name",
29 "activate",
30 "deactivate",
31 "override",
32 "localtime",
33 "localdate",
34 "now",
35 "is_aware",
36 "is_naive",
37 "make_aware",
38 "make_naive",
39]
41# RemovedInDjango50Warning: sentinel for deprecation of is_dst parameters.
42NOT_PASSED = object()
45def __getattr__(name):
46 if name != "utc":
47 raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
49 warnings.warn(
50 "The django.utils.timezone.utc alias is deprecated. "
51 "Please update your code to use datetime.timezone.utc instead.",
52 RemovedInDjango50Warning,
53 stacklevel=2,
54 )
56 return timezone.utc
59def get_fixed_timezone(offset):
60 """Return a tzinfo instance with a fixed offset from UTC."""
61 if isinstance(offset, timedelta):
62 offset = offset.total_seconds() // 60
63 sign = "-" if offset < 0 else "+"
64 hhmm = "%02d%02d" % divmod(abs(offset), 60)
65 name = sign + hhmm
66 return timezone(timedelta(minutes=offset), name)
69# In order to avoid accessing settings at compile time,
70# wrap the logic in a function and cache the result.
71@functools.lru_cache
72def get_default_timezone():
73 """
74 Return the default time zone as a tzinfo instance.
76 This is the time zone defined by settings.TIME_ZONE.
77 """
78 if settings.USE_DEPRECATED_PYTZ:
79 import pytz
81 return pytz.timezone(settings.TIME_ZONE)
82 return zoneinfo.ZoneInfo(settings.TIME_ZONE)
85# This function exists for consistency with get_current_timezone_name
86def get_default_timezone_name():
87 """Return the name of the default time zone."""
88 return _get_timezone_name(get_default_timezone())
91_active = Local()
94def get_current_timezone():
95 """Return the currently active time zone as a tzinfo instance."""
96 return getattr(_active, "value", get_default_timezone())
99def get_current_timezone_name():
100 """Return the name of the currently active time zone."""
101 return _get_timezone_name(get_current_timezone())
104def _get_timezone_name(timezone):
105 """
106 Return the offset for fixed offset timezones, or the name of timezone if
107 not set.
108 """
109 return timezone.tzname(None) or str(timezone)
112# Timezone selection functions.
114# These functions don't change os.environ['TZ'] and call time.tzset()
115# because it isn't thread safe.
118def activate(timezone):
119 """
120 Set the time zone for the current thread.
122 The ``timezone`` argument must be an instance of a tzinfo subclass or a
123 time zone name.
124 """
125 if isinstance(timezone, tzinfo):
126 _active.value = timezone
127 elif isinstance(timezone, str):
128 if settings.USE_DEPRECATED_PYTZ:
129 import pytz
131 _active.value = pytz.timezone(timezone)
132 else:
133 _active.value = zoneinfo.ZoneInfo(timezone)
134 else:
135 raise ValueError("Invalid timezone: %r" % timezone)
138def deactivate():
139 """
140 Unset the time zone for the current thread.
142 Django will then use the time zone defined by settings.TIME_ZONE.
143 """
144 if hasattr(_active, "value"):
145 del _active.value
148class override(ContextDecorator):
149 """
150 Temporarily set the time zone for the current thread.
152 This is a context manager that uses django.utils.timezone.activate()
153 to set the timezone on entry and restores the previously active timezone
154 on exit.
156 The ``timezone`` argument must be an instance of a ``tzinfo`` subclass, a
157 time zone name, or ``None``. If it is ``None``, Django enables the default
158 time zone.
159 """
161 def __init__(self, timezone):
162 self.timezone = timezone
164 def __enter__(self):
165 self.old_timezone = getattr(_active, "value", None)
166 if self.timezone is None:
167 deactivate()
168 else:
169 activate(self.timezone)
171 def __exit__(self, exc_type, exc_value, traceback):
172 if self.old_timezone is None:
173 deactivate()
174 else:
175 _active.value = self.old_timezone
178# Templates
181def template_localtime(value, use_tz=None):
182 """
183 Check if value is a datetime and converts it to local time if necessary.
185 If use_tz is provided and is not None, that will force the value to
186 be converted (or not), overriding the value of settings.USE_TZ.
188 This function is designed for use by the template engine.
189 """
190 should_convert = (
191 isinstance(value, datetime)
192 and (settings.USE_TZ if use_tz is None else use_tz)
193 and not is_naive(value)
194 and getattr(value, "convert_to_local_time", True)
195 )
196 return localtime(value) if should_convert else value
199# Utilities
202def localtime(value=None, timezone=None):
203 """
204 Convert an aware datetime.datetime to local time.
206 Only aware datetimes are allowed. When value is omitted, it defaults to
207 now().
209 Local time is defined by the current time zone, unless another time zone
210 is specified.
211 """
212 if value is None:
213 value = now()
214 if timezone is None:
215 timezone = get_current_timezone()
216 # Emulate the behavior of astimezone() on Python < 3.6.
217 if is_naive(value):
218 raise ValueError("localtime() cannot be applied to a naive datetime")
219 return value.astimezone(timezone)
222def localdate(value=None, timezone=None):
223 """
224 Convert an aware datetime to local time and return the value's date.
226 Only aware datetimes are allowed. When value is omitted, it defaults to
227 now().
229 Local time is defined by the current time zone, unless another time zone is
230 specified.
231 """
232 return localtime(value, timezone).date()
235def now():
236 """
237 Return an aware or naive datetime.datetime, depending on settings.USE_TZ.
238 """
239 return datetime.now(tz=timezone.utc if settings.USE_TZ else None)
242# By design, these four functions don't perform any checks on their arguments.
243# The caller should ensure that they don't receive an invalid value like None.
246def is_aware(value):
247 """
248 Determine if a given datetime.datetime is aware.
250 The concept is defined in Python's docs:
251 https://docs.python.org/library/datetime.html#datetime.tzinfo
253 Assuming value.tzinfo is either None or a proper datetime.tzinfo,
254 value.utcoffset() implements the appropriate logic.
255 """
256 return value.utcoffset() is not None
259def is_naive(value):
260 """
261 Determine if a given datetime.datetime is naive.
263 The concept is defined in Python's docs:
264 https://docs.python.org/library/datetime.html#datetime.tzinfo
266 Assuming value.tzinfo is either None or a proper datetime.tzinfo,
267 value.utcoffset() implements the appropriate logic.
268 """
269 return value.utcoffset() is None
272def make_aware(value, timezone=None, is_dst=NOT_PASSED):
273 """Make a naive datetime.datetime in a given time zone aware."""
274 if is_dst is NOT_PASSED:
275 is_dst = None
276 else:
277 warnings.warn(
278 "The is_dst argument to make_aware(), used by the Trunc() "
279 "database functions and QuerySet.datetimes(), is deprecated as it "
280 "has no effect with zoneinfo time zones.",
281 RemovedInDjango50Warning,
282 )
283 if timezone is None:
284 timezone = get_current_timezone()
285 if _is_pytz_zone(timezone):
286 # This method is available for pytz time zones.
287 return timezone.localize(value, is_dst=is_dst)
288 else:
289 # Check that we won't overwrite the timezone of an aware datetime.
290 if is_aware(value):
291 raise ValueError("make_aware expects a naive datetime, got %s" % value)
292 # This may be wrong around DST changes!
293 return value.replace(tzinfo=timezone)
296def make_naive(value, timezone=None):
297 """Make an aware datetime.datetime naive in a given time zone."""
298 if timezone is None:
299 timezone = get_current_timezone()
300 # Emulate the behavior of astimezone() on Python < 3.6.
301 if is_naive(value):
302 raise ValueError("make_naive() cannot be applied to a naive datetime")
303 return value.astimezone(timezone).replace(tzinfo=None)
306_PYTZ_IMPORTED = False
309def _pytz_imported():
310 """
311 Detects whether or not pytz has been imported without importing pytz.
313 Copied from pytz_deprecation_shim with thanks to Paul Ganssle.
314 """
315 global _PYTZ_IMPORTED
317 if not _PYTZ_IMPORTED and "pytz" in sys.modules:
318 _PYTZ_IMPORTED = True
320 return _PYTZ_IMPORTED
323def _is_pytz_zone(tz):
324 """Checks if a zone is a pytz zone."""
325 # See if pytz was already imported rather than checking
326 # settings.USE_DEPRECATED_PYTZ to *allow* manually passing a pytz timezone,
327 # which some of the test cases (at least) rely on.
328 if not _pytz_imported():
329 return False
331 # If tz could be pytz, then pytz is needed here.
332 import pytz
334 _PYTZ_BASE_CLASSES = (pytz.tzinfo.BaseTzInfo, pytz._FixedOffset)
335 # In releases prior to 2018.4, pytz.UTC was not a subclass of BaseTzInfo
336 if not isinstance(pytz.UTC, pytz._FixedOffset):
337 _PYTZ_BASE_CLASSES += (type(pytz.UTC),)
339 return isinstance(tz, _PYTZ_BASE_CLASSES)
342def _datetime_ambiguous_or_imaginary(dt, tz):
343 if _is_pytz_zone(tz):
344 import pytz
346 try:
347 tz.utcoffset(dt)
348 except (pytz.AmbiguousTimeError, pytz.NonExistentTimeError):
349 return True
350 else:
351 return False
353 return tz.utcoffset(dt.replace(fold=not dt.fold)) != tz.utcoffset(dt)
356# RemovedInDjango50Warning.
357_DIR = dir()
360def __dir__():
361 return sorted([*_DIR, "utc"])