Skip to content

Commit 71cd0d0

Browse files
jbrockmendelproost
authored andcommitted
BUG: fix array_equivalent with mismatched tzawareness (pandas-dev#28508)
1 parent fa8f5a2 commit 71cd0d0

File tree

4 files changed

+50
-13
lines changed

4 files changed

+50
-13
lines changed

pandas/_libs/lib.pyx

+13-5
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ cimport pandas._libs.util as util
5555
from pandas._libs.util cimport is_nan, UINT64_MAX, INT64_MAX, INT64_MIN
5656

5757
from pandas._libs.tslib import array_to_datetime
58-
from pandas._libs.tslibs.nattype cimport NPY_NAT
59-
from pandas._libs.tslibs.nattype import NaT
58+
from pandas._libs.tslibs.nattype cimport NPY_NAT, c_NaT as NaT
6059
from pandas._libs.tslibs.conversion cimport convert_to_tsobject
6160
from pandas._libs.tslibs.timedeltas cimport convert_to_timedelta64
6261
from pandas._libs.tslibs.timezones cimport get_timezone, tz_compare
@@ -525,9 +524,18 @@ def array_equivalent_object(left: object[:], right: object[:]) -> bool:
525524

526525
# we are either not equal or both nan
527526
# I think None == None will be true here
528-
if not (PyObject_RichCompareBool(x, y, Py_EQ) or
529-
(x is None or is_nan(x)) and (y is None or is_nan(y))):
530-
return False
527+
try:
528+
if not (PyObject_RichCompareBool(x, y, Py_EQ) or
529+
(x is None or is_nan(x)) and (y is None or is_nan(y))):
530+
return False
531+
except TypeError as err:
532+
# Avoid raising TypeError on tzawareness mismatch
533+
# TODO: This try/except can be removed if/when Timestamp
534+
# comparisons are change dto match datetime, see GH#28507
535+
if "tz-naive and tz-aware" in str(err):
536+
return False
537+
raise
538+
531539
return True
532540

533541

pandas/core/dtypes/missing.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,14 @@ def array_equivalent(left, right, strict_nan=False):
445445
if not isinstance(right_value, float) or not np.isnan(right_value):
446446
return False
447447
else:
448-
if np.any(left_value != right_value):
449-
return False
448+
try:
449+
if np.any(left_value != right_value):
450+
return False
451+
except TypeError as err:
452+
if "Cannot compare tz-naive" in str(err):
453+
# tzawareness compat failure, see GH#28507
454+
return False
455+
raise
450456
return True
451457

452458
# NaNs can occur in float and complex arrays.

pandas/core/indexes/base.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -4324,12 +4324,9 @@ def equals(self, other):
43244324
# if other is not object, use other's logic for coercion
43254325
return other.equals(self)
43264326

4327-
try:
4328-
return array_equivalent(
4329-
com.values_from_object(self), com.values_from_object(other)
4330-
)
4331-
except Exception:
4332-
return False
4327+
return array_equivalent(
4328+
com.values_from_object(self), com.values_from_object(other)
4329+
)
43334330

43344331
def identical(self, other):
43354332
"""

pandas/tests/dtypes/test_missing.py

+26
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
from pandas import DatetimeIndex, Float64Index, NaT, Series, TimedeltaIndex, date_range
2626
from pandas.util import testing as tm
2727

28+
now = pd.Timestamp.now()
29+
utcnow = pd.Timestamp.now("UTC")
30+
2831

2932
@pytest.mark.parametrize("notna_f", [notna, notnull])
3033
def test_notna_notnull(notna_f):
@@ -332,6 +335,29 @@ def test_array_equivalent():
332335
assert not array_equivalent(DatetimeIndex([0, np.nan]), TimedeltaIndex([0, np.nan]))
333336

334337

338+
@pytest.mark.parametrize(
339+
"lvalue, rvalue",
340+
[
341+
# There are 3 variants for each of lvalue and rvalue. We include all
342+
# three for the tz-naive `now` and exclude the datetim64 variant
343+
# for utcnow because it drops tzinfo.
344+
(now, utcnow),
345+
(now.to_datetime64(), utcnow),
346+
(now.to_pydatetime(), utcnow),
347+
(now, utcnow),
348+
(now.to_datetime64(), utcnow.to_pydatetime()),
349+
(now.to_pydatetime(), utcnow.to_pydatetime()),
350+
],
351+
)
352+
def test_array_equivalent_tzawareness(lvalue, rvalue):
353+
# we shouldn't raise if comparing tzaware and tznaive datetimes
354+
left = np.array([lvalue], dtype=object)
355+
right = np.array([rvalue], dtype=object)
356+
357+
assert not array_equivalent(left, right, strict_nan=True)
358+
assert not array_equivalent(left, right, strict_nan=False)
359+
360+
335361
def test_array_equivalent_compat():
336362
# see gh-13388
337363
m = np.array([(1, 2), (3, 4)], dtype=[("a", int), ("b", float)])

0 commit comments

Comments
 (0)