Skip to content

Commit cd35a2f

Browse files
committed
Add unit property and as_unit method to TimestampSeries and TimedeltaSeries
1 parent dc84f57 commit cd35a2f

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed

pandas-stubs/core/indexes/accessors.pyi

+22-14
Original file line numberDiff line numberDiff line change
@@ -154,40 +154,40 @@ class _DatetimeLikeOps(
154154
# type of the series, we don't know which kind of series was ...ed
155155
# in to the dt accessor
156156

157-
_DTRoundingMethodReturnType = TypeVar(
158-
"_DTRoundingMethodReturnType",
157+
_DTTimestampTimedeltaReturnType = TypeVar(
158+
"_DTTimestampTimedeltaReturnType",
159159
Series,
160-
TimedeltaSeries,
161160
TimestampSeries,
161+
TimedeltaSeries,
162162
DatetimeIndex,
163163
TimedeltaIndex,
164164
)
165165

166-
class _DatetimeRoundingMethods(Generic[_DTRoundingMethodReturnType]):
166+
class _DatetimeRoundingMethods(Generic[_DTTimestampTimedeltaReturnType]):
167167
def round(
168168
self,
169169
freq: str | BaseOffset | None,
170170
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
171171
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
172172
| timedelta
173173
| Timedelta = ...,
174-
) -> _DTRoundingMethodReturnType: ...
174+
) -> _DTTimestampTimedeltaReturnType: ...
175175
def floor(
176176
self,
177177
freq: str | BaseOffset | None,
178178
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
179179
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
180180
| timedelta
181181
| Timedelta = ...,
182-
) -> _DTRoundingMethodReturnType: ...
182+
) -> _DTTimestampTimedeltaReturnType: ...
183183
def ceil(
184184
self,
185185
freq: str | BaseOffset | None,
186186
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
187187
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
188188
| timedelta
189189
| Timedelta = ...,
190-
) -> _DTRoundingMethodReturnType: ...
190+
) -> _DTTimestampTimedeltaReturnType: ...
191191

192192
_DTNormalizeReturnType = TypeVar(
193193
"_DTNormalizeReturnType", TimestampSeries, DatetimeIndex
@@ -196,9 +196,9 @@ _DTStrKindReturnType = TypeVar("_DTStrKindReturnType", Series[str], Index)
196196
_DTToPeriodReturnType = TypeVar("_DTToPeriodReturnType", PeriodSeries, PeriodIndex)
197197

198198
class _DatetimeLikeNoTZMethods(
199-
_DatetimeRoundingMethods[_DTRoundingMethodReturnType],
199+
_DatetimeRoundingMethods[_DTTimestampTimedeltaReturnType],
200200
Generic[
201-
_DTRoundingMethodReturnType,
201+
_DTTimestampTimedeltaReturnType,
202202
_DTNormalizeReturnType,
203203
_DTStrKindReturnType,
204204
_DTToPeriodReturnType,
@@ -230,15 +230,15 @@ class _DatetimeNoTZProperties(
230230
_DTFreqReturnType,
231231
],
232232
_DatetimeLikeNoTZMethods[
233-
_DTRoundingMethodReturnType,
233+
_DTTimestampTimedeltaReturnType,
234234
_DTNormalizeReturnType,
235235
_DTStrKindReturnType,
236236
_DTToPeriodReturnType,
237237
],
238238
Generic[
239239
_DTFieldOpsReturnType,
240240
_DTBoolOpsReturnType,
241-
_DTRoundingMethodReturnType,
241+
_DTTimestampTimedeltaReturnType,
242242
_DTOtherOpsDateReturnType,
243243
_DTOtherOpsTimeReturnType,
244244
_DTFreqReturnType,
@@ -253,7 +253,7 @@ class DatetimeProperties(
253253
_DatetimeNoTZProperties[
254254
_DTFieldOpsReturnType,
255255
_DTBoolOpsReturnType,
256-
_DTRoundingMethodReturnType,
256+
_DTTimestampTimedeltaReturnType,
257257
_DTOtherOpsDateReturnType,
258258
_DTOtherOpsTimeReturnType,
259259
_DTFreqReturnType,
@@ -264,7 +264,7 @@ class DatetimeProperties(
264264
Generic[
265265
_DTFieldOpsReturnType,
266266
_DTBoolOpsReturnType,
267-
_DTRoundingMethodReturnType,
267+
_DTTimestampTimedeltaReturnType,
268268
_DTOtherOpsDateReturnType,
269269
_DTOtherOpsTimeReturnType,
270270
_DTFreqReturnType,
@@ -275,6 +275,11 @@ class DatetimeProperties(
275275
):
276276
def to_pydatetime(self) -> np.ndarray: ...
277277
def isocalendar(self) -> DataFrame: ...
278+
@property
279+
def unit(self) -> str: ...
280+
def as_unit(
281+
self, unit: Literal["s", "ms", "us", "ns"]
282+
) -> _DTTimestampTimedeltaReturnType: ...
278283

279284
_TDNoRoundingMethodReturnType = TypeVar(
280285
"_TDNoRoundingMethodReturnType", Series[int], Index
@@ -301,7 +306,10 @@ class TimedeltaProperties(
301306
Properties,
302307
_TimedeltaPropertiesNoRounding[Series[int], Series[float]],
303308
_DatetimeRoundingMethods[TimedeltaSeries],
304-
): ...
309+
):
310+
@property
311+
def unit(self) -> str: ...
312+
def as_unit(self, unit: Literal["s", "ms", "us", "ns"]) -> TimedeltaSeries: ...
305313

306314
_PeriodDTReturnTypes = TypeVar("_PeriodDTReturnTypes", TimestampSeries, DatetimeIndex)
307315
_PeriodIntReturnTypes = TypeVar("_PeriodIntReturnTypes", Series[int], Index[int])

tests/test_timefuncs.py

+35
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
TYPE_CHECKING,
66
Any,
77
Optional,
8+
cast,
89
)
910

1011
import numpy as np
@@ -428,6 +429,11 @@ def test_series_dt_accessors() -> None:
428429
)
429430
check(assert_type(s0.dt.month_name(), "pd.Series[str]"), pd.Series, str)
430431
check(assert_type(s0.dt.day_name(), "pd.Series[str]"), pd.Series, str)
432+
check(assert_type(s0.dt.unit, str), str)
433+
check(assert_type(s0.dt.as_unit("s"), "TimestampSeries"), pd.Series, pd.Timestamp)
434+
check(assert_type(s0.dt.as_unit("ms"), "TimestampSeries"), pd.Series, pd.Timestamp)
435+
check(assert_type(s0.dt.as_unit("us"), "TimestampSeries"), pd.Series, pd.Timestamp)
436+
check(assert_type(s0.dt.as_unit("ns"), "TimestampSeries"), pd.Series, pd.Timestamp)
431437

432438
i1 = pd.period_range(start="2022-06-01", periods=10)
433439

@@ -455,6 +461,35 @@ def test_series_dt_accessors() -> None:
455461
check(assert_type(s2.dt.components, pd.DataFrame), pd.DataFrame)
456462
check(assert_type(s2.dt.to_pytimedelta(), np.ndarray), np.ndarray)
457463
check(assert_type(s2.dt.total_seconds(), "pd.Series[float]"), pd.Series, float)
464+
check(assert_type(s2.dt.unit, str), str)
465+
check(assert_type(s2.dt.as_unit("s"), "TimedeltaSeries"), pd.Series, pd.Timedelta)
466+
check(assert_type(s2.dt.as_unit("ms"), "TimedeltaSeries"), pd.Series, pd.Timedelta)
467+
check(assert_type(s2.dt.as_unit("us"), "TimedeltaSeries"), pd.Series, pd.Timedelta)
468+
check(assert_type(s2.dt.as_unit("ns"), "TimedeltaSeries"), pd.Series, pd.Timedelta)
469+
470+
# Checks for general Series other than TimestampSeries and TimedeltaSeries
471+
472+
s4 = cast(
473+
"pd.Series[pd.Timestamp]",
474+
pd.Series([pd.Timestamp("2024-01-01"), pd.Timestamp("2024-01-02")]),
475+
)
476+
477+
check(assert_type(s4.dt.unit, str), str)
478+
check(assert_type(s4.dt.as_unit("s"), pd.Series), pd.Series, pd.Timestamp)
479+
check(assert_type(s4.dt.as_unit("ms"), pd.Series), pd.Series, pd.Timestamp)
480+
check(assert_type(s4.dt.as_unit("us"), pd.Series), pd.Series, pd.Timestamp)
481+
check(assert_type(s4.dt.as_unit("ns"), pd.Series), pd.Series, pd.Timestamp)
482+
483+
s5 = cast(
484+
"pd.Series[pd.Timedelta]",
485+
pd.Series([pd.Timedelta("1 day"), pd.Timedelta("2 days")]),
486+
)
487+
488+
check(assert_type(s5.dt.unit, str), str)
489+
check(assert_type(s5.dt.as_unit("s"), pd.Series), pd.Series, pd.Timedelta)
490+
check(assert_type(s5.dt.as_unit("ms"), pd.Series), pd.Series, pd.Timedelta)
491+
check(assert_type(s5.dt.as_unit("us"), pd.Series), pd.Series, pd.Timedelta)
492+
check(assert_type(s5.dt.as_unit("ns"), pd.Series), pd.Series, pd.Timedelta)
458493

459494

460495
def test_datetimeindex_accessors() -> None:

0 commit comments

Comments
 (0)