diff --git a/doc/source/reference/series.rst b/doc/source/reference/series.rst index 659385c611ff0..5a43e5796d1d9 100644 --- a/doc/source/reference/series.rst +++ b/doc/source/reference/series.rst @@ -326,6 +326,7 @@ Datetime properties Series.dt.days_in_month Series.dt.tz Series.dt.freq + Series.dt.unit Datetime methods ^^^^^^^^^^^^^^^^ @@ -346,6 +347,7 @@ Datetime methods Series.dt.ceil Series.dt.month_name Series.dt.day_name + Series.dt.as_unit Period properties ^^^^^^^^^^^^^^^^^ @@ -370,6 +372,7 @@ Timedelta properties Series.dt.microseconds Series.dt.nanoseconds Series.dt.components + Series.dt.unit Timedelta methods ^^^^^^^^^^^^^^^^^ @@ -380,6 +383,7 @@ Timedelta methods Series.dt.to_pytimedelta Series.dt.total_seconds + Series.dt.as_unit .. _api.series.str: diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index f907e89880d25..c9113182f862e 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -291,6 +291,7 @@ Other enhancements - Improved error message in :func:`to_datetime` for non-ISO8601 formats, informing users about the position of the first error (:issue:`50361`) - Improved error message when trying to align :class:`DataFrame` objects (for example, in :func:`DataFrame.compare`) to clarify that "identically labelled" refers to both index and columns (:issue:`50083`) - Added :meth:`DatetimeIndex.as_unit` and :meth:`TimedeltaIndex.as_unit` to convert to different resolutions; supported resolutions are "s", "ms", "us", and "ns" (:issue:`50616`) +- Added :meth:`Series.dt.unit` and :meth:`Series.dt.as_unit` to convert to different resolutions; supported resolutions are "s", "ms", "us", and "ns" (:issue:`51223`) - Added new argument ``dtype`` to :func:`read_sql` to be consistent with :func:`read_sql_query` (:issue:`50797`) - diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 1bf43f61a67a7..d2154265d5cb0 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -228,7 +228,9 @@ def _scalar_type(self) -> type[Timestamp]: "nanosecond", ] _other_ops: list[str] = ["date", "time", "timetz"] - _datetimelike_ops: list[str] = _field_ops + _object_ops + _bool_ops + _other_ops + _datetimelike_ops: list[str] = ( + _field_ops + _object_ops + _bool_ops + _other_ops + ["unit"] + ) _datetimelike_methods: list[str] = [ "to_period", "tz_localize", @@ -240,6 +242,7 @@ def _scalar_type(self) -> type[Timestamp]: "ceil", "month_name", "day_name", + "as_unit", ] # ndim is inherited from ExtensionArray, must exist to ensure diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 861c9712cd2ae..65eaf83c48bb8 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -137,13 +137,14 @@ def _scalar_type(self) -> type[Timedelta]: _bool_ops: list[str] = [] _object_ops: list[str] = ["freq"] _field_ops: list[str] = ["days", "seconds", "microseconds", "nanoseconds"] - _datetimelike_ops: list[str] = _field_ops + _object_ops + _bool_ops + _datetimelike_ops: list[str] = _field_ops + _object_ops + _bool_ops + ["unit"] _datetimelike_methods: list[str] = [ "to_pytimedelta", "total_seconds", "round", "floor", "ceil", + "as_unit", ] # Note: ndim must be defined to ensure NaT.__richcmp__(TimedeltaArray) diff --git a/pandas/core/indexes/accessors.py b/pandas/core/indexes/accessors.py index 7525e8131fabf..788448f2c7be6 100644 --- a/pandas/core/indexes/accessors.py +++ b/pandas/core/indexes/accessors.py @@ -227,10 +227,14 @@ def isocalendar(self): @delegate_names( - delegate=DatetimeArray, accessors=DatetimeArray._datetimelike_ops, typ="property" + delegate=DatetimeArray, + accessors=DatetimeArray._datetimelike_ops + ["unit"], + typ="property", ) @delegate_names( - delegate=DatetimeArray, accessors=DatetimeArray._datetimelike_methods, typ="method" + delegate=DatetimeArray, + accessors=DatetimeArray._datetimelike_methods + ["as_unit"], + typ="method", ) class DatetimeProperties(Properties): """ diff --git a/pandas/tests/series/accessors/test_cat_accessor.py b/pandas/tests/series/accessors/test_cat_accessor.py index 9266afc89fa19..c999a3efee31f 100644 --- a/pandas/tests/series/accessors/test_cat_accessor.py +++ b/pandas/tests/series/accessors/test_cat_accessor.py @@ -167,6 +167,7 @@ def test_dt_accessor_api_for_categorical(self, idx): ("floor", ("D",), {}), ("ceil", ("D",), {}), ("asfreq", ("D",), {}), + ("as_unit", ("s"), {}), ] if idx.dtype == "M8[ns]": # exclude dt64tz since that is already localized and would raise diff --git a/pandas/tests/series/accessors/test_dt_accessor.py b/pandas/tests/series/accessors/test_dt_accessor.py index 1914bdae07e4b..a7e3cd43d1a6e 100644 --- a/pandas/tests/series/accessors/test_dt_accessor.py +++ b/pandas/tests/series/accessors/test_dt_accessor.py @@ -55,6 +55,7 @@ "day_name", "month_name", "isocalendar", + "as_unit", ] ok_for_td = TimedeltaArray._datetimelike_ops ok_for_td_methods = [ @@ -64,6 +65,7 @@ "round", "floor", "ceil", + "as_unit", ]