Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dateutil and pytz give different results

I have an issue comparing outputs with dateutil and pytz. I'm creating a aware datetime object (UTC) and then converting to a given time zone, but I get different answers. I suspect that dateutil sometimes gives wrong results because it has problems taking into account daylight saving time (at least, I read a comment about it) but I can't find confirmation or a fix to that issue. This is the code:

import dateutil

u = dateutil.tz.tzutc()
date1 = datetime.datetime(2010, 5, 2, 11, 10, tzinfo=u)
# 2010-05-02 11:10:00+00:00

u2 = dateutil.tz.gettz('America/Chicago')
date2 = datetime.datetime(2010, 5, 2, 11, 10, tzinfo=u2)
# 2010-05-02 11:10:00-05:00


import pytz
u = pytz.timezone('UTC')
date1 = datetime.datetime(2010, 5, 2, 11, 10, tzinfo=u)

# 2010-05-02 11:10:00+00:00
u2 = pytz.timezone('America/Chicago')
date2 = datetime.datetime(2010, 5, 2, 11, 10, tzinfo=u2)

# 2010-05-02 11:10:00-06:00

So, what could be the problem here?

UPDATE:

I just tried this:

print u2.normalize(date1.astimezone(u2))
# 2010-05-02 06:10:00-05:00

So pytz needs normalize to consider DST?

UPDATE 2:

It seemed as if pytz and dateutil don't give the answer for America/Argentina/San_Luis but this works:

import pytz, dateutil, datetime

now = datetime.datetime.now() 

for zone in pytz.all_timezones:
    utc_dateutil = dateutil.tz.tzutc()
    utcdate_dateutil = datetime.datetime(now.year, now.month, now.day, now.hour, now.minute, tzinfo=utc_dateutil)
    zone_dateutil = dateutil.tz.gettz(zone)
    newzone_dateutil = utcdate_dateutil.astimezone(zone_dateutil)

    utc_pytz = pytz.timezone('UTC')
    utcdate_pytz = datetime.datetime(now.year, now.month, now.day, now.hour, now.minute, tzinfo=utc_pytz)
    zone_pytz = pytz.timezone(zone)
    newzone_pytz = utcdate_pytz.astimezone(zone_pytz)
    assert newzone_dateutil == newzone_pytz

Am I missing something?

Thanks

like image 691
Robert Smith Avatar asked Dec 19 '12 02:12

Robert Smith


People also ask

What is pytz used for?

Pytz brings the Olson tz database into Python and thus supports almost all time zones. This module serves the date-time conversion functionalities and helps user serving international client's base.

What is Dateutil tz?

Functions. dateutil.tz. gettz (name=None) Retrieve a time zone object from a string representation. This function is intended to retrieve the tzinfo subclass that best represents the time zone that would be used if a POSIX TZ variable were set to the same value.

What is pytz UTC?

The pytz package encourages using UTC for internal timezone representation by including a special UTC implementation based on the standard Python reference implementation in the Python documentation. The UTC timezone unpickles to be the same instance, and pickles to a smaller size than other pytz tzinfo instances.


1 Answers

Edit: The discrepancy discussed below no longer exists when using

>>> dateutil.__version__
'1.5'

>>> pytz.__version__
'2012c'

The pytz module warns,

this library differs from the documented Python API for tzinfo implementations; if you want to create local wallclock times you need to use the localize() method

and further on

This library only supports two ways of building a localized time. The first is to use the localize() method provided by the pytz library.

In [61]: u4 = pytz.timezone('America/Chicago')
In [62]: print(u4.localize(datetime.datetime(2010, 5, 2, 11, 10)))
2010-05-02 11:10:00-05:00

The other way is to use the astimezone method, which is used to convert a timezone-aware datetime into another timezone-aware datetime.

And to be completely explicit, it warns against constructing a timezone-aware datetime using the tzinfo argument:

Unfortunately using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones.


Let's test the hypothesis that

datetime.datetime(year, month, day, hour, minute, tzinfo = dateutil_tz)

equals

pytz_tz.localize(datetime.datetime(year, month, day, hour, minute))

with this code:

import dateutil.tz
import datetime
import pytz

now  = datetime.datetime.now()

for name in pytz.all_timezones:
    dateutil_tz = dateutil.tz.gettz(name)
    pytz_tz = pytz.timezone(name)
    dateutil_date = datetime.datetime(
        now.year, now.month, now.day, now.hour, now.minute, tzinfo = dateutil_tz)
    pytz_date = pytz_tz.localize(datetime.datetime(
        now.year, now.month, now.day, now.hour, now.minute))

    try:
        assert dateutil_date.isoformat() == pytz_date.isoformat()
    except AssertionError:
        print(name)
        print(dateutil_date.isoformat())
        print(pytz_date.isoformat())           

The code yields:

America/Argentina/San_Luis
2012-12-18T22:32:00-04:00 <-- dateutil datetime
2012-12-18T22:32:00-03:00 <-- pytz's datetime

So my hypothesis was wrong: dateutil and pytz return different results.

So which one is correct? I'm not really sure, but according to this website, currently,

America/Argentina/San_Luis time zone offset is: 
UTC / GMT -03:00 hours

so it appears pytz is correct.

like image 159
unutbu Avatar answered Oct 11 '22 19:10

unutbu