Skip to content

BUG: Adding nano offset raises TypeError #9291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/source/whatsnew/v0.16.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ Bug Fixes



- Bug in adding ``offsets.Nano`` to other offets raises ``TypeError`` (:issue:`9284`)





Expand Down
Binary file not shown.
16 changes: 16 additions & 0 deletions pandas/io/tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jreback Older pickles are tested in here. Also, I've added my pickle taken in v0.15.2.

# 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
Expand Down
17 changes: 9 additions & 8 deletions pandas/tseries/offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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'


Expand Down
24 changes: 23 additions & 1 deletion pandas/tseries/tests/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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()
Expand All @@ -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))
Expand Down
2 changes: 2 additions & 0 deletions pandas/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down