Skip to content
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ Categorical
- Bug in :meth:`Categorical.astype` where ``copy=False`` would still trigger a copy of the codes (:issue:`62000`)
- Bug in :meth:`DataFrame.pivot` and :meth:`DataFrame.set_index` raising an ``ArrowNotImplementedError`` for columns with pyarrow dictionary dtype (:issue:`53051`)
- Bug in :meth:`Series.convert_dtypes` with ``dtype_backend="pyarrow"`` where empty :class:`CategoricalDtype` :class:`Series` raised an error or got converted to ``null[pyarrow]`` (:issue:`59934`)
-
- Bug in :meth:`array.astype` where casting a pyarrow-backed array to a temporal :class:`CategoricalDtype` (e.g. with datetime or timedelta categories) raised or incorrectly converted values to all ``NaT`` (:issue:`62051`)

Datetimelike
^^^^^^^^^^^^
Expand Down
1 change: 1 addition & 0 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3673,6 +3673,7 @@ def get_indexer(
method = clean_reindex_fill_method(method)
orig_target = target
target = self._maybe_cast_listlike_indexer(target)
target, self = target._maybe_downcast_for_indexing(self)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does doing this here mean that we don't need to do it again below?


self._check_indexing_method(method, limit, tolerance)

Expand Down
13 changes: 12 additions & 1 deletion pandas/core/indexes/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from pandas.core.dtypes.common import (
is_integer,
is_list_like,
is_timedelta64_dtype,
)
from pandas.core.dtypes.concat import concat_compat
from pandas.core.dtypes.dtypes import (
Expand All @@ -57,6 +58,7 @@
TimedeltaArray,
)
from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin
from pandas.core.arrays.timedeltas import sequence_to_td64ns
import pandas.core.common as com
import pandas.core.indexes.base as ibase
from pandas.core.indexes.base import (
Expand Down Expand Up @@ -415,7 +417,16 @@ def _maybe_cast_listlike_indexer(self, keyarr):
# TODO: com.asarray_tuplesafe shouldn't cast e.g. DatetimeArray
else:
res = keyarr
return Index(res, dtype=res.dtype)

res_index = Index(res, dtype=res.dtype)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should wrapping in an Index go just once at the end?


if isinstance(res, ExtensionArray):
if res_index.dtype == "string[pyarrow]" and is_timedelta64_dtype(
self.dtype
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in this file we usually just check self.dtype.kind == "m"

):
data, freq = sequence_to_td64ns(res_index, copy=False, unit=None)
res_index = type(res_index)(data)
return res_index


class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin, ABC):
Expand Down
27 changes: 27 additions & 0 deletions pandas/tests/arrays/categorical/test_astype.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
CategoricalDtype,
CategoricalIndex,
DatetimeIndex,
Index,
Interval,
NaT,
Period,
Timestamp,
array,
isna,
to_datetime,
)
import pandas._testing as tm
from pandas.core.arrays.arrow.array import ArrowExtensionArray


class TestAstype:
Expand Down Expand Up @@ -160,3 +163,27 @@ def test_astype_category_readonly_mask_values(self):
result = arr.astype("category")
expected = array([0, 1, 2], dtype="Int64").astype("category")
tm.assert_extension_array_equal(result, expected)

def test_arrow_array_astype_to_categorical_dtype_date(self):
# GH#62051
pytest.importorskip("pyarrow")
arr = array(
["2017-01-01", "2018-01-01", "2019-01-01"], dtype="date32[day][pyarrow]"
)
cats = Index(["2017-01-01", "2018-01-01", "2019-01-01"], dtype="M8[s]")
dtype = CategoricalDtype(categories=cats, ordered=False)
assert not all(isna(arr.astype(dtype)))

arr_index, cats = Index(arr)._maybe_downcast_for_indexing(cats)
assert cats._should_compare(arr_index)

def test_arrow_array_astype_to_categorical_dtype_timedelta(self):
# GH#62051
pytest.importorskip("pyarrow")
arr = ArrowExtensionArray._from_sequence(["1h", "2h", "3h"])
cats = Index(["1h", "2h", "3h"], dtype="m8[ns]")
dtype = CategoricalDtype(cats, ordered=False)
assert not all(isna(arr.astype(dtype)))

arr_index = cats._maybe_cast_listlike_indexer(Index(arr))
tm.assert_index_equal(arr_index, cats)
Loading