Я использую django 1.11 и pytz 2018.6
У меня проблемы с пониманием того, как django работает с DST.
Моя основная проблема - это локализация даты 2018-11-04 00:00:00
в часовом поясе America/Sao_Paulo
. Согласно последней версии pytz, это дата начала летнего времени в этом часовом поясе в 2018 году.
Что ж, в моем приложении я начал видеть исключение pytz.exceptions.NonExistentTimeError
при попытке локализовать указанную дату. Следующий код воспроизводит это исключение:
import os
import datetime
import django
import pytz
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings")
django.setup()
from django.utils.timezone import make_aware
sp = pytz.timezone('America/Sao_Paulo')
dst_start_date = datetime.datetime(2018, 11, 4, 0, 0, 0)
make_aware(dst_start_date, sp)
# Exception raised: pytz.exceptions.NonExistentTimeError: 2018-11-04 00:00:00
Однако, если я попытаюсь локализовать с помощью pytz.localize
вместо make_aware
, я получу другие результаты:
sp.localize(dst_start_date) # Returns 2018-11-04 00:00:00-03:00
Я ожидал получить такое же исключение при попытке локализации. Но это не вызвало исключения и фактически вернуло неправильный результат (смещение -03:00
- это когда мы не на летнем времени. В конкретную дату я ожидал, что дата 2018-11-04 00:00:00-03:00
будет преобразована в 2018-11-04 00:00:00-02:00
).
Это меня смущает, потому что читая код make_aware
в django.utils.timezone
, я понял, что вызывается тот же метод pytz.tzinfo.localize
.
# django.utils.timezone
def make_aware(value, timezone=None, is_dst=None):
"""
Makes a naive datetime.datetime in a given time zone aware.
"""
if timezone is None:
timezone = get_current_timezone()
if hasattr(timezone, 'localize'):
# This method is available for pytz time zones.
return timezone.localize(value, is_dst=is_dst)
else:
# Check that we won't overwrite the timezone of an aware datetime.
if is_aware(value):
raise ValueError(
"make_aware expects a naive datetime, got %s" % value)
# This may be wrong around DST changes!
return value.replace(tzinfo=timezone)
Почему оба результата разные? Почему я не получаю исключение при попытке вручную локализовать дату с 2018-11-04 00:00:00
на America/Sao_Paulo
?
Перед тем, как попробовать этот код, убедитесь, что у вас установлена последняя версия pytz (pip install pytz --upgrade
), потому что в этом году мы изменили дату летнего времени.
Разница в параметре is_dst
, переданном в localize
. Когда вы сами называете его, но не используете, по умолчанию используется False
. В коде make_aware
, который вы разместили, по умолчанию используется None
.
Вау, это именно то, что вам нужно! Спасибо!