diff --git a/doc/source/release.rst b/doc/source/release.rst index 5db612059685b..f161ead7f7ecc 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -633,6 +633,7 @@ Bug Fixes - Fixed issue with ``drop`` and a non-unique index on Series (:issue:`5248`) - Fixed seg fault in C parser caused by passing more names than columns in the file. (:issue:`5156`) + - Fix ``Series.isin`` with date/time-like dtypes (:issue:`5021`) pandas 0.12.0 ------------- diff --git a/pandas/core/series.py b/pandas/core/series.py index 11033893b0b93..4a288f4c283b2 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -2077,8 +2077,20 @@ def isin(self, values): raise TypeError("only list-like objects are allowed to be passed" " to Series.isin(), you passed a " "{0!r}".format(type(values).__name__)) + + # may need i8 conversion for proper membership testing + comps = _values_from_object(self) + if com.is_datetime64_dtype(self): + from pandas.tseries.tools import to_datetime + values = Series(to_datetime(values)).values.view('i8') + comps = comps.view('i8') + elif com.is_timedelta64_dtype(self): + from pandas.tseries.timedeltas import to_timedelta + values = Series(to_timedelta(values)).values.view('i8') + comps = comps.view('i8') + value_set = set(values) - result = lib.ismember(_values_from_object(self), value_set) + result = lib.ismember(comps, value_set) return self._constructor(result, index=self.index).__finalize__(self) def between(self, left, right, inclusive=True): diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 6988c81b181de..9b7d1008329c5 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -4840,7 +4840,7 @@ def test_isin(self): assert_series_equal(result, expected) def test_isin_with_string_scalar(self): - #GH4763 + # GH4763 s = Series(['A', 'B', 'C', 'a', 'B', 'B', 'A', 'C']) with tm.assertRaises(TypeError): s.isin('a') @@ -4849,6 +4849,38 @@ def test_isin_with_string_scalar(self): s = Series(['aaa', 'b', 'c']) s.isin('aaa') + def test_isin_with_i8(self): + # GH 5021 + + expected = Series([True,True,False,False,False]) + expected2 = Series([False,True,False,False,False]) + + # datetime64[ns] + s = Series(date_range('jan-01-2013','jan-05-2013')) + + result = s.isin(s[0:2]) + assert_series_equal(result, expected) + + result = s.isin(s[0:2].values) + assert_series_equal(result, expected) + + # fails on dtype conversion in the first place + if not _np_version_under1p7: + result = s.isin(s[0:2].values.astype('datetime64[D]')) + assert_series_equal(result, expected) + + result = s.isin([s[1]]) + assert_series_equal(result, expected2) + + result = s.isin([np.datetime64(s[1])]) + assert_series_equal(result, expected2) + + # timedelta64[ns] + if not _np_version_under1p7: + s = Series(pd.to_timedelta(lrange(5),unit='d')) + result = s.isin(s[0:2]) + assert_series_equal(result, expected) + #------------------------------------------------------------------------------ # TimeSeries-specific def test_cummethods_bool(self):