Skip to content

Commit eefc775

Browse files
jbrockmendelclaude
andcommitted
DEPR: deprecate dates-with-datetime64 in _maybe_downcast_for_indexing
Deprecate the special case in Index._maybe_downcast_for_indexing that implicitly converts sequences of datetime.date objects to DatetimeIndex when joining or indexing. This affects join, alignment, and get_indexer fallback paths where _maybe_cast_listlike_indexer does not handle the conversion. closes #62158 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5c2795a commit eefc775

6 files changed

Lines changed: 44 additions & 6 deletions

File tree

doc/source/whatsnew/v3.1.0.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Deprecations
9999
- Deprecated :meth:`ExcelFile.parse`, use :func:`read_excel` instead (:issue:`58247`)
100100
- Deprecated arithmetic operations between pandas objects (:class:`DataFrame`, :class:`Series`, :class:`Index`, and pandas-implemented :class:`ExtensionArray` subclasses) and list-likes other than ``list``, ``np.ndarray``, :class:`ExtensionArray`, :class:`Index`, :class:`Series`, :class:`DataFrame`. For e.g. ``tuple`` or ``range``, explicitly cast these to a supported object instead. In a future version, these will be treated as scalar-like for pointwise operation (:issue:`62423`)
101101
- Deprecated automatic dtype promotion when reindexing with a ``fill_value`` that cannot be held by the original dtype. Explicitly cast to a common dtype instead (:issue:`53910`)
102+
- Deprecated implicit conversion of ``datetime.date`` objects to :class:`Timestamp` when indexing or joining a :class:`DatetimeIndex`. Use :func:`to_datetime` to explicitly convert to :class:`DatetimeIndex` instead (:issue:`62158`)
102103
- Deprecated passing unnecessary ``*args`` and ``**kwargs`` to :meth:`.GroupBy.cumsum`, :meth:`.GroupBy.cumprod`, :meth:`.GroupBy.cummin`, :meth:`.GroupBy.cummax`, :meth:`.SeriesGroupBy.skew`, :meth:`.DataFrameGroupBy.skew`, :meth:`.SeriesGroupBy.take`, and :meth:`.DataFrameGroupBy.take`. The ``skipna`` parameter for the cum* methods is now an explicit keyword argument (:issue:`50407`)
103104
- Deprecated the ``.name`` property of offset objects (e.g., :class:`~pandas.tseries.offsets.Day`, :class:`~pandas.tseries.offsets.Hour`). Use ``.rule_code`` instead (:issue:`64207`)
104105
- Deprecated the ``xlrd`` and ``pyxlsb`` engines in :func:`read_excel`. Use ``engine="calamine"`` instead (:issue:`56542`)

pandas/core/indexes/base.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6534,9 +6534,18 @@ def _maybe_downcast_for_indexing(self, other: Index) -> tuple[Index, Index]:
65346534

65356535
elif self.inferred_type == "date" and isinstance(other, ABCDatetimeIndex):
65366536
try:
6537-
return type(other)(self), other
6537+
result = type(other)(self), other
65386538
except OutOfBoundsDatetime:
65396539
return self, other
6540+
else:
6541+
warnings.warn(
6542+
# GH#62158 deprecate special-case treatment of date objects
6543+
"Indexing a DatetimeIndex with a sequence of datetime.date "
6544+
"objects is deprecated. Use Timestamp objects instead.",
6545+
Pandas4Warning,
6546+
stacklevel=find_stack_level(),
6547+
)
6548+
return result
65406549
elif self.inferred_type == "timedelta" and isinstance(other, ABCTimedeltaIndex):
65416550
# TODO: we dont have tests that get here
65426551
return type(other)(self), other

pandas/tests/frame/methods/test_asfreq.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55

66
from pandas._libs.tslibs.offsets import MonthEnd
7+
from pandas.errors import Pandas4Warning
78

89
from pandas import (
910
DataFrame,
@@ -192,7 +193,10 @@ def test_asfreq_with_date_object_index(self, frame_or_series):
192193
ts2 = ts.copy()
193194
ts2.index = [x.date() for x in ts2.index]
194195

195-
result = ts2.asfreq("4h", method="ffill")
196+
# GH#62158 date-object Index reindexed against DatetimeIndex
197+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
198+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
199+
result = ts2.asfreq("4h", method="ffill")
196200
expected = ts.asfreq("4h", method="ffill")
197201
tm.assert_equal(result, expected)
198202

pandas/tests/indexes/datetimes/test_indexing.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,11 @@ def test_get_indexer(self):
604604
def test_get_indexer_mixed_dtypes(self, target):
605605
# https://github.com/pandas-dev/pandas/issues/33741
606606
values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])
607-
result = values.get_indexer(target)
607+
# GH#62158 mixed date/Timestamp list infers as "date", triggering
608+
# the _maybe_downcast_for_indexing fallback
609+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
610+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
611+
result = values.get_indexer(target)
608612
expected = np.array([0, 1], dtype=np.intp)
609613
tm.assert_numpy_array_equal(result, expected)
610614

@@ -617,9 +621,12 @@ def test_get_indexer_mixed_dtypes(self, target):
617621
],
618622
)
619623
def test_get_indexer_out_of_bounds_date(self, target, positions):
624+
# GH#62158
620625
values = DatetimeIndex([Timestamp("2020-01-01"), Timestamp("2020-01-02")])
621626

622-
result = values.get_indexer(target)
627+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
628+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
629+
result = values.get_indexer(target)
623630
expected = np.array(positions, dtype=np.intp)
624631
tm.assert_numpy_array_equal(result, expected)
625632

pandas/tests/indexes/datetimes/test_join.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
from datetime import (
2+
date,
23
datetime,
34
timezone,
45
)
56

67
import numpy as np
78
import pytest
89

10+
from pandas.errors import Pandas4Warning
11+
912
from pandas import (
1013
DataFrame,
1114
DatetimeIndex,
@@ -151,3 +154,14 @@ def test_join_preserves_freq(self, tz):
151154
assert result.freq is None
152155
expected = dti.delete(5)
153156
tm.assert_index_equal(result, expected)
157+
158+
159+
def test_join_date_objects_with_datetimeindex():
160+
# GH#62158
161+
dti = date_range("2016-01-01", periods=3)
162+
date_idx = Index([date(2016, 1, 1), date(2016, 1, 2), date(2016, 1, 3)])
163+
164+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
165+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
166+
result = dti.join(date_idx, how="inner")
167+
tm.assert_index_equal(result, dti)

pandas/tests/series/test_arithmetic.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -895,8 +895,11 @@ def test_align_date_objects_with_datetimeindex(self):
895895
ts2 = ts_slice.copy()
896896
ts2.index = [x.date() for x in ts2.index]
897897

898-
result = ts + ts2
899-
result2 = ts2 + ts
898+
# GH#62158 alignment joins date-object Index with DatetimeIndex
899+
msg = "Indexing a DatetimeIndex with a sequence of datetime.date"
900+
with tm.assert_produces_warning(Pandas4Warning, match=msg):
901+
result = ts + ts2
902+
result2 = ts2 + ts
900903
expected = ts + ts[5:]
901904
expected.index = expected.index._with_freq(None)
902905
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)