Skip to content

Commit 52384d3

Browse files
authored
Timestamp -> datetime and Timedelta -> timedelta (#841)
* Timestamp -> datetime and Timedelta -> timedelta * keep redundancy * test * redundancy
1 parent 0a567b4 commit 52384d3

File tree

13 files changed

+130
-36
lines changed

13 files changed

+130
-36
lines changed

pandas-stubs/_libs/tslibs/timedeltas.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class Timedelta(timedelta):
210210
@overload
211211
def __rsub__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ...
212212
@overload
213-
def __rsub__(self, other: Timestamp | np.datetime64) -> Timestamp: ...
213+
def __rsub__(self, other: dt.datetime | Timestamp | np.datetime64) -> Timestamp: ... # type: ignore[misc]
214214
@overload
215215
def __rsub__(self, other: NaTType) -> NaTType: ...
216216
@overload

pandas-stubs/core/frame.pyi

+10-11
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ from collections.abc import (
77
MutableMapping,
88
Sequence,
99
)
10-
import datetime
11-
import datetime as _dt
10+
import datetime as dt
1211
from re import Pattern
1312
from typing import (
1413
Any,
@@ -373,7 +372,7 @@ class DataFrame(NDFrame, OpsMixin):
373372
convert_dates: dict[HashableT1, StataDateFormat] | None = ...,
374373
write_index: _bool = ...,
375374
byteorder: Literal["<", ">", "little", "big"] | None = ...,
376-
time_stamp: _dt.datetime | None = ...,
375+
time_stamp: dt.datetime | None = ...,
377376
data_label: _str | None = ...,
378377
variable_labels: dict[HashableT2, str] | None = ...,
379378
version: Literal[114, 117, 118, 119] | None = ...,
@@ -1565,14 +1564,14 @@ class DataFrame(NDFrame, OpsMixin):
15651564
) -> DataFrame: ...
15661565
def at_time(
15671566
self,
1568-
time: _str | datetime.time,
1567+
time: _str | dt.time,
15691568
asof: _bool = ...,
15701569
axis: Axis | None = ...,
15711570
) -> DataFrame: ...
15721571
def between_time(
15731572
self,
1574-
start_time: _str | datetime.time,
1575-
end_time: _str | datetime.time,
1573+
start_time: _str | dt.time,
1574+
end_time: _str | dt.time,
15761575
axis: Axis | None = ...,
15771576
) -> DataFrame: ...
15781577
@overload
@@ -1941,7 +1940,7 @@ class DataFrame(NDFrame, OpsMixin):
19411940
level: Level | None = ...,
19421941
origin: Timestamp
19431942
| Literal["epoch", "start", "start_day", "end", "end_day"] = ...,
1944-
offset: Timedelta | _str | None = ...,
1943+
offset: dt.timedelta | Timedelta | _str | None = ...,
19451944
group_keys: _bool = ...,
19461945
) -> Resampler[DataFrame]: ...
19471946
def rfloordiv(
@@ -1968,7 +1967,7 @@ class DataFrame(NDFrame, OpsMixin):
19681967
@overload
19691968
def rolling(
19701969
self,
1971-
window: int | str | _dt.timedelta | BaseOffset | BaseIndexer,
1970+
window: int | str | dt.timedelta | BaseOffset | BaseIndexer,
19721971
min_periods: int | None = ...,
19731972
center: _bool = ...,
19741973
on: Hashable | None = ...,
@@ -1982,7 +1981,7 @@ class DataFrame(NDFrame, OpsMixin):
19821981
@overload
19831982
def rolling(
19841983
self,
1985-
window: int | str | _dt.timedelta | BaseOffset | BaseIndexer,
1984+
window: int | str | dt.timedelta | BaseOffset | BaseIndexer,
19861985
min_periods: int | None = ...,
19871986
center: _bool = ...,
19881987
on: Hashable | None = ...,
@@ -2217,8 +2216,8 @@ class DataFrame(NDFrame, OpsMixin):
22172216
) -> DataFrame: ...
22182217
def truncate(
22192218
self,
2220-
before: datetime.date | _str | int | None = ...,
2221-
after: datetime.date | _str | int | None = ...,
2219+
before: dt.date | _str | int | None = ...,
2220+
after: dt.date | _str | int | None = ...,
22222221
axis: Axis | None = ...,
22232222
copy: _bool = ...,
22242223
) -> DataFrame: ...

pandas-stubs/core/indexes/accessors.pyi

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import datetime as dt
2-
from datetime import tzinfo
2+
from datetime import (
3+
timedelta,
4+
tzinfo,
5+
)
36
from typing import (
47
Generic,
58
Literal,
@@ -166,20 +169,23 @@ class _DatetimeRoundingMethods(Generic[_DTRoundingMethodReturnType]):
166169
freq: str | BaseOffset | None,
167170
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
168171
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
172+
| timedelta
169173
| Timedelta = ...,
170174
) -> _DTRoundingMethodReturnType: ...
171175
def floor(
172176
self,
173177
freq: str | BaseOffset | None,
174178
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
175179
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
180+
| timedelta
176181
| Timedelta = ...,
177182
) -> _DTRoundingMethodReturnType: ...
178183
def ceil(
179184
self,
180185
freq: str | BaseOffset | None,
181186
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
182187
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
188+
| timedelta
183189
| Timedelta = ...,
184190
) -> _DTRoundingMethodReturnType: ...
185191

@@ -206,6 +212,7 @@ class _DatetimeLikeNoTZMethods(
206212
tz: tzinfo | str | None,
207213
ambiguous: Literal["raise", "infer", "NaT"] | np_ndarray_bool = ...,
208214
nonexistent: Literal["shift_forward", "shift_backward", "NaT", "raise"]
215+
| timedelta
209216
| Timedelta = ...,
210217
) -> _DTNormalizeReturnType: ...
211218
def tz_convert(self, tz: tzinfo | str | None) -> _DTNormalizeReturnType: ...

pandas-stubs/core/indexes/datetimes.pyi

+10-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ from collections.abc import (
33
Sequence,
44
)
55
from datetime import (
6+
datetime,
67
timedelta,
78
tzinfo,
89
)
@@ -59,13 +60,19 @@ class DatetimeIndex(DatetimeTimedeltaMixin[Timestamp], DatetimeIndexProperties):
5960
@overload
6061
def __add__(self, other: TimedeltaSeries) -> TimestampSeries: ...
6162
@overload
62-
def __add__(self, other: Timedelta | TimedeltaIndex) -> DatetimeIndex: ...
63+
def __add__(
64+
self, other: timedelta | Timedelta | TimedeltaIndex
65+
) -> DatetimeIndex: ...
6366
@overload
6467
def __sub__(self, other: TimedeltaSeries) -> TimestampSeries: ...
6568
@overload
66-
def __sub__(self, other: Timedelta | TimedeltaIndex) -> DatetimeIndex: ...
69+
def __sub__(
70+
self, other: timedelta | Timedelta | TimedeltaIndex
71+
) -> DatetimeIndex: ...
6772
@overload
68-
def __sub__(self, other: Timestamp | DatetimeIndex) -> TimedeltaIndex: ...
73+
def __sub__(
74+
self, other: datetime | Timestamp | DatetimeIndex
75+
) -> TimedeltaIndex: ...
6976
def to_series(self, index=..., name=...) -> TimestampSeries: ...
7077
def snap(self, freq: str = ...): ...
7178
def get_value(self, series, key): ...

pandas-stubs/core/indexes/timedeltas.pyi

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ class TimedeltaIndex(DatetimeTimedeltaMixin[Timedelta], TimedeltaIndexProperties
5252
@overload
5353
def __add__(self, other: DatetimeIndex) -> DatetimeIndex: ...
5454
@overload
55-
def __add__(self, other: Timedelta | Self) -> Self: ...
56-
def __radd__(self, other: Timestamp | DatetimeIndex) -> DatetimeIndex: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
57-
def __sub__(self, other: Timedelta | Self) -> Self: ...
55+
def __add__(self, other: dt.timedelta | Timedelta | Self) -> Self: ...
56+
def __radd__(self, other: dt.datetime | Timestamp | DatetimeIndex) -> DatetimeIndex: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
57+
def __sub__(self, other: dt.timedelta | Timedelta | Self) -> Self: ...
5858
def __mul__(self, other: num) -> Self: ...
5959
@overload # type: ignore[override]
6060
def __truediv__(self, other: num | Sequence[float]) -> Self: ...

pandas-stubs/core/reshape/merge.pyi

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from datetime import timedelta
12
from typing import (
23
Literal,
34
overload,
@@ -6,9 +7,9 @@ from typing import (
67
from pandas import (
78
DataFrame,
89
Series,
10+
Timedelta,
911
)
1012

11-
from pandas._libs.tslibs import Timedelta
1213
from pandas._typing import (
1314
AnyArrayLike,
1415
HashableT,
@@ -99,7 +100,7 @@ def merge_asof(
99100
| tuple[str, str]
100101
| tuple[None, str]
101102
| tuple[str, None] = ...,
102-
tolerance: int | Timedelta | None = ...,
103+
tolerance: int | timedelta | Timedelta | None = ...,
103104
allow_exact_matches: bool = ...,
104105
direction: Literal["backward", "forward", "nearest"] = ...,
105106
) -> DataFrame: ...

pandas-stubs/core/series.pyi

+15-8
Original file line numberDiff line numberDiff line change
@@ -1352,9 +1352,10 @@ class Series(IndexOpsMixin[S1], NDFrame):
13521352
base: int = ...,
13531353
on: _str | None = ...,
13541354
level: Level | None = ...,
1355-
origin: Timestamp
1355+
origin: datetime
1356+
| Timestamp
13561357
| Literal["epoch", "start", "start_day", "end", "end_day"] = ...,
1357-
offset: Timedelta | _str | None = ...,
1358+
offset: timedelta | Timedelta | _str | None = ...,
13581359
) -> Resampler[Series]: ...
13591360
def first(self, offset) -> Series[S1]: ...
13601361
def last(self, offset) -> Series[S1]: ...
@@ -1456,7 +1457,8 @@ class Series(IndexOpsMixin[S1], NDFrame):
14561457
def __add__(self, other: S1 | Self) -> Self: ...
14571458
@overload
14581459
def __add__(
1459-
self, other: num | _str | Timedelta | _ListLike | Series | np.timedelta64
1460+
self,
1461+
other: num | _str | timedelta | Timedelta | _ListLike | Series | np.timedelta64,
14601462
) -> Series: ...
14611463
# ignore needed for mypy as we want different results based on the arguments
14621464
@overload # type: ignore[override]
@@ -1485,7 +1487,7 @@ class Series(IndexOpsMixin[S1], NDFrame):
14851487
) -> Series[_bool]: ...
14861488
@overload
14871489
def __mul__(
1488-
self, other: Timedelta | TimedeltaSeries | np.timedelta64
1490+
self, other: timedelta | Timedelta | TimedeltaSeries | np.timedelta64
14891491
) -> TimedeltaSeries: ...
14901492
@overload
14911493
def __mul__(self, other: num | _ListLike | Series) -> Series: ...
@@ -2043,18 +2045,23 @@ class TimedeltaSeries(Series[Timedelta]):
20432045
def __add__(self, other: Period) -> PeriodSeries: ...
20442046
@overload
20452047
def __add__(
2046-
self, other: Timestamp | TimestampSeries | DatetimeIndex
2048+
self, other: datetime | Timestamp | TimestampSeries | DatetimeIndex
20472049
) -> TimestampSeries: ...
20482050
@overload
20492051
def __add__( # pyright: ignore[reportIncompatibleMethodOverride]
2050-
self, other: Timedelta | np.timedelta64
2052+
self, other: timedelta | Timedelta | np.timedelta64
20512053
) -> TimedeltaSeries: ...
2052-
def __radd__(self, other: Timestamp | TimestampSeries) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
2054+
def __radd__(self, other: datetime | Timestamp | TimestampSeries) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
20532055
def __mul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
20542056
self, other: num | Sequence[num] | Series[int] | Series[float]
20552057
) -> TimedeltaSeries: ...
20562058
def __sub__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
2057-
self, other: Timedelta | TimedeltaSeries | TimedeltaIndex | np.timedelta64
2059+
self,
2060+
other: timedelta
2061+
| Timedelta
2062+
| TimedeltaSeries
2063+
| TimedeltaIndex
2064+
| np.timedelta64,
20582065
) -> TimedeltaSeries: ...
20592066
@overload # type: ignore[override]
20602067
def __truediv__(self, other: float | Sequence[float]) -> Self: ...

pandas-stubs/tseries/holiday.pyi

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ def register(cls: type[AbstractHolidayCalendar]) -> None: ...
7171
def get_calendar(name: str) -> AbstractHolidayCalendar: ...
7272

7373
class AbstractHolidayCalendar:
74-
rules: list[Holiday] = ...
75-
start_date: Timestamp = ...
76-
end_date: Timestamp = ...
74+
rules: list[Holiday]
75+
start_date: Timestamp
76+
end_date: Timestamp
7777

7878
def __init__(self, name: str = "", rules: list[Holiday] | None = None) -> None: ...
7979
def rule_from_name(self, name: str) -> Holiday | None: ...

tests/test_frame.py

+1
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ def test_types_resample() -> None:
13591359
with pytest_warns_bounded(FutureWarning, "'M' is deprecated", lower="2.1.99"):
13601360
df.resample("M", on="date")
13611361
df.resample("20min", origin="epoch", offset=pd.Timedelta(2, "minutes"), on="date")
1362+
df.resample("20min", origin="epoch", offset=datetime.timedelta(2), on="date")
13621363

13631364

13641365
def test_types_to_dict() -> None:

tests/test_indexes.py

+12
Original file line numberDiff line numberDiff line change
@@ -1048,3 +1048,15 @@ def test_timedelta_div() -> None:
10481048
[1] / index # type: ignore[operator] # pyright: ignore[reportGeneralTypeIssues]
10491049
1 // index # type: ignore[operator] # pyright: ignore[reportGeneralTypeIssues]
10501050
[1] // index # type: ignore[operator] # pyright: ignore[reportGeneralTypeIssues]
1051+
1052+
1053+
def test_datetime_operators_builtin() -> None:
1054+
time = pd.date_range("2022-01-01", "2022-01-31", freq="D")
1055+
check(assert_type(time + dt.timedelta(0), pd.DatetimeIndex), pd.DatetimeIndex)
1056+
check(assert_type(time - dt.timedelta(0), pd.DatetimeIndex), pd.DatetimeIndex)
1057+
check(assert_type(time - dt.datetime.now(), pd.TimedeltaIndex), pd.TimedeltaIndex)
1058+
1059+
delta = check(assert_type(time - time, pd.TimedeltaIndex), pd.TimedeltaIndex)
1060+
check(assert_type(delta + dt.timedelta(0), pd.TimedeltaIndex), pd.TimedeltaIndex)
1061+
check(assert_type(dt.datetime.now() + delta, pd.DatetimeIndex), pd.DatetimeIndex)
1062+
check(assert_type(delta - dt.timedelta(0), pd.TimedeltaIndex), pd.TimedeltaIndex)

tests/test_pandas.py

+9
Original file line numberDiff line numberDiff line change
@@ -1412,6 +1412,15 @@ def test_merge_asof() -> None:
14121412
),
14131413
pd.DataFrame,
14141414
)
1415+
check(
1416+
assert_type(
1417+
pd.merge_asof(
1418+
trades, quotes, on="time", by="ticker", tolerance=dt.timedelta(1)
1419+
),
1420+
pd.DataFrame,
1421+
),
1422+
pd.DataFrame,
1423+
)
14151424
check(
14161425
assert_type(
14171426
pd.merge_asof(

tests/test_series.py

+25
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,7 @@ def test_types_resample() -> None:
994994
s.resample("3min").sum()
995995
# origin and offset params added in 1.1.0 https://pandas.pydata.org/docs/whatsnew/v1.1.0.html
996996
s.resample("20min", origin="epoch", offset=pd.Timedelta(value=2, unit="minutes"))
997+
s.resample("20min", origin=datetime.datetime.now(), offset=datetime.timedelta(1))
997998

998999

9991000
# set_flags() method added in 1.2.0 https://pandas.pydata.org/docs/whatsnew/v1.2.0.html
@@ -2860,3 +2861,27 @@ def test_round() -> None:
28602861
def test_series_new_empty() -> None:
28612862
# GH 826
28622863
check(assert_type(pd.Series(), "pd.Series[Any]"), pd.Series)
2864+
2865+
2866+
def test_timedeltaseries_operators() -> None:
2867+
series = pd.Series([pd.Timedelta(days=1)])
2868+
check(
2869+
assert_type(series + datetime.datetime.now(), TimestampSeries),
2870+
pd.Series,
2871+
pd.Timestamp,
2872+
)
2873+
check(
2874+
assert_type(series + datetime.timedelta(1), TimedeltaSeries),
2875+
pd.Series,
2876+
pd.Timedelta,
2877+
)
2878+
check(
2879+
assert_type(datetime.datetime.now() + series, TimestampSeries),
2880+
pd.Series,
2881+
pd.Timestamp,
2882+
)
2883+
check(
2884+
assert_type(series - datetime.timedelta(1), TimedeltaSeries),
2885+
pd.Series,
2886+
pd.Timedelta,
2887+
)

tests/test_timefuncs.py

+30-4
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,10 @@ def test_series_dt_accessors() -> None:
373373
assert_type(s0.dt.tz_localize(None), "TimestampSeries"), pd.Series, pd.Timestamp
374374
)
375375
check(
376-
assert_type(s0.dt.tz_localize(pytz.UTC), "TimestampSeries"),
376+
assert_type(
377+
s0.dt.tz_localize(pytz.UTC, nonexistent=dt.timedelta(0)),
378+
"TimestampSeries",
379+
),
377380
pd.Series,
378381
pd.Timestamp,
379382
)
@@ -408,9 +411,21 @@ def test_series_dt_accessors() -> None:
408411
check(assert_type(s0_local.dt.tz, Optional[dt.tzinfo]), dt.tzinfo)
409412
check(assert_type(s0.dt.normalize(), "TimestampSeries"), pd.Series, pd.Timestamp)
410413
check(assert_type(s0.dt.strftime("%Y"), "pd.Series[str]"), pd.Series, str)
411-
check(assert_type(s0.dt.round("D"), "TimestampSeries"), pd.Series, pd.Timestamp)
412-
check(assert_type(s0.dt.floor("D"), "TimestampSeries"), pd.Series, pd.Timestamp)
413-
check(assert_type(s0.dt.ceil("D"), "TimestampSeries"), pd.Series, pd.Timestamp)
414+
check(
415+
assert_type(s0.dt.round("D", nonexistent=dt.timedelta(1)), "TimestampSeries"),
416+
pd.Series,
417+
pd.Timestamp,
418+
)
419+
check(
420+
assert_type(s0.dt.floor("D", nonexistent=dt.timedelta(1)), "TimestampSeries"),
421+
pd.Series,
422+
pd.Timestamp,
423+
)
424+
check(
425+
assert_type(s0.dt.ceil("D", nonexistent=dt.timedelta(1)), "TimestampSeries"),
426+
pd.Series,
427+
pd.Timestamp,
428+
)
414429
check(assert_type(s0.dt.month_name(), "pd.Series[str]"), pd.Series, str)
415430
check(assert_type(s0.dt.day_name(), "pd.Series[str]"), pd.Series, str)
416431

@@ -1234,3 +1249,14 @@ def test_date_range_unit():
12341249
),
12351250
pd.DatetimeIndex,
12361251
)
1252+
1253+
1254+
def test_DatetimeIndex_sub_timedelta() -> None:
1255+
# GH838
1256+
check(
1257+
assert_type(
1258+
pd.date_range("2023-01-01", periods=10, freq="1D") - dt.timedelta(days=1),
1259+
"pd.DatetimeIndex",
1260+
),
1261+
pd.DatetimeIndex,
1262+
)

0 commit comments

Comments
 (0)