diff --git a/doc/source/whatsnew/v0.16.0.txt b/doc/source/whatsnew/v0.16.0.txt index b3ac58a9fb84a..16882c572f48e 100644 --- a/doc/source/whatsnew/v0.16.0.txt +++ b/doc/source/whatsnew/v0.16.0.txt @@ -152,6 +152,9 @@ Bug Fixes +- Bug in adding ``offsets.Nano`` to other offets raises ``TypeError`` (:issue:`9284`) + + diff --git a/pandas/io/tests/data/legacy_pickle/0.15.2/0.15.2_x86_64_darwin_2.7.9.pickle b/pandas/io/tests/data/legacy_pickle/0.15.2/0.15.2_x86_64_darwin_2.7.9.pickle new file mode 100644 index 0000000000000..1a01539700cf1 Binary files /dev/null and b/pandas/io/tests/data/legacy_pickle/0.15.2/0.15.2_x86_64_darwin_2.7.9.pickle differ diff --git a/pandas/io/tests/test_pickle.py b/pandas/io/tests/test_pickle.py index aea7fb42b7d36..3073673575702 100644 --- a/pandas/io/tests/test_pickle.py +++ b/pandas/io/tests/test_pickle.py @@ -75,6 +75,7 @@ def read_pickles(self, version): if 'series' in data: if 'ts' in data['series']: self._validate_timeseries(data['series']['ts'], self.data['series']['ts']) + self._validate_frequency(data['series']['ts']) def test_read_pickles_0_10_1(self): self.read_pickles('0.10.1') @@ -148,6 +149,21 @@ def _validate_timeseries(self, pickled, current): self.assertEqual(pickled.index.freq.normalize, False) self.assert_numpy_array_equal(pickled > 0, current > 0) + def _validate_frequency(self, pickled): + # GH 9291 + from pandas.tseries.offsets import Day + freq = pickled.index.freq + result = freq + Day(1) + self.assertTrue(result, Day(2)) + + result = freq + pandas.Timedelta(hours=1) + self.assertTrue(isinstance(result, pandas.Timedelta)) + self.assertEqual(result, pandas.Timedelta(days=1, hours=1)) + + result = freq + pandas.Timedelta(nanoseconds=1) + self.assertTrue(isinstance(result, pandas.Timedelta)) + self.assertEqual(result, pandas.Timedelta(days=1, nanoseconds=1)) + if __name__ == '__main__': import nose diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index 81daa2b451c6b..84449cd2fad98 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -9,7 +9,7 @@ from dateutil.relativedelta import relativedelta, weekday from dateutil.easter import easter import pandas.tslib as tslib -from pandas.tslib import Timestamp, OutOfBoundsDatetime +from pandas.tslib import Timestamp, OutOfBoundsDatetime, Timedelta import functools @@ -2010,7 +2010,7 @@ def f(self, other): class Tick(SingleConstructorOffset): - _inc = timedelta(microseconds=1000) + _inc = Timedelta(microseconds=1000) __gt__ = _tick_comp(operator.gt) __ge__ = _tick_comp(operator.ge) @@ -2107,36 +2107,37 @@ def _delta_to_tick(delta): class Day(Tick): - _inc = timedelta(1) + _inc = Timedelta(days=1) _prefix = 'D' class Hour(Tick): - _inc = timedelta(0, 3600) + _inc = Timedelta(hours=1) _prefix = 'H' class Minute(Tick): - _inc = timedelta(0, 60) + _inc = Timedelta(minutes=1) _prefix = 'T' class Second(Tick): - _inc = timedelta(0, 1) + _inc = Timedelta(seconds=1) _prefix = 'S' class Milli(Tick): + _inc = Timedelta(milliseconds=1) _prefix = 'L' class Micro(Tick): - _inc = timedelta(microseconds=1) + _inc = Timedelta(microseconds=1) _prefix = 'U' class Nano(Tick): - _inc = np.timedelta64(1, 'ns') + _inc = Timedelta(nanoseconds=1) _prefix = 'N' diff --git a/pandas/tseries/tests/test_offsets.py b/pandas/tseries/tests/test_offsets.py index ef4288b28e9e4..6f9e8b6819bd3 100644 --- a/pandas/tseries/tests/test_offsets.py +++ b/pandas/tseries/tests/test_offsets.py @@ -25,7 +25,7 @@ import pandas.tseries.offsets as offsets from pandas.io.pickle import read_pickle -from pandas.tslib import NaT, Timestamp +from pandas.tslib import NaT, Timestamp, Timedelta import pandas.tslib as tslib from pandas.util.testing import assertRaisesRegexp import pandas.util.testing as tm @@ -2817,6 +2817,7 @@ def test_Easter(): assertEq(-Easter(), datetime(2010, 4, 4), datetime(2009, 4, 12)) assertEq(-Easter(2), datetime(2010, 4, 4), datetime(2008, 3, 23)) + def test_Hour(): assertEq(Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 1)) assertEq(Hour(-1), datetime(2010, 1, 1, 1), datetime(2010, 1, 1)) @@ -2904,6 +2905,10 @@ def test_Nanosecond(): assert (Nano(3) + Nano(2)) == Nano(5) assert (Nano(3) - Nano(2)) == Nano() + # GH9284 + assert Nano(1) + Nano(10) == Nano(11) + assert Nano(5) + Micro(1) == Nano(1005) + assert Micro(5) + Nano(1) == Nano(5001) def test_tick_offset(): assert not Day().isAnchored() @@ -2928,6 +2933,23 @@ def test_compare_ticks(): assert(kls(3) != kls(4)) +class TestTicks(tm.TestCase): + + def test_ticks(self): + offsets = [(Hour, Timedelta(hours=5)), + (Minute, Timedelta(hours=2, minutes=3)), + (Second, Timedelta(hours=2, seconds=3)), + (Milli, Timedelta(hours=2, milliseconds=3)), + (Micro, Timedelta(hours=2, microseconds=3)), + (Nano, Timedelta(hours=2, nanoseconds=3))] + + for kls, expected in offsets: + offset = kls(3) + result = offset + Timedelta(hours=2) + self.assertTrue(isinstance(result, Timedelta)) + self.assertEqual(result, expected) + + class TestOffsetNames(tm.TestCase): def test_get_offset_name(self): assertRaisesRegexp(ValueError, 'Bad rule.*BusinessDays', get_offset_name, BDay(2)) diff --git a/pandas/tslib.pyx b/pandas/tslib.pyx index 8217c4b31b287..c7c35564c1e5a 100644 --- a/pandas/tslib.pyx +++ b/pandas/tslib.pyx @@ -997,6 +997,8 @@ cdef class _NaT(_Timestamp): def _delta_to_nanoseconds(delta): + if hasattr(delta, 'nanos'): + return delta.nanos if hasattr(delta, 'delta'): delta = delta.delta if is_timedelta64_object(delta): diff --git a/setup.py b/setup.py index f58b9b0bb8551..e64235affaae2 100755 --- a/setup.py +++ b/setup.py @@ -590,6 +590,9 @@ def pxd(name): 'tests/data/legacy_pickle/0.12.0/*.pickle', 'tests/data/legacy_pickle/0.13.0/*.pickle', 'tests/data/legacy_pickle/0.14.0/*.pickle', + 'tests/data/legacy_pickle/0.14.1/*.pickle', + 'tests/data/legacy_pickle/0.15.0/*.pickle', + 'tests/data/legacy_pickle/0.15.2/*.pickle', 'tests/data/*.csv', 'tests/data/*.dta', 'tests/data/*.txt',