From 9fc201d79d81eeb038144c868fda20c9dde08759 Mon Sep 17 00:00:00 2001 From: nrebena <49879400+nrebena@users.noreply.github.com> Date: Mon, 13 Apr 2020 19:16:25 +0200 Subject: [PATCH] BUG: Do not use string Index like Datetimelike Index --- pandas/core/indexes/datetimelike.py | 46 +++++++++++++++++---- pandas/tests/indexes/datetimes/test_misc.py | 17 ++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index ca6eb45e22c69..a8ff836dbf983 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -138,13 +138,16 @@ def equals(self, other) -> bool: if not isinstance(other, ABCIndexClass): return False elif not isinstance(other, type(self)): - try: - other = type(self)(other) - except (ValueError, TypeError, OverflowError): - # e.g. - # ValueError -> cannot parse str entry, or OutOfBoundsDatetime - # TypeError -> trying to convert IntervalIndex to DatetimeIndex - # OverflowError -> Index([very_large_timedeltas]) + if self._is_convertible_to_index_for_join(other): + try: + other = type(self)(other) + except (ValueError, TypeError, OverflowError): + # e.g. + # ValueError -> cannot parse str entry, or OutOfBoundsDatetime + # TypeError -> trying to convert IntervalIndex to DatetimeIndex + # OverflowError -> Index([very_large_timedeltas]) + return False + else: return False if not is_dtype_equal(self.dtype, other.dtype): @@ -596,6 +599,26 @@ def _convert_arr_indexer(self, keyarr): converted_arr = com.asarray_tuplesafe(keyarr) return converted_arr + @classmethod + def _is_convertible_to_index_for_join(cls, other: Index) -> bool: + """ + return a boolean whether I can attempt conversion to a + DatetimeIndex/TimedeltaIndex + """ + if isinstance(other, cls): + return False + elif len(other) > 0 and other.inferred_type not in ( + "floating", + "mixed-integer", + "integer", + "integer-na", + "mixed-integer-float", + "mixed", + "string", + ): + return True + return False + class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin, Int64Index): """ @@ -903,6 +926,15 @@ def _is_convertible_to_index_for_join(cls, other: Index) -> bool: return True return False + def _wrap_joined_index(self, joined: np.ndarray, other): + assert other.dtype == self.dtype, (other.dtype, self.dtype) + name = get_op_result_name(self, other) + + freq = self.freq if self._can_fast_union(other) else None + new_data = type(self._data)._simple_new(joined, dtype=self.dtype, freq=freq) + + return type(self)._simple_new(new_data, name=name) + # -------------------------------------------------------------------- # List-Like Methods diff --git a/pandas/tests/indexes/datetimes/test_misc.py b/pandas/tests/indexes/datetimes/test_misc.py index 51841727d510b..04d85663d75fb 100644 --- a/pandas/tests/indexes/datetimes/test_misc.py +++ b/pandas/tests/indexes/datetimes/test_misc.py @@ -408,3 +408,20 @@ def test_isocalendar_returns_correct_values_close_to_new_year_with_tz(): dtype="UInt32", ) tm.assert_frame_equal(result, expected_data_frame) + + +def test_datetimelike_string(): + # Related to PR 32739 + # Ensure we do not compare strings and datetimelike type. + date_string = "2020-04-13" + i1 = pd.Index([date_string]) + i2 = pd.Index([pd.to_datetime(date_string)]) + + assert i1.equals(i2) is False + assert i2.equals(i1) is False + + assert len(i1.intersection(i2)) == 0 + assert len(i2.intersection(i1)) == 0 + + assert len(i1.union(i2)) == 2 + assert len(i2.union(i1)) == 2