Skip to content

Commit dd7ad86

Browse files
committed
timedelta on datetime df, series arithmetic
1 parent f1e6cc1 commit dd7ad86

File tree

3 files changed

+33
-3
lines changed

3 files changed

+33
-3
lines changed

doc/source/whatsnew/v3.0.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ Other enhancements
5757
- :meth:`pandas.concat` will raise a ``ValueError`` when ``ignore_index=True`` and ``keys`` is not ``None`` (:issue:`59274`)
5858
- :meth:`str.get_dummies` now accepts a ``dtype`` parameter to specify the dtype of the resulting DataFrame (:issue:`47872`)
5959
- Multiplying two :class:`DateOffset` objects will now raise a ``TypeError`` instead of a ``RecursionError`` (:issue:`59442`)
60+
- Arithmetic operations on :class:`Datetime` dataframe and series objects will result in :class:`Timedelta` values instead of ``TypeError`` (:issue: `59529`)
6061
- Restore support for reading Stata 104-format and enable reading 103-format dta files (:issue:`58554`)
6162
- Support passing a :class:`Iterable[Hashable]` input to :meth:`DataFrame.drop_duplicates` (:issue:`59237`)
6263
- Support reading Stata 102-format (Stata 1) dta files (:issue:`58978`)

pandas/core/internals/managers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,8 @@ def _make_na_block(
997997
dtype = interleaved_dtype([blk.dtype for blk in self.blocks])
998998
if dtype is not None and np.issubdtype(dtype.type, np.floating):
999999
fill_value = dtype.type(fill_value)
1000+
if dtype is not None and np.issubdtype(dtype.type, np.datetime64):
1001+
fill_value = np.datetime64("NaT")
10001002

10011003
shape = (len(placement), self.shape[1])
10021004

pandas/tests/frame/test_arithmetic.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,9 +1038,9 @@ def test_frame_with_frame_reindex(self):
10381038
[
10391039
(1, "i8"),
10401040
(1.0, "f8"),
1041-
(2**63, "f8"),
1041+
(2 ** 63, "f8"),
10421042
(1j, "complex128"),
1043-
(2**63, "complex128"),
1043+
(2 ** 63, "complex128"),
10441044
(True, "bool"),
10451045
(np.timedelta64(20, "ns"), "<m8[ns]"),
10461046
(np.datetime64(20, "ns"), "<M8[ns]"),
@@ -1147,6 +1147,33 @@ def test_arithmetic_midx_cols_different_dtypes_different_order(self):
11471147
expected = DataFrame([[-1, 1], [-1, 1]], columns=midx)
11481148
tm.assert_frame_equal(result, expected)
11491149

1150+
@pytest.mark.xfail(reason="NaT op NaT results in datetime instead of timedelta")
1151+
def test_arithmetic_datetime_df_series(self):
1152+
# GH#59529
1153+
df_datetime = DataFrame([[1, 2], [3, 4]]).astype("datetime64[ns]")
1154+
ser_datetime = Series([5, 6, 7]).astype("datetime64[ns]")
1155+
result = df_datetime - ser_datetime
1156+
expected = DataFrame(
1157+
[
1158+
[pd.Timedelta(-4), pd.Timedelta(-4), pd.Timedelta(pd.NaT)],
1159+
[pd.Timedelta(-2), pd.Timedelta(-2), pd.Timedelta(pd.NaT)],
1160+
]
1161+
)
1162+
tm.assert_frame_equal(result, expected)
1163+
1164+
@pytest.mark.xfail(reason="NaT op NaT results in datetime instead of timedelta")
1165+
def test_arithmetic_timestamp_timedelta(self):
1166+
# GH#59529
1167+
df_timestamp = DataFrame([pd.Timestamp(1)])
1168+
ser_timedelta = Series([pd.Timedelta(2), pd.Timedelta(3)])
1169+
result = df_timestamp - ser_timedelta
1170+
expected = DataFrame(
1171+
[
1172+
[pd.Timestamp(-1), pd.NaT],
1173+
]
1174+
)
1175+
tm.assert_frame_equal(result, expected)
1176+
11501177

11511178
def test_frame_with_zero_len_series_corner_cases():
11521179
# GH#28600
@@ -1913,7 +1940,7 @@ def test_pow_with_realignment():
19131940
left = DataFrame({"A": [0, 1, 2]})
19141941
right = DataFrame(index=[0, 1, 2])
19151942

1916-
result = left**right
1943+
result = left ** right
19171944
expected = DataFrame({"A": [np.nan, 1.0, np.nan]})
19181945
tm.assert_frame_equal(result, expected)
19191946

0 commit comments

Comments
 (0)