Skip to content

Commit

Permalink
ENH: Use datetutil.tz.gettz() instead of dateutil.zoneinfo.gettz()
Browse files Browse the repository at this point in the history
python-dateutil provides two implementations for gettz(), tz.gettz() and
zoneinfo.gettz(). The former tries first to use system provided timezone data,
where as the later always uses a bundled tarball. Upstreams recommandation
for library consumers is only using tz.gettz() (1 & 2). Further more, on
system which do not install the zoninfo tarball (e.g. Debian, Gentoo and
Fedora) but rely on the system zoneinfo files the direct usage of
zoneinfo.gettz() creates problems which result in test failures (3 - 6).

For compatibility in pandas code

    pandas.tslib._dateutil_gettz()

should be used.

1 dateutil/dateutil#8
2 dateutil/dateutil#11
3 pandas-dev#9059
4 pandas-dev#8639
5 pandas-dev#10121
6 pandas-dev#9663

Signed-off-by: Justin Lecher <jlec@gentoo.org>
  • Loading branch information
jlec committed May 15, 2015
1 parent cf96024 commit d638212
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 12 deletions.
23 changes: 21 additions & 2 deletions doc/source/whatsnew/v0.17.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ New features
Other enhancements
^^^^^^^^^^^^^^^^^^

- Add helper functions to check for OS running on

from pandas.compat import is_platform_windows
if is_platform_window():
pass

- Use dateutil.tz.gettz() after upstream recommandations

python-dateutil provides two implementations of gettz().
"dateutil.tz.gettz()" tries to load zone information from system provided data and fals back to
an included tarball, where as "dateutil.zoneinfo.gettz() loads directly from the tarball. Using the later on systems
which aren't providing included zone informations (e.g. Fedora or Gentoo) breaks (#9059, #8639, #9663 and #10121)
As stated by upstream in https://github.com/dateutil/dateutil/issues/11#issuecomment-70769019 only the former should be
used by library consumers.

For compatibility in pandas following code should be used

from pandas.tslib import _dateutil_gettz as gettz
tz = gettz('Europe/Brussels')

.. _whatsnew_0170.api:

Backwards incompatible API changes
Expand Down Expand Up @@ -66,5 +86,4 @@ Bug Fixes
- Bug in ``Timestamp``'s' ``microsecond``, ``quarter``, ``dayofyear``, ``week`` and ``daysinmonth`` properties return ``np.int`` type, not built-in ``int``. (:issue:`10050`)
- Bug in ``NaT`` raises ``AttributeError`` when accessing to ``daysinmonth``, ``dayofweek`` properties. (:issue:`10096`)



- Bug in dateutil.tz.gettz() vs. dateutil.zoneinfo.gettz() usage which creates problems on systems solely rely on systems timezone data (:issue:`9123`, :issue:`9059`, :issue:`8639`, :issue:`9663`, :issue:`10121`)
14 changes: 14 additions & 0 deletions pandas/compat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
Other items:
* OrderedDefaultDict
* platform checker
"""
# pylint disable=W0611
import functools
Expand Down Expand Up @@ -754,3 +755,16 @@ def __missing__(self, key):
def __reduce__(self): # optional, for pickle support
args = self.default_factory if self.default_factory else tuple()
return type(self), args, None, None, list(self.items())


# https://github.com/pydata/pandas/pull/9123
def is_platform_windows():
return sys.platform == 'win32' or sys.platform == 'cygwin'


def is_platform_linux():
return sys.platform == 'linux2'


def is_platform_mac():
return sys.platform == 'darwin'
3 changes: 2 additions & 1 deletion pandas/tests/test_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -5398,7 +5398,8 @@ def test_getitem_setitem_datetime_tz_pytz(self):
def test_getitem_setitem_datetime_tz_dateutil(self):
tm._skip_if_no_dateutil();
from dateutil.tz import tzutc
from dateutil.tz import gettz
from pandas.tslib import _dateutil_gettz as gettz

tz = lambda x: tzutc() if x == 'UTC' else gettz(x) # handle special case for utc in dateutil

from pandas import date_range
Expand Down
2 changes: 1 addition & 1 deletion pandas/tseries/tests/test_daterange.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ def test_month_range_union_tz_pytz(self):
def test_month_range_union_tz_dateutil(self):
_skip_if_windows_python_3()
tm._skip_if_no_dateutil()
from dateutil.tz import gettz as timezone
from pandas.tslib import _dateutil_gettz as timezone
tz = timezone('US/Eastern')

early_start = datetime(2011, 1, 1)
Expand Down
8 changes: 4 additions & 4 deletions pandas/tseries/tests/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,15 @@ def test_timestamp_tz_arg(self):
pytz.timezone('Europe/Brussels').normalize(p).tzinfo)

def test_timestamp_tz_arg_dateutil(self):
import dateutil
from pandas.tslib import _dateutil_gettz as gettz
from pandas.tslib import maybe_get_tz
p = Period('1/1/2005', freq='M').to_timestamp(tz=maybe_get_tz('dateutil/Europe/Brussels'))
self.assertEqual(p.tz, dateutil.tz.gettz('Europe/Brussels'))
self.assertEqual(p.tz, gettz('Europe/Brussels'))

def test_timestamp_tz_arg_dateutil_from_string(self):
import dateutil
from pandas.tslib import _dateutil_gettz as gettz
p = Period('1/1/2005', freq='M').to_timestamp(tz='dateutil/Europe/Brussels')
self.assertEqual(p.tz, dateutil.tz.gettz('Europe/Brussels'))
self.assertEqual(p.tz, gettz('Europe/Brussels'))

def test_timestamp_nat_tz(self):
t = Period('NaT', freq='M').to_timestamp()
Expand Down
6 changes: 3 additions & 3 deletions pandas/tseries/tests/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,9 @@ def test_timestamp_to_datetime_explicit_pytz(self):
def test_timestamp_to_datetime_explicit_dateutil(self):
_skip_if_windows_python_3()
tm._skip_if_no_dateutil()
import dateutil
from pandas.tslib import _dateutil_gettz as gettz
rng = date_range('20090415', '20090519',
tz=dateutil.tz.gettz('US/Eastern'))
tz=gettz('US/Eastern'))

stamp = rng[0]
dtval = stamp.to_pydatetime()
Expand Down Expand Up @@ -1807,7 +1807,7 @@ def test_append_concat_tz_explicit_pytz(self):
def test_append_concat_tz_dateutil(self):
# GH 2938
tm._skip_if_no_dateutil()
from dateutil.tz import gettz as timezone
from pandas.tslib import _dateutil_gettz as timezone

rng = date_range('5/8/2012 1:45', periods=10, freq='5T',
tz='dateutil/US/Eastern')
Expand Down
6 changes: 5 additions & 1 deletion pandas/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ from datetime import time as datetime_time
# dateutil compat
from dateutil.tz import (tzoffset, tzlocal as _dateutil_tzlocal, tzfile as _dateutil_tzfile,
tzutc as _dateutil_tzutc)
from dateutil.tz import gettz as _dateutil_gettz
from pandas.compat import is_platform_windows
if is_platform_windows():
from dateutil.zoneinfo import gettz as _dateutil_gettz
else:
from dateutil.tz import gettz as _dateutil_gettz

from pytz.tzinfo import BaseTzInfo as _pytz_BaseTzInfo
from pandas.compat import parse_date, string_types, PY3, iteritems
Expand Down

0 comments on commit d638212

Please sign in to comment.