Localized date/time hell

by George Y. Kussumoto

Once in a while we still need to work with localized dates instead of UTC and almost everytime we have bad surprises.

This time it was no different, but an example will demonstrate this better than words:

>>> from datetime import datetime
>>> from pytz import timezone

>>> tz = timezone('America/Sao_Paulo')
>>> datetime(2014, 11, 2, tzinfo=tz)
datetime.datetime(2014, 11, 2, 0, 0, tzinfo=<DstTzInfo 'America/Sao_Paulo' LMT-1 day, 20:54:00 STD>)
>>> tz.localize(datetime(2014, 11, 2)
datetime.datetime(2014, 11, 2, 0, 0, tzinfo=<DstTzInfo 'America/Sao_Paulo' BRST-1 day, 22:00:00 DST>)

Did you see that (LMT/BRST) ? WTF those dates are not equals ? Which one is correct ?

The answer is that the standard datetime module does not work with every timezones and we are advised to use pytz when working with localized date and times.

(So the second way is the correct one)

That hurts!

Notes

Actually, the use of pytz and datetime might still be broken if you use datetime.now, take a look:

>>> from datetime import datetime
>>> from pytz import timezone
>>> tz = timezone('America/Sao_Paulo')
>>> datetime.now().strftime('%Y-%m-%d %H:%M:%S %Z%z')
'2014-11-05 19:10:55 '
>>> tz.localize(datetime.now()).strftime('%Y-%m-%d %H:%M:%S %Z%z')
'2014-11-05 19:11:12 BRST-0200'

As you notice, there is no date and time convertion, just a setting of timezones. And it is also true if we use datetime.utcnow.

One way to workaround this is to use python-dateutil or Arrow:

>>> from dateutil.tz import gettz
>>> from datetime import datetime
>>> import arrow
>>> tz = gettz('America/Sao_Paulo')
>>> datetime.now(tz).strftime('%Y-%m-%d %H:%M:%S %Z%z')
'2014-11-05 19:19:56 BRST-0200'
>>> datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S %Z%z')
'2014-11-05 21:20:58 '
>>> arrow.now('America/Sao_Paulo').strftime('%Y-%m-%d %H:%M:%S %Z%z')
'2014-11-05 19:26:03 BRST-0200'

o/