Skip to content

Commit

Permalink
BUG: allow Series[Period].astype(dt64) (pandas-dev#45055)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored Dec 27, 2021
1 parent f1b255d commit aff0694
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 26 deletions.
11 changes: 3 additions & 8 deletions doc/source/user_guide/timeseries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2102,19 +2102,14 @@ The ``period`` dtype can be used in ``.astype(...)``. It allows one to change th
# change monthly freq to daily freq
pi.astype("period[D]")
# convert to DatetimeIndex
pi.astype("datetime64[ns]")
# convert to PeriodIndex
dti = pd.date_range("2011-01-01", freq="M", periods=3)
dti
dti.astype("period[M]")
.. deprecated:: 1.4.0
Converting PeriodIndex to DatetimeIndex with ``.astype(...)`` is deprecated and will raise in a future version. Use ``obj.to_timestamp(how).tz_localize(dtype.tz)`` instead.

.. ipython:: python
# convert to DatetimeIndex
pi.to_timestamp(how="start")
PeriodIndex partial string indexing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,6 @@ Other Deprecations
- Deprecated casting behavior when passing an item with mismatched-timezone to :meth:`DatetimeIndex.insert`, :meth:`DatetimeIndex.putmask`, :meth:`DatetimeIndex.where` :meth:`DatetimeIndex.fillna`, :meth:`Series.mask`, :meth:`Series.where`, :meth:`Series.fillna`, :meth:`Series.shift`, :meth:`Series.replace`, :meth:`Series.reindex` (and :class:`DataFrame` column analogues). In the past this has cast to object dtype. In a future version, these will cast the passed item to the index or series's timezone (:issue:`37605`,:issue:`44940`)
- Deprecated the 'errors' keyword argument in :meth:`Series.where`, :meth:`DataFrame.where`, :meth:`Series.mask`, and :meth:`DataFrame.mask`; in a future version the argument will be removed (:issue:`44294`)
- Deprecated the ``prefix`` keyword argument in :func:`read_csv` and :func:`read_table`, in a future version the argument will be removed (:issue:`43396`)
- Deprecated :meth:`PeriodIndex.astype` to ``datetime64[ns]`` or ``DatetimeTZDtype``, use ``obj.to_timestamp(how).tz_localize(dtype.tz)`` instead (:issue:`44398`)
- Deprecated passing non boolean argument to sort in :func:`concat` (:issue:`41518`)
- Deprecated passing arguments as positional for :func:`read_fwf` other than ``filepath_or_buffer`` (:issue:`41485`):
- Deprecated passing ``skipna=None`` for :meth:`DataFrame.mad` and :meth:`Series.mad`, pass ``skipna=True`` instead (:issue:`44580`)
Expand Down Expand Up @@ -676,6 +675,7 @@ Conversion
- Bug in :meth:`DataFrame.astype` not propagating ``attrs`` from the original :class:`DataFrame` (:issue:`44414`)
- Bug in :meth:`DataFrame.convert_dtypes` result losing ``columns.names`` (:issue:`41435`)
- Bug in constructing a ``IntegerArray`` from pyarrow data failing to validate dtypes (:issue:`44891`)
- Bug in :meth:`Series.astype` not allowing converting from a ``PeriodDtype`` to ``datetime64`` dtype, inconsistent with the :class:`PeriodIndex` behavior (:issue:`45038`)
-

Strings
Expand Down
7 changes: 7 additions & 0 deletions pandas/core/arrays/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from pandas.core.dtypes.common import (
TD64NS_DTYPE,
ensure_object,
is_datetime64_any_dtype,
is_datetime64_dtype,
is_dtype_equal,
is_float_dtype,
Expand Down Expand Up @@ -666,6 +667,12 @@ def astype(self, dtype, copy: bool = True):
return self.copy()
if is_period_dtype(dtype):
return self.asfreq(dtype.freq)

if is_datetime64_any_dtype(dtype):
# GH#45038 match PeriodIndex behavior.
tz = getattr(dtype, "tz", None)
return self.to_timestamp().tz_localize(tz)

return super().astype(dtype, copy=copy)

def searchsorted(
Expand Down
11 changes: 3 additions & 8 deletions pandas/core/indexes/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,14 +358,9 @@ def astype(self, dtype, copy: bool = True, how=lib.no_default):

if is_datetime64_any_dtype(dtype):
# 'how' is index-specific, isn't part of the EA interface.
# GH#44398 deprecate astype(dt64), matching Series behavior
warnings.warn(
f"Converting {type(self).__name__} to DatetimeIndex with "
"'astype' is deprecated and will raise in a future version. "
"Use `obj.to_timestamp(how).tz_localize(dtype.tz)` instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
# GH#45038 implement this for PeriodArray (but without "how")
# once the "how" deprecation is enforced we can just dispatch
# directly to PeriodArray.
tz = getattr(dtype, "tz", None)
return self.to_timestamp(how=how).tz_localize(tz)

Expand Down
11 changes: 9 additions & 2 deletions pandas/tests/arrays/period/test_astype.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,12 @@ def test_astype_period():
def test_astype_datetime(other):
arr = period_array(["2000", "2001", None], freq="D")
# slice off the [ns] so that the regex matches.
with pytest.raises(TypeError, match=other[:-4]):
arr.astype(other)
if other == "timedelta64[ns]":
with pytest.raises(TypeError, match=other[:-4]):
arr.astype(other)

else:
# GH#45038 allow period->dt64 because we allow dt64->period
result = arr.astype(other)
expected = pd.DatetimeIndex(["2000", "2001", pd.NaT])._data
tm.assert_datetime_array_equal(result, expected)
5 changes: 1 addition & 4 deletions pandas/tests/indexes/period/methods/test_astype.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,7 @@ def test_period_astype_to_timestamp(self):
assert res.freq == exp.freq

exp = DatetimeIndex(["2011-01-01", "2011-02-01", "2011-03-01"], tz="US/Eastern")
msg = "Use `obj.to_timestamp"
with tm.assert_produces_warning(FutureWarning, match=msg):
# GH#44398
res = pi.astype("datetime64[ns, US/Eastern]")
res = pi.astype("datetime64[ns, US/Eastern]")
tm.assert_index_equal(res, exp)
assert res.freq == exp.freq

Expand Down
3 changes: 0 additions & 3 deletions pandas/tests/indexes/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,6 @@ def test_astype_preserves_name(self, index, dtype):
):
# This astype is deprecated in favor of tz_localize
warn = FutureWarning
elif isinstance(index, PeriodIndex) and dtype == "datetime64[ns]":
# Deprecated in favor of to_timestamp GH#44398
warn = FutureWarning
try:
# Some of these conversions cannot succeed so we use a try / except
with tm.assert_produces_warning(warn):
Expand Down

0 comments on commit aff0694

Please sign in to comment.