Repository: pandas-dev/pandas

Issue:
Adding tseries.offsets.Nano to other offsets throws error
xref #9226 

<pre>
In [11]: from pandas.tseries import offsets

In [12]: t1 = offsets.Nano(100)

In [13]: t2 = offsets.Micro(1)

In [14]: t3 = t1 + t2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-4ee6d99529e1> in <module>()
----> 1 t3 = t1 + t2

/Users/tvyomkesh/pandas/pandas/tseries/offsets.pyc in __add__(self, other)
   2025                 return type(self)(self.n + other.n)
   2026             else:
-> 2027                 return _delta_to_tick(self.delta + other.delta)
   2028         try:
   2029             return self.apply(other)

TypeError: ufunc add cannot use operands with types dtype('&lt;m8[ns]') and dtype('O')
</pre>



Discussion:

Resolving patch:
diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py
--- 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/setup.py b/setup.py
--- 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',


Test patch:
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
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
--- 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/tests/test_offsets.py b/pandas/tseries/tests/test_offsets.py
--- 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))