Repository: pandas-dev/pandas (python)

Issue:
BUG: cov buggy when having NaT in column
### Pandas version checks

- [X] I have checked that this issue has not already been reported.

- [X] I have confirmed this bug exists on the [latest version](https://pandas.pydata.org/docs/whatsnew/index.html) of pandas.

- [X] I have confirmed this bug exists on the [main branch](https://pandas.pydata.org/docs/dev/getting_started/install.html#installing-the-development-version-of-pandas) of pandas.


### Reproducible Example

```python
df = DataFrame({
    "a": [1, 2, 3],
    # "b": [pd.Timestamp("1970-01-01 00:00:00.000000001"), pd.Timestamp("1970-01-01 00:00:00.000000002"), pd.NaT],
    "b": [1, 2, np.nan],
    "c": [1, 2, 3],
})
df.cov()
```


### Issue Description

If I understand this correctly, both calculations should be equivalent. The np.nan case returns

```
     a    b    c
a  1.0  0.5  1.0
b  0.5  0.5  0.5
c  1.0  0.5  1.0
```

while the NaT case returns 

```
              a             b             c
a  1.000000e+00 -4.611686e+18  1.000000e+00
b -4.611686e+18  2.835686e+37 -4.611686e+18
c  1.000000e+00 -4.611686e+18  1.000000e+00
```

Both are equivalent without any missing values

### Expected Behavior

Same result for both


### Installed Versions

<details>

main
</details>


Pull request description:
Bug cov nat
- closes #53115 


Patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
index dc3fecba7f..b2c1e38f61 100644
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -11434,6 +11434,12 @@ class DataFrame(NDFrame, OpsMixin):
         c -0.150812  0.191417  0.895202
         """
         data = self._get_numeric_data() if numeric_only else self
+        if any(blk.dtype.kind in "mM" for blk in self._mgr.blocks):
+            msg = (
+                "DataFrame contains columns with dtype datetime64 "
+                "or timedelta64, which are not supported for cov."
+            )
+            raise TypeError(msg)
         cols = data.columns
         idx = cols.copy()
         mat = data.to_numpy(dtype=float, na_value=np.nan, copy=False)
diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py
index e238bb78bb..cb290fde70 100644
--- a/pandas/core/internals/managers.py
+++ b/pandas/core/internals/managers.py
@@ -1800,6 +1800,8 @@ class BlockManager(libinternals.BlockManager, BaseBlockManager):
                 arr = np.asarray(blk.values, dtype=dtype)
             else:
                 arr = np.array(blk.values, dtype=dtype, copy=copy)
+            if passed_nan and blk.dtype.kind in "mM":
+                arr[isna(blk.values)] = na_value
 
             if not copy:
                 arr = arr.view()
@@ -1865,6 +1867,8 @@ class BlockManager(libinternals.BlockManager, BaseBlockManager):
             else:
                 arr = blk.get_values(dtype)
             result[rl.indexer] = arr
+            if na_value is not lib.no_default and blk.dtype.kind in "mM":
+                result[rl.indexer][isna(arr)] = na_value
             itemmask[rl.indexer] = 1
 
         if not itemmask.all():


Test patch:
diff --git a/pandas/tests/frame/methods/test_to_numpy.py b/pandas/tests/frame/methods/test_to_numpy.py
index 36088cceb1..f68d7f5336 100644
--- a/pandas/tests/frame/methods/test_to_numpy.py
+++ b/pandas/tests/frame/methods/test_to_numpy.py
@@ -3,7 +3,9 @@ import pytest
 
 from pandas import (
     DataFrame,
+    NaT,
     Timestamp,
+    date_range,
 )
 import pandas._testing as tm
 
@@ -41,3 +43,37 @@ class TestToNumpy:
         result = df.to_numpy(dtype=str)
         expected = np.array([["2020-01-01 00:00:00", "100.0"]], dtype=str)
         tm.assert_numpy_array_equal(result, expected)
+
+    def test_to_numpy_datetime_with_na(self):
+        # GH #53115
+        dti = date_range("2016-01-01", periods=3)
+        df = DataFrame(dti)
+        df.iloc[0, 0] = NaT
+        expected = np.array([[np.nan], [1.45169280e18], [1.45177920e18]])
+        result = df.to_numpy(float, na_value=np.nan)
+        tm.assert_numpy_array_equal(result, expected)
+
+        df = DataFrame(
+            {
+                "a": [Timestamp("1970-01-01"), Timestamp("1970-01-02"), NaT],
+                "b": [
+                    Timestamp("1970-01-01"),
+                    np.nan,
+                    Timestamp("1970-01-02"),
+                ],
+                "c": [
+                    1,
+                    np.nan,
+                    2,
+                ],
+            }
+        )
+        expected = np.array(
+            [
+                [0.00e00, 0.00e00, 1.00e00],
+                [8.64e04, np.nan, np.nan],
+                [np.nan, 8.64e04, 2.00e00],
+            ]
+        )
+        result = df.to_numpy(float, na_value=np.nan)
+        tm.assert_numpy_array_equal(result, expected)
diff --git a/pandas/tests/frame/test_reductions.py b/pandas/tests/frame/test_reductions.py
index 127f0fc50a..cc23c292b6 100644
--- a/pandas/tests/frame/test_reductions.py
+++ b/pandas/tests/frame/test_reductions.py
@@ -1917,6 +1917,39 @@ class TestEmptyDataFrameReductions:
         expected = Series([pd.NA, pd.NA], dtype=exp_dtype, index=Index([0, 1]))
         tm.assert_series_equal(result, expected)
 
+    @pytest.mark.parametrize(
+        "data",
+        [
+            {"a": [0, 1, 2], "b": [pd.NaT, pd.NaT, pd.NaT]},
+            {"a": [0, 1, 2], "b": [Timestamp("1990-01-01"), pd.NaT, pd.NaT]},
+            {
+                "a": [0, 1, 2],
+                "b": [
+                    Timestamp("1990-01-01"),
+                    Timestamp("1991-01-01"),
+                    Timestamp("1992-01-01"),
+                ],
+            },
+            {
+                "a": [0, 1, 2],
+                "b": [pd.Timedelta("1 days"), pd.Timedelta("2 days"), pd.NaT],
+            },
+            {
+                "a": [0, 1, 2],
+                "b": [
+                    pd.Timedelta("1 days"),
+                    pd.Timedelta("2 days"),
+                    pd.Timedelta("3 days"),
+                ],
+            },
+        ],
+    )
+    def test_df_cov_pd_nat(self, data):
+        # GH #53115
+        df = DataFrame(data)
+        with pytest.raises(TypeError, match="not supported for cov"):
+            df.cov()
+
 
 def test_sum_timedelta64_skipna_false():
     # GH#17235