I'm using django 1.11 and pytz 2018.6
I'm having some problems understanding how django is dealing with DST.
My main problem is localizing the date 2018-11-04 00:00:00
in the America/Sao_Paulo
timezone. According to the latest pytz version this is the date when DST starts in this timezone in 2018.
Well, on my application I started seeing the pytz.exceptions.NonExistentTimeError
exception when trying to localize the mentioned date. The following code reproduces this exception:
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
However, if I try to localize using pytz.localize
instead of make_aware
I get different results:
sp.localize(dst_start_date) # Returns 2018-11-04 00:00:00-03:00
I expected to receive the same exception when trying to localize. But it didn't raise the exception and actually returned a wrong result (the -03:00
offset is when we're not on DST. On the specific date I was expecting the 2018-11-04 00:00:00-03:00
date to be converted to 2018-11-04 00:00:00-02:00
).
This confuses me, because reading the make_aware
code in django.utils.timezone
I understood the same pytz.tzinfo.localize
method is called.
# 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)
Why are both results different? Why I'm not getting an exception when manually trying to localize the date 2018-11-04 00:00:00
to America/Sao_Paulo
?
Please make sure you have the latest pytz version (pip install pytz --upgrade
) before trying this code because we had a change on the DST date this year.
The difference is the is_dst
parameter passed to localize
. When you call it yourself but leave it off, it defaults to False
. In the make_aware
code you posted it defaults to None
.