Repository: pandas-dev/pandas

Issue:
Timestamp comparisons to Series should work on either side of the comparison operator
```
In [2]: df = DataFrame({'dates': date_range('20010101', periods=10)})

In [3]: Timestamp('20010109') < df.dates
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-713f2b228d0e> in <module>()
----> 1 Timestamp('20010109') < df.dates

/home/phillip/Documents/code/py/pandas/pandas/tslib.so in pandas.tslib._Timestamp.__richcmp__ (pandas/tslib.c:9555)()

TypeError: Cannot compare Timestamp with 'Series'
```

but when a `Series` is on the left hand side, things go swimmingly:

```
In [4]: df.dates < Timestamp('20010109')
Out[4]:
0     True
1     True
2     True
3     True
4     True
5     True
6     True
7     True
8    False
9    False
Name: dates, dtype: bool
```



Discussion:
related to #3428 which was impossible to fix, but this IS fixable

pr coming shortly


Resolving patch:
diff --git a/vb_suite/binary_ops.py b/vb_suite/binary_ops.py
--- a/vb_suite/binary_ops.py
+++ b/vb_suite/binary_ops.py
@@ -102,3 +102,15 @@
 frame_multi_and_no_ne = \
     Benchmark("df[(df>0) & (df2>0)]", setup, name='frame_multi_and_no_ne',cleanup="expr.set_use_numexpr(True)",
               start_date=datetime(2013, 2, 26))
+
+setup = common_setup + """
+N = 1000000
+halfway = N // 2 - 1
+s  = Series(date_range('20010101', periods=N, freq='D'))
+ts = s[halfway]
+"""
+
+timestamp_series_compare = Benchmark("ts >= s", setup,
+                                     start_date=datetime(2013, 9, 27))
+series_timestamp_compare = Benchmark("s <= ts", setup,
+                                     start_date=datetime(2012, 2, 21))
diff --git a/vb_suite/index_object.py b/vb_suite/index_object.py
--- a/vb_suite/index_object.py
+++ b/vb_suite/index_object.py
@@ -22,6 +22,16 @@
 index_datetime_intersection = Benchmark("rng.intersection(rng2)", setup)
 index_datetime_union = Benchmark("rng.union(rng2)", setup)
 
+setup = common_setup + """
+rng = date_range('1/1/2000', periods=10000, freq='T')
+rng2 = rng[:-1]
+"""
+
+datetime_index_intersection = Benchmark("rng.intersection(rng2)", setup,
+                                        start_date=datetime(2013, 9, 27))
+datetime_index_union = Benchmark("rng.union(rng2)", setup,
+                                 start_date=datetime(2013, 9, 27))
+
 # integers
 setup = common_setup + """
 N = 1000000


Test patch:
diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py
--- a/pandas/tests/test_frame.py
+++ b/pandas/tests/test_frame.py
@@ -4335,6 +4335,31 @@ def check(df,df2):
         df2 = DataFrame({'a': date_range('20010101', periods=len(df)), 'b': date_range('20100101', periods=len(df))})
         check(df,df2)
 
+    def test_timestamp_compare(self):
+        # make sure we can compare Timestamps on the right AND left hand side
+        # GH4982
+        df = DataFrame({'dates1': date_range('20010101', periods=10),
+                        'dates2': date_range('20010102', periods=10),
+                        'intcol': np.random.randint(1000000000, size=10),
+                        'floatcol': np.random.randn(10),
+                        'stringcol': list(tm.rands(10))})
+        df.loc[np.random.rand(len(df)) > 0.5, 'dates2'] = pd.NaT
+        ops = {'gt': 'lt', 'lt': 'gt', 'ge': 'le', 'le': 'ge', 'eq': 'eq',
+               'ne': 'ne'}
+        for left, right in ops.items():
+            left_f = getattr(operator, left)
+            right_f = getattr(operator, right)
+
+            # no nats
+            expected = left_f(df, Timestamp('20010109'))
+            result = right_f(Timestamp('20010109'), df)
+            tm.assert_frame_equal(result, expected)
+
+            # nats
+            expected = left_f(df, Timestamp('nat'))
+            result = right_f(Timestamp('nat'), df)
+            tm.assert_frame_equal(result, expected)
+
     def test_modulo(self):
 
         # GH3590, modulo as ints
diff --git a/pandas/tseries/tests/test_timeseries.py b/pandas/tseries/tests/test_timeseries.py
--- a/pandas/tseries/tests/test_timeseries.py
+++ b/pandas/tseries/tests/test_timeseries.py
@@ -3,6 +3,7 @@
 import sys
 import os
 import unittest
+import operator
 
 import nose
 
@@ -2010,6 +2011,7 @@ def test_join_self(self):
             joined = index.join(index, how=kind)
             self.assert_(index is joined)
 
+
 class TestDatetime64(unittest.TestCase):
     """
     Also test supoprt for datetime64[ns] in Series / DataFrame
@@ -2507,6 +2509,74 @@ def test_hash_equivalent(self):
         stamp = Timestamp(datetime(2011, 1, 1))
         self.assertEquals(d[stamp], 5)
 
+    def test_timestamp_compare_scalars(self):
+        # case where ndim == 0
+        lhs = np.datetime64(datetime(2013, 12, 6))
+        rhs = Timestamp('now')
+        nat = Timestamp('nat')
+
+        ops = {'gt': 'lt', 'lt': 'gt', 'ge': 'le', 'le': 'ge', 'eq': 'eq',
+            'ne': 'ne'}
+
+        for left, right in ops.items():
+            left_f = getattr(operator, left)
+            right_f = getattr(operator, right)
+
+            if pd._np_version_under1p7:
+                # you have to convert to timestamp for this to work with numpy
+                # scalars
+                expected = left_f(Timestamp(lhs), rhs)
+
+                # otherwise a TypeError is thrown
+                if left not in ('eq', 'ne'):
+                    with tm.assertRaises(TypeError):
+                        left_f(lhs, rhs)
+            else:
+                expected = left_f(lhs, rhs)
+
+            result = right_f(rhs, lhs)
+            self.assertEqual(result, expected)
+
+            expected = left_f(rhs, nat)
+            result = right_f(nat, rhs)
+            self.assertEqual(result, expected)
+
+    def test_timestamp_compare_series(self):
+        # make sure we can compare Timestamps on the right AND left hand side
+        # GH4982
+        s = Series(date_range('20010101', periods=10), name='dates')
+        s_nat = s.copy(deep=True)
+
+        s[0] = pd.Timestamp('nat')
+        s[3] = pd.Timestamp('nat')
+
+        ops = {'lt': 'gt', 'le': 'ge', 'eq': 'eq', 'ne': 'ne'}
+
+        for left, right in ops.items():
+            left_f = getattr(operator, left)
+            right_f = getattr(operator, right)
+
+            # no nats
+            expected = left_f(s, Timestamp('20010109'))
+            result = right_f(Timestamp('20010109'), s)
+            tm.assert_series_equal(result, expected)
+
+            # nats
+            expected = left_f(s, Timestamp('nat'))
+            result = right_f(Timestamp('nat'), s)
+            tm.assert_series_equal(result, expected)
+
+            # compare to timestamp with series containing nats
+            expected = left_f(s_nat, Timestamp('20010109'))
+            result = right_f(Timestamp('20010109'), s_nat)
+            tm.assert_series_equal(result, expected)
+
+            # compare to nat with series containing nats
+            expected = left_f(s_nat, Timestamp('nat'))
+            result = right_f(Timestamp('nat'), s_nat)
+            tm.assert_series_equal(result, expected)
+
+
 class TestSlicing(unittest.TestCase):
 
     def test_slice_year(self):
@@ -2775,6 +2845,7 @@ def test_frame_apply_dont_convert_datetime64(self):
 
         self.assertTrue(df.x1.dtype == 'M8[ns]')
 
+
 if __name__ == '__main__':
     nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
                    exit=False)