Skip to content

Commit 93f59a3

Browse files
committed
BUG: DTI doesnt handle tzlocal properly
1 parent ba82b51 commit 93f59a3

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

doc/source/whatsnew/v0.19.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,8 @@ Bug Fixes
480480
- Bug in ``.resample(..)`` with a ``PeriodIndex`` not retaining its type or name with an empty ``DataFrame`` appropriately when empty (:issue:`13212`)
481481
- Bug in ``groupby(..).resample(..)`` where passing some keywords would raise an exception (:issue:`13235`)
482482
- Bug in ``.tz_convert`` on a tz-aware ``DateTimeIndex`` that relied on index being sorted for correct results (:issue:`13306`)
483+
- Bug in ``.tz_localize`` with ``dateutil.tz.tzlocal`` may return incorrect result (:issue:`13583`)
484+
- Bug in ``DatetimeTZDtype`` dtype with ``dateutil.tz.tzlocal`` cannot be regarded as valid dtype (:issue:`13583`)
483485
- Bug in ``pd.read_hdf()`` where attempting to load an HDF file with a single dataset, that had one or more categorical columns, failed unless the key argument was set to the name of the dataset. (:issue:`13231`)
484486
- Bug in ``.rolling()`` that allowed a negative integer window in contruction of the ``Rolling()`` object, but would later fail on aggregation (:issue:`13383`)
485487

pandas/tools/tests/test_merge.py

+12
Original file line numberDiff line numberDiff line change
@@ -1263,6 +1263,18 @@ def test_concat_tz_series_with_datetimelike(self):
12631263
result = concat([pd.Series(x), pd.Series(y)], ignore_index=True)
12641264
tm.assert_series_equal(result, pd.Series(x + y, dtype='object'))
12651265

1266+
def test_concat_tz_series_tzlocal(self):
1267+
# GH 13583
1268+
tm._skip_if_no_dateutil()
1269+
import dateutil
1270+
x = [pd.Timestamp('2011-01-01', tz=dateutil.tz.tzlocal()),
1271+
pd.Timestamp('2011-02-01', tz=dateutil.tz.tzlocal())]
1272+
y = [pd.Timestamp('2012-01-01', tz=dateutil.tz.tzlocal()),
1273+
pd.Timestamp('2012-02-01', tz=dateutil.tz.tzlocal())]
1274+
result = concat([pd.Series(x), pd.Series(y)], ignore_index=True)
1275+
tm.assert_series_equal(result, pd.Series(x + y))
1276+
self.assertEqual(result.dtype, 'datetime64[ns, tzlocal()]')
1277+
12661278
def test_concat_period_series(self):
12671279
x = Series(pd.PeriodIndex(['2015-11-01', '2015-12-01'], freq='D'))
12681280
y = Series(pd.PeriodIndex(['2015-10-01', '2016-01-01'], freq='D'))

pandas/tseries/tests/test_timezones.py

+40
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,46 @@ def test_tslib_tz_convert_dst(self):
10611061
self.assert_numpy_array_equal(idx.hour,
10621062
np.array([4, 4], dtype=np.int32))
10631063

1064+
def test_tzlocal(self):
1065+
# GH 13583
1066+
ts = Timestamp('2011-01-01', tz=dateutil.tz.tzlocal())
1067+
self.assertEqual(ts.tz, dateutil.tz.tzlocal())
1068+
self.assertTrue("tz='tzlocal()')" in repr(ts))
1069+
1070+
tz = tslib.maybe_get_tz('tzlocal()')
1071+
self.assertEqual(tz, dateutil.tz.tzlocal())
1072+
1073+
# get offset using normal datetime for test
1074+
offset = dateutil.tz.tzlocal().utcoffset(datetime(2011, 1, 1))
1075+
offset = offset.total_seconds() * 1000000000
1076+
self.assertEqual(ts.value + offset, Timestamp('2011-01-01').value)
1077+
1078+
def test_tz_localize_tzlocal(self):
1079+
# GH 13583
1080+
offset = dateutil.tz.tzlocal().utcoffset(datetime(2011, 1, 1))
1081+
offset = int(offset.total_seconds() * 1000000000)
1082+
1083+
dti = date_range(start='2001-01-01', end='2001-03-01')
1084+
dti2 = dti.tz_localize(dateutil.tz.tzlocal())
1085+
tm.assert_numpy_array_equal(dti2.asi8 + offset, dti.asi8)
1086+
1087+
dti = date_range(start='2001-01-01', end='2001-03-01',
1088+
tz=dateutil.tz.tzlocal())
1089+
dti2 = dti.tz_localize(None)
1090+
tm.assert_numpy_array_equal(dti2.asi8 - offset, dti.asi8)
1091+
1092+
def test_tz_convert_tzlocal(self):
1093+
# GH 13583
1094+
# tz_convert doesn't affect to internal
1095+
dti = date_range(start='2001-01-01', end='2001-03-01', tz='UTC')
1096+
dti2 = dti.tz_convert(dateutil.tz.tzlocal())
1097+
tm.assert_numpy_array_equal(dti2.asi8, dti.asi8)
1098+
1099+
dti = date_range(start='2001-01-01', end='2001-03-01',
1100+
tz=dateutil.tz.tzlocal())
1101+
dti2 = dti.tz_convert(None)
1102+
tm.assert_numpy_array_equal(dti2.asi8, dti.asi8)
1103+
10641104

10651105
class TestTimeZoneCacheKey(tm.TestCase):
10661106
def test_cache_keys_are_distinct_for_pytz_vs_dateutil(self):

pandas/tslib.pyx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,9 @@ cpdef inline object maybe_get_tz(object tz):
15911591
Otherwise, just return tz.
15921592
"""
15931593
if isinstance(tz, string_types):
1594-
if tz.startswith('dateutil/'):
1594+
if tz == 'tzlocal()':
1595+
tz = _dateutil_tzlocal()
1596+
elif tz.startswith('dateutil/'):
15951597
zone = tz[9:]
15961598
tz = _dateutil_gettz(zone)
15971599
# On Python 3 on Windows, the filename is not always set correctly.
@@ -3767,7 +3769,6 @@ def tz_convert(ndarray[int64_t] vals, object tz1, object tz2):
37673769
return np.array([], dtype=np.int64)
37683770

37693771
# Convert to UTC
3770-
37713772
if _get_zone(tz1) != 'UTC':
37723773
utc_dates = np.empty(n, dtype=np.int64)
37733774
if _is_tzlocal(tz1):
@@ -3822,7 +3823,7 @@ def tz_convert(ndarray[int64_t] vals, object tz1, object tz2):
38223823
dts.min, dts.sec, dts.us, tz2)
38233824
delta = int(total_seconds(_get_utcoffset(tz2, dt))) * 1000000000
38243825
result[i] = v + delta
3825-
return result
3826+
return result
38263827

38273828
# Convert UTC to other timezone
38283829
trans, deltas, typ = _get_dst_info(tz2)

0 commit comments

Comments
 (0)