diff --git a/python/cudf/cudf/core/column/datetime.py b/python/cudf/cudf/core/column/datetime.py index 8073092775d..da6c4fb858c 100644 --- a/python/cudf/cudf/core/column/datetime.py +++ b/python/cudf/cudf/core/column/datetime.py @@ -460,14 +460,22 @@ def _binaryop(self, other: ColumnBinaryOperand, op: str) -> ColumnBase: if isinstance(other, ColumnBase) and not isinstance( other, DatetimeColumn ): - return _all_bools_with_nulls( + result = _all_bools_with_nulls( self, other, bool_fill_value=op == "__ne__" ) + if cudf.get_option("mode.pandas_compatible"): + result = result.fillna(op == "__ne__") + return result if out_dtype is None: return NotImplemented - return libcudf.binaryop.binaryop(lhs, rhs, op, out_dtype) + result = libcudf.binaryop.binaryop(lhs, rhs, op, out_dtype) + if cudf.get_option( + "mode.pandas_compatible" + ) and out_dtype == cudf.dtype(np.bool_): + result = result.fillna(op == "__ne__") + return result def fillna( self, diff --git a/python/cudf/cudf/core/column/timedelta.py b/python/cudf/cudf/core/column/timedelta.py index b571461b307..e254761e9ec 100644 --- a/python/cudf/cudf/core/column/timedelta.py +++ b/python/cudf/cudf/core/column/timedelta.py @@ -181,7 +181,7 @@ def _binaryop(self, other: ColumnBinaryOperand, op: str) -> ColumnBase: "__ge__", "NULL_EQUALS", }: - out_dtype = np.bool_ + out_dtype = cudf.dtype(np.bool_) elif op == "__mod__": out_dtype = determine_out_dtype(self.dtype, other.dtype) elif op in {"__truediv__", "__floordiv__"}: @@ -206,16 +206,24 @@ def _binaryop(self, other: ColumnBinaryOperand, op: str) -> ColumnBase: if isinstance(other, ColumnBase) and not isinstance( other, TimeDeltaColumn ): - return _all_bools_with_nulls( + result = _all_bools_with_nulls( self, other, bool_fill_value=op == "__ne__" ) + if cudf.get_option("mode.pandas_compatible"): + result = result.fillna(op == "__ne__") + return result if out_dtype is None: return NotImplemented lhs, rhs = (other, this) if reflect else (this, other) - return libcudf.binaryop.binaryop(lhs, rhs, op, out_dtype) + result = libcudf.binaryop.binaryop(lhs, rhs, op, out_dtype) + if cudf.get_option( + "mode.pandas_compatible" + ) and out_dtype == cudf.dtype(np.bool_): + result = result.fillna(op == "__ne__") + return result def normalize_binop_value(self, other) -> ColumnBinaryOperand: if isinstance(other, (ColumnBase, cudf.Scalar)): diff --git a/python/cudf/cudf/tests/test_datetime.py b/python/cudf/cudf/tests/test_datetime.py index a59f8b62e7e..4c4657ccba1 100644 --- a/python/cudf/cudf/tests/test_datetime.py +++ b/python/cudf/cudf/tests/test_datetime.py @@ -2109,6 +2109,27 @@ def test_datetime_binop_tz_timestamp(op): op(s, date_scalar) +@pytest.mark.parametrize( + "data1", [["20110101", "20120101", None, "20140101", None]] +) +@pytest.mark.parametrize( + "data2", [["20110101", "20120101", "20130101", None, None]] +) +@pytest.mark.parametrize("op", _cmpops) +def test_datetime_series_cmpops_pandas_compatibility(data1, data2, op): + gsr1 = cudf.Series(data=data1, dtype="datetime64[ns]") + psr1 = gsr1.to_pandas() + + gsr2 = cudf.Series(data=data2, dtype="datetime64[ns]") + psr2 = gsr2.to_pandas() + + expect = op(psr1, psr2) + with cudf.option_context("mode.pandas_compatible", True): + got = op(gsr1, gsr2) + + assert_eq(expect, got) + + def test_datetime_getitem_na(): s = cudf.Series([1, 2, None, 3], dtype="datetime64[ns]") assert s[2] is cudf.NaT diff --git a/python/cudf/cudf/tests/test_timedelta.py b/python/cudf/cudf/tests/test_timedelta.py index 681b42fd3bd..ef39a4fef5a 100644 --- a/python/cudf/cudf/tests/test_timedelta.py +++ b/python/cudf/cudf/tests/test_timedelta.py @@ -57,6 +57,15 @@ [12, 11, 2.32, 2234.32411, 2343.241, 23432.4, 23234], ] +_cmpops = [ + operator.lt, + operator.gt, + operator.le, + operator.ge, + operator.eq, + operator.ne, +] + @pytest.mark.parametrize( "data", @@ -1442,3 +1451,20 @@ def test_timdelta_binop_tz_timestamp(op): def test_timedelta_getitem_na(): s = cudf.Series([1, 2, None, 3], dtype="timedelta64[ns]") assert s[2] is cudf.NaT + + +@pytest.mark.parametrize("data1", [[123, 456, None, 321, None]]) +@pytest.mark.parametrize("data2", [[123, 456, 789, None, None]]) +@pytest.mark.parametrize("op", _cmpops) +def test_timedelta_series_cmpops_pandas_compatibility(data1, data2, op): + gsr1 = cudf.Series(data=data1, dtype="timedelta64[ns]") + psr1 = gsr1.to_pandas() + + gsr2 = cudf.Series(data=data2, dtype="timedelta64[ns]") + psr2 = gsr2.to_pandas() + + expect = op(psr1, psr2) + with cudf.option_context("mode.pandas_compatible", True): + got = op(gsr1, gsr2) + + assert_eq(expect, got)