mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Fixed #32365 -- Made zoneinfo the default timezone implementation.
Thanks to Adam Johnson, Aymeric Augustin, David Smith, Mariusz Felisiak, Nick Pope, and Paul Ganssle for reviews.
This commit is contained in:
parent
7132d17de1
commit
306607d5b9
27 changed files with 635 additions and 280 deletions
|
@ -242,7 +242,8 @@ Takes an ``expression`` representing a ``DateField``, ``DateTimeField``,
|
|||
of the date referenced by ``lookup_name`` as an ``IntegerField``.
|
||||
Django usually uses the databases' extract function, so you may use any
|
||||
``lookup_name`` that your database supports. A ``tzinfo`` subclass, usually
|
||||
provided by ``pytz``, can be passed to extract a value in a specific timezone.
|
||||
provided by :mod:`zoneinfo`, can be passed to extract a value in a specific
|
||||
timezone.
|
||||
|
||||
Given the datetime ``2015-06-15 23:30:01.000321+00:00``, the built-in
|
||||
``lookup_name``\s return:
|
||||
|
@ -450,8 +451,8 @@ to that timezone before the value is extracted. The example below converts to
|
|||
the Melbourne timezone (UTC +10:00), which changes the day, weekday, and hour
|
||||
values that are returned::
|
||||
|
||||
>>> import pytz
|
||||
>>> melb = pytz.timezone('Australia/Melbourne') # UTC+10:00
|
||||
>>> import zoneinfo
|
||||
>>> melb = zoneinfo.ZoneInfo('Australia/Melbourne') # UTC+10:00
|
||||
>>> with timezone.override(melb):
|
||||
... Experiment.objects.annotate(
|
||||
... day=ExtractDay('start_datetime'),
|
||||
|
@ -466,8 +467,8 @@ values that are returned::
|
|||
Explicitly passing the timezone to the ``Extract`` function behaves in the same
|
||||
way, and takes priority over an active timezone::
|
||||
|
||||
>>> import pytz
|
||||
>>> melb = pytz.timezone('Australia/Melbourne')
|
||||
>>> import zoneinfo
|
||||
>>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
|
||||
>>> Experiment.objects.annotate(
|
||||
... day=ExtractDay('start_datetime', tzinfo=melb),
|
||||
... weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
|
||||
|
@ -517,12 +518,16 @@ part, and an ``output_field`` that's either ``DateTimeField()``,
|
|||
``TimeField()``, or ``DateField()``. It returns a datetime, date, or time
|
||||
depending on ``output_field``, with fields up to ``kind`` set to their minimum
|
||||
value. If ``output_field`` is omitted, it will default to the ``output_field``
|
||||
of ``expression``. A ``tzinfo`` subclass, usually provided by ``pytz``, can be
|
||||
passed to truncate a value in a specific timezone.
|
||||
of ``expression``. A ``tzinfo`` subclass, usually provided by :mod:`zoneinfo`,
|
||||
can be passed to truncate a value in a specific timezone.
|
||||
|
||||
The ``is_dst`` parameter indicates whether or not ``pytz`` should interpret
|
||||
nonexistent and ambiguous datetimes in daylight saving time. By default (when
|
||||
``is_dst=None``), ``pytz`` raises an exception for such datetimes.
|
||||
.. deprecated:: 4.0
|
||||
|
||||
The ``is_dst`` parameter indicates whether or not ``pytz`` should interpret
|
||||
nonexistent and ambiguous datetimes in daylight saving time. By default
|
||||
(when ``is_dst=None``), ``pytz`` raises an exception for such datetimes.
|
||||
|
||||
The ``is_dst`` parameter is deprecated and will be removed in Django 5.0.
|
||||
|
||||
Given the datetime ``2015-06-15 14:30:50.000321+00:00``, the built-in ``kind``\s
|
||||
return:
|
||||
|
@ -607,6 +612,10 @@ Usage example::
|
|||
|
||||
.. attribute:: kind = 'quarter'
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
The ``is_dst`` parameter is deprecated and will be removed in Django 5.0.
|
||||
|
||||
These are logically equivalent to ``Trunc('date_field', kind)``. They truncate
|
||||
all parts of the date up to ``kind`` which allows grouping or filtering dates
|
||||
with less precision. ``expression`` can have an ``output_field`` of either
|
||||
|
@ -634,8 +643,8 @@ that deal with date-parts can be used with ``DateField``::
|
|||
2014-01-01 1
|
||||
2015-01-01 2
|
||||
|
||||
>>> import pytz
|
||||
>>> melb = pytz.timezone('Australia/Melbourne')
|
||||
>>> import zoneinfo
|
||||
>>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
|
||||
>>> experiments_per_month = Experiment.objects.annotate(
|
||||
... month=TruncMonth('start_datetime', tzinfo=melb)).values('month').annotate(
|
||||
... experiments=Count('id'))
|
||||
|
@ -691,6 +700,10 @@ truncate function. It's also registered as a transform on ``DateTimeField`` as
|
|||
|
||||
.. attribute:: kind = 'second'
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
The ``is_dst`` parameter is deprecated and will be removed in Django 5.0.
|
||||
|
||||
These are logically equivalent to ``Trunc('datetime_field', kind)``. They
|
||||
truncate all parts of the date up to ``kind`` and allow grouping or filtering
|
||||
datetimes with less precision. ``expression`` must have an ``output_field`` of
|
||||
|
@ -704,10 +717,10 @@ Usage example::
|
|||
... TruncDate, TruncDay, TruncHour, TruncMinute, TruncSecond,
|
||||
... )
|
||||
>>> from django.utils import timezone
|
||||
>>> import pytz
|
||||
>>> import zoneinfo
|
||||
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
|
||||
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
|
||||
>>> melb = pytz.timezone('Australia/Melbourne')
|
||||
>>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
|
||||
>>> Experiment.objects.annotate(
|
||||
... date=TruncDate('start_datetime'),
|
||||
... day=TruncDay('start_datetime', tzinfo=melb),
|
||||
|
@ -716,10 +729,10 @@ Usage example::
|
|||
... second=TruncSecond('start_datetime'),
|
||||
... ).values('date', 'day', 'hour', 'minute', 'second').get()
|
||||
{'date': datetime.date(2014, 6, 15),
|
||||
'day': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
|
||||
'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
|
||||
'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=<UTC>),
|
||||
'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=<UTC>)
|
||||
'day': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=zoneinfo.ZoneInfo('Australia/Melbourne')),
|
||||
'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=zoneinfo.ZoneInfo('Australia/Melbourne')),
|
||||
'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=zoneinfo.ZoneInfo('UTC')),
|
||||
'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=zoneinfo.ZoneInfo('UTC'))
|
||||
}
|
||||
|
||||
``TimeField`` truncation
|
||||
|
@ -740,6 +753,10 @@ Usage example::
|
|||
|
||||
.. attribute:: kind = 'second'
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
The ``is_dst`` parameter is deprecated and will be removed in Django 5.0.
|
||||
|
||||
These are logically equivalent to ``Trunc('time_field', kind)``. They truncate
|
||||
all parts of the time up to ``kind`` which allows grouping or filtering times
|
||||
with less precision. ``expression`` can have an ``output_field`` of either
|
||||
|
@ -767,8 +784,8 @@ that deal with time-parts can be used with ``TimeField``::
|
|||
14:00:00 2
|
||||
17:00:00 1
|
||||
|
||||
>>> import pytz
|
||||
>>> melb = pytz.timezone('Australia/Melbourne')
|
||||
>>> import zoneinfo
|
||||
>>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
|
||||
>>> experiments_per_hour = Experiment.objects.annotate(
|
||||
... hour=TruncHour('start_datetime', tzinfo=melb),
|
||||
... ).values('hour').annotate(experiments=Count('id'))
|
||||
|
|
|
@ -834,6 +834,10 @@ object. If it's ``None``, Django uses the :ref:`current time zone
|
|||
ambiguous datetimes in daylight saving time. By default (when ``is_dst=None``),
|
||||
``pytz`` raises an exception for such datetimes.
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
The ``is_dst`` parameter is deprecated and will be removed in Django 5.0.
|
||||
|
||||
.. _database-time-zone-definitions:
|
||||
|
||||
.. note::
|
||||
|
@ -842,13 +846,11 @@ ambiguous datetimes in daylight saving time. By default (when ``is_dst=None``),
|
|||
As a consequence, your database must be able to interpret the value of
|
||||
``tzinfo.tzname(None)``. This translates into the following requirements:
|
||||
|
||||
- SQLite: no requirements. Conversions are performed in Python with pytz_
|
||||
(installed when you install Django).
|
||||
- SQLite: no requirements. Conversions are performed in Python.
|
||||
- PostgreSQL: no requirements (see `Time Zones`_).
|
||||
- Oracle: no requirements (see `Choosing a Time Zone File`_).
|
||||
- MySQL: load the time zone tables with `mysql_tzinfo_to_sql`_.
|
||||
|
||||
.. _pytz: http://pytz.sourceforge.net/
|
||||
.. _Time Zones: https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-TIMEZONES
|
||||
.. _Choosing a Time Zone File: https://docs.oracle.com/en/database/oracle/
|
||||
oracle-database/18/nlspg/datetime-data-types-and-time-zone-support.html
|
||||
|
|
|
@ -677,8 +677,8 @@ When :setting:`USE_TZ` is ``False``, it is an error to set this option.
|
|||
otherwise, you should leave this option unset. It's best to store datetimes
|
||||
in UTC because it avoids ambiguous or nonexistent datetimes during daylight
|
||||
saving time changes. Also, receiving datetimes in UTC keeps datetime
|
||||
arithmetic simple — there's no need for the ``normalize()`` method provided
|
||||
by pytz.
|
||||
arithmetic simple — there's no need to consider potential offset changes
|
||||
over a DST transition.
|
||||
|
||||
* If you're connecting to a third-party database that stores datetimes in a
|
||||
local time rather than UTC, then you must set this option to the
|
||||
|
@ -695,8 +695,8 @@ When :setting:`USE_TZ` is ``False``, it is an error to set this option.
|
|||
as ``date_trunc``, because their results depend on the time zone.
|
||||
|
||||
However, this has a downside: receiving all datetimes in local time makes
|
||||
datetime arithmetic more tricky — you must call the ``normalize()`` method
|
||||
provided by pytz after each operation.
|
||||
datetime arithmetic more tricky — you must account for possible offset
|
||||
changes over DST transitions.
|
||||
|
||||
Consider converting to local time explicitly with ``AT TIME ZONE`` in raw SQL
|
||||
queries instead of setting the ``TIME_ZONE`` option.
|
||||
|
@ -2758,6 +2758,23 @@ the correct environment.
|
|||
|
||||
.. _list of time zones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
|
||||
.. setting:: USE_DEPRECATED_PYTZ
|
||||
|
||||
``USE_DEPRECATED_PYTZ``
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 4.0
|
||||
|
||||
Default: ``False``
|
||||
|
||||
A boolean that specifies whether to use ``pytz``, rather than :mod:`zoneinfo`,
|
||||
as the default time zone implementation.
|
||||
|
||||
.. deprecated:: 4.0
|
||||
|
||||
This transitional setting is deprecated. Support for using ``pytz`` will be
|
||||
removed in Django 5.0.
|
||||
|
||||
.. setting:: USE_I18N
|
||||
|
||||
``USE_I18N``
|
||||
|
|
|
@ -941,24 +941,30 @@ appropriate entities.
|
|||
:class:`~datetime.datetime`. If ``timezone`` is set to ``None``, it
|
||||
defaults to the :ref:`current time zone <default-current-time-zone>`.
|
||||
|
||||
When using ``pytz``, 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.
|
||||
.. deprecated:: 4.0
|
||||
|
||||
When using ``pytz``, the ``pytz.NonExistentTimeError`` exception is raised
|
||||
if you try to make ``value`` aware during a DST transition such that the
|
||||
time never occurred. For example, if the 2:00 hour is skipped during a DST
|
||||
transition, trying to make 2:30 aware in that time zone will raise an
|
||||
exception. To avoid that you can use ``is_dst`` to specify how
|
||||
``make_aware()`` should interpret such a nonexistent time. If
|
||||
``is_dst=True`` then the above time would be interpreted as 2:30 DST time
|
||||
(equivalent to 1:30 local time). Conversely, if ``is_dst=False`` the time
|
||||
would be interpreted as 2:30 standard time (equivalent to 3:30 local time).
|
||||
When using ``pytz``, 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.
|
||||
|
||||
The ``is_dst`` parameter has no effect when using non-``pytz`` timezone
|
||||
implementations.
|
||||
When using ``pytz``, the ``pytz.NonExistentTimeError`` exception is
|
||||
raised if you try to make ``value`` aware during a DST transition such
|
||||
that the time never occurred. For example, if the 2:00 hour is skipped
|
||||
during a DST transition, trying to make 2:30 aware in that time zone
|
||||
will raise an exception. To avoid that you can use ``is_dst`` to
|
||||
specify how ``make_aware()`` should interpret such a nonexistent time.
|
||||
If ``is_dst=True`` then the above time would be interpreted as 2:30 DST
|
||||
time (equivalent to 1:30 local time). Conversely, if ``is_dst=False``
|
||||
the time would be interpreted as 2:30 standard time (equivalent to 3:30
|
||||
local time).
|
||||
|
||||
The ``is_dst`` parameter has no effect when using non-``pytz`` timezone
|
||||
implementations.
|
||||
|
||||
The ``is_dst`` parameter is deprecated and will be removed in Django
|
||||
5.0.
|
||||
|
||||
.. function:: make_naive(value, timezone=None)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue