diff --git a/doc/source/whatsnew/v0.16.2.txt b/doc/source/whatsnew/v0.16.2.txt index 49f143e158abf..91acd3d670e9f 100644 --- a/doc/source/whatsnew/v0.16.2.txt +++ b/doc/source/whatsnew/v0.16.2.txt @@ -80,7 +80,7 @@ Bug Fixes - Bug in ``Series.align`` resets ``name`` when ``fill_value`` is specified (:issue:`10067`) - Bug in ``SparseSeries.abs`` resets ``name`` (:issue:`10241`) - +- Bug in ``TimedeltaIndex`` slicing may reset freq (:issue:`10292`) - Bug in GroupBy.get_group raises ValueError when group key contains NaT (:issue:`6992`) - Bug in ``SparseSeries`` constructor ignores input data name (:issue:`10258`) diff --git a/pandas/tseries/base.py b/pandas/tseries/base.py index 88b4117d4807c..71ff0f6c9c56c 100644 --- a/pandas/tseries/base.py +++ b/pandas/tseries/base.py @@ -69,6 +69,35 @@ def __contains__(self, key): except (KeyError, TypeError, ValueError): return False + def __getitem__(self, key): + getitem = self._data.__getitem__ + if np.isscalar(key): + val = getitem(key) + return self._box_func(val) + else: + if com.is_bool_indexer(key): + key = np.asarray(key) + if key.all(): + key = slice(0, None, None) + else: + key = lib.maybe_booleans_to_slice(key.view(np.uint8)) + + attribs = self._get_attributes_dict() + + freq = None + if isinstance(key, slice): + if self.freq is not None and key.step is not None: + freq = key.step * self.freq + else: + freq = self.freq + attribs['freq'] = freq + + result = getitem(key) + if result.ndim > 1: + return result + + return self._simple_new(result, **attribs) + @property def freqstr(self): """ return the frequency object as a string if its set, otherwise None """ diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py index 745c536914e47..35400b3588d3b 100644 --- a/pandas/tseries/index.py +++ b/pandas/tseries/index.py @@ -1349,32 +1349,6 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None): else: raise - def __getitem__(self, key): - getitem = self._data.__getitem__ - if np.isscalar(key): - val = getitem(key) - return Timestamp(val, offset=self.offset, tz=self.tz) - else: - if com.is_bool_indexer(key): - key = np.asarray(key) - if key.all(): - key = slice(0,None,None) - else: - key = lib.maybe_booleans_to_slice(key.view(np.uint8)) - - new_offset = None - if isinstance(key, slice): - if self.offset is not None and key.step is not None: - new_offset = key.step * self.offset - else: - new_offset = self.offset - - result = getitem(key) - if result.ndim > 1: - return result - - return self._simple_new(result, self.name, new_offset, self.tz) - # alias to offset def _get_freq(self): return self.offset diff --git a/pandas/tseries/tdi.py b/pandas/tseries/tdi.py index de68dd763d68c..f1871e78e21a1 100644 --- a/pandas/tseries/tdi.py +++ b/pandas/tseries/tdi.py @@ -244,7 +244,7 @@ def _generate(cls, start, end, periods, name, offset, closed=None): @property def _box_func(self): - return lambda x: Timedelta(x,unit='ns') + return lambda x: Timedelta(x, unit='ns') @classmethod def _simple_new(cls, values, name=None, freq=None, **kwargs): @@ -747,25 +747,6 @@ def _partial_td_slice(self, key, freq, use_lhs=True, use_rhs=True): # try to find a the dates return (lhs_mask & rhs_mask).nonzero()[0] - def __getitem__(self, key): - getitem = self._data.__getitem__ - if np.isscalar(key): - val = getitem(key) - return Timedelta(val) - else: - if com.is_bool_indexer(key): - key = np.asarray(key) - if key.all(): - key = slice(0,None,None) - else: - key = lib.maybe_booleans_to_slice(key.view(np.uint8)) - - result = getitem(key) - if result.ndim > 1: - return result - - return self._simple_new(result, self.name) - def searchsorted(self, key, side='left'): if isinstance(key, (np.ndarray, Index)): key = np.array(key, dtype=_TD_DTYPE, copy=False) diff --git a/pandas/tseries/tests/test_base.py b/pandas/tseries/tests/test_base.py index 55482401a20f4..fc432d5236f62 100644 --- a/pandas/tseries/tests/test_base.py +++ b/pandas/tseries/tests/test_base.py @@ -297,6 +297,38 @@ def test_nonunique_contains(self): ['2015', '2015', '2016'], ['2015', '2015', '2014'])): tm.assertIn(idx[0], idx) + def test_getitem(self): + idx1 = pd.date_range('2011-01-01', '2011-01-31', freq='D', name='idx') + idx2 = pd.date_range('2011-01-01', '2011-01-31', freq='D', tz='Asia/Tokyo', name='idx') + + for idx in [idx1, idx2]: + result = idx[0] + self.assertEqual(result, pd.Timestamp('2011-01-01', tz=idx.tz)) + + result = idx[0:5] + expected = pd.date_range('2011-01-01', '2011-01-05', freq='D', + tz=idx.tz, name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) + + result = idx[0:10:2] + expected = pd.date_range('2011-01-01', '2011-01-09', freq='2D', + tz=idx.tz, name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) + + result = idx[-20:-5:3] + expected = pd.date_range('2011-01-12', '2011-01-25', freq='3D', + tz=idx.tz, name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) + + result = idx[4::-1] + expected = DatetimeIndex(['2011-01-05', '2011-01-04', '2011-01-03', + '2011-01-02', '2011-01-01'], + freq='-1D', tz=idx.tz, name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) class TestTimedeltaIndexOps(Ops): @@ -742,6 +774,33 @@ def test_unknown_attribute(self): self.assertNotIn('foo',ts.__dict__.keys()) self.assertRaises(AttributeError,lambda : ts.foo) + def test_getitem(self): + idx1 = pd.timedelta_range('1 day', '31 day', freq='D', name='idx') + + for idx in [idx1]: + result = idx[0] + self.assertEqual(result, pd.Timedelta('1 day')) + + result = idx[0:5] + expected = pd.timedelta_range('1 day', '5 day', freq='D', name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) + + result = idx[0:10:2] + expected = pd.timedelta_range('1 day', '9 day', freq='2D', name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) + + result = idx[-20:-5:3] + expected = pd.timedelta_range('12 day', '25 day', freq='3D', name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) + + result = idx[4::-1] + expected = TimedeltaIndex(['5 day', '4 day', '3 day', '2 day', '1 day'], + freq='-1D', name='idx') + self.assert_index_equal(result, expected) + self.assertEqual(result.freq, expected.freq) class TestPeriodIndexOps(Ops):