Repository: pandas-dev/pandas
Pull request #56658 (2023-12-28 17:33:33)

Backport PR #56613 on branch 2.2.x (BUG: Added raising when merging datetime columns with timedelta columns)
Backport PR #56613: BUG: Added raising when merging datetime columns with timedelta columns


Patch:
diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst
index 34c9c142d3..d60dbefd83 100644
--- a/doc/source/whatsnew/v2.2.0.rst
+++ b/doc/source/whatsnew/v2.2.0.rst
@@ -824,6 +824,7 @@ Reshaping
 - Bug in :func:`merge_asof` raising ``TypeError`` when ``by`` dtype is not ``object``, ``int64``, or ``uint64`` (:issue:`22794`)
 - Bug in :func:`merge_asof` raising incorrect error for string dtype (:issue:`56444`)
 - Bug in :func:`merge_asof` when using a :class:`Timedelta` tolerance on a :class:`ArrowDtype` column (:issue:`56486`)
+- Bug in :func:`merge` not raising when merging datetime columns with timedelta columns (:issue:`56455`)
 - Bug in :func:`merge` not raising when merging string columns with numeric columns (:issue:`56441`)
 - Bug in :func:`merge` returning columns in incorrect order when left and/or right is empty (:issue:`51929`)
 - Bug in :meth:`DataFrame.melt` where an exception was raised if ``var_name`` was not a string (:issue:`55948`)
diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py
index 690e3c2700..320e4e33a2 100644
--- a/pandas/core/reshape/merge.py
+++ b/pandas/core/reshape/merge.py
@@ -1526,6 +1526,11 @@ class _MergeOperation:
             ) or (lk.dtype.kind == "M" and rk.dtype.kind == "M"):
                 # allows datetime with different resolutions
                 continue
+            # datetime and timedelta not allowed
+            elif lk.dtype.kind == "M" and rk.dtype.kind == "m":
+                raise ValueError(msg)
+            elif lk.dtype.kind == "m" and rk.dtype.kind == "M":
+                raise ValueError(msg)
 
             elif is_object_dtype(lk.dtype) and is_object_dtype(rk.dtype):
                 continue


Test patch:
diff --git a/pandas/tests/reshape/merge/test_merge.py b/pandas/tests/reshape/merge/test_merge.py
index d7a343ae9f..ab8d22e567 100644
--- a/pandas/tests/reshape/merge/test_merge.py
+++ b/pandas/tests/reshape/merge/test_merge.py
@@ -2988,3 +2988,23 @@ def test_merge_empty_frames_column_order(left_empty, right_empty):
     elif right_empty:
         expected.loc[:, ["C", "D"]] = np.nan
     tm.assert_frame_equal(result, expected)
+
+
+@pytest.mark.parametrize("how", ["left", "right", "inner", "outer"])
+def test_merge_datetime_and_timedelta(how):
+    left = DataFrame({"key": Series([1, None], dtype="datetime64[ns]")})
+    right = DataFrame({"key": Series([1], dtype="timedelta64[ns]")})
+
+    msg = (
+        f"You are trying to merge on {left['key'].dtype} and {right['key'].dtype} "
+        "columns for key 'key'. If you wish to proceed you should use pd.concat"
+    )
+    with pytest.raises(ValueError, match=re.escape(msg)):
+        left.merge(right, on="key", how=how)
+
+    msg = (
+        f"You are trying to merge on {right['key'].dtype} and {left['key'].dtype} "
+        "columns for key 'key'. If you wish to proceed you should use pd.concat"
+    )
+    with pytest.raises(ValueError, match=re.escape(msg)):
+        right.merge(left, on="key", how=how)