Skip to content

Commit ba84f84

Browse files
authored
Warn when unit keyword is ignored (#62841)
1 parent 8d48f02 commit ba84f84

File tree

8 files changed

+49
-7
lines changed

8 files changed

+49
-7
lines changed

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,6 +2026,19 @@ class Timedelta(_Timedelta):
20262026
"milliseconds, microseconds, nanoseconds]"
20272027
)
20282028

2029+
if (
2030+
unit is not None
2031+
and not (is_float_object(value) or is_integer_object(value))
2032+
):
2033+
# GH#53198
2034+
warnings.warn(
2035+
"The 'unit' keyword is only used when the Timedelta input is "
2036+
f"an integer or float, not {type(value).__name__}. "
2037+
"To specify the storage unit of the output use `td.as_unit(unit)`",
2038+
UserWarning,
2039+
stacklevel=find_stack_level(),
2040+
)
2041+
20292042
if value is _no_input:
20302043
if not len(kwargs):
20312044
raise ValueError("cannot construct a Timedelta without a "

pandas/_libs/tslibs/timestamps.pyx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ from pandas._libs.tslibs.dtypes cimport (
6767
)
6868
from pandas._libs.tslibs.util cimport (
6969
is_array,
70+
is_float_object,
7071
is_integer_object,
7172
)
7273

@@ -2654,6 +2655,19 @@ class Timestamp(_Timestamp):
26542655
if hasattr(ts_input, "fold"):
26552656
ts_input = ts_input.replace(fold=fold)
26562657
2658+
if (
2659+
unit is not None
2660+
and not (is_float_object(ts_input) or is_integer_object(ts_input))
2661+
):
2662+
# GH#53198
2663+
warnings.warn(
2664+
"The 'unit' keyword is only used when the Timestamp input is "
2665+
f"an integer or float, not {type(ts_input).__name__}. "
2666+
"To specify the storage unit of the output use `ts.as_unit(unit)`",
2667+
UserWarning,
2668+
stacklevel=find_stack_level(),
2669+
)
2670+
26572671
# GH 30543 if pd.Timestamp already passed, return it
26582672
# check that only ts_input is passed
26592673
# checking verbosely, because cython doesn't optimize

pandas/core/computation/pytables.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import numpy as np
1919

20+
from pandas._libs import lib
2021
from pandas._libs.tslibs import (
2122
Timedelta,
2223
Timestamp,
@@ -227,8 +228,10 @@ def stringify(value):
227228
elif kind in ("timedelta64", "timedelta"):
228229
if isinstance(conv_val, str):
229230
conv_val = Timedelta(conv_val)
230-
else:
231+
elif lib.is_integer(conv_val) or lib.is_float(conv_val):
231232
conv_val = Timedelta(conv_val, unit="s")
233+
else:
234+
conv_val = Timedelta(conv_val)
232235
conv_val = conv_val.as_unit("ns")._value
233236
return TermValue(int(conv_val), conv_val, kind)
234237
elif meta == "category":

pandas/core/resample.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2642,7 +2642,7 @@ def _adjust_bin_edges(
26422642
edges_dti = binner.tz_localize(None)
26432643
edges_dti = (
26442644
edges_dti
2645-
+ Timedelta(days=1, unit=edges_dti.unit).as_unit(edges_dti.unit)
2645+
+ Timedelta(days=1).as_unit(edges_dti.unit)
26462646
- Timedelta(1, unit=edges_dti.unit).as_unit(edges_dti.unit)
26472647
)
26482648
bin_edges = edges_dti.tz_localize(binner.tz).asi8

pandas/core/tools/datetimes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,10 @@ def _adjust_to_origin(arg, origin, unit):
599599

600600
# we are going to offset back to unix / epoch time
601601
try:
602-
offset = Timestamp(origin, unit=unit)
602+
if lib.is_integer(origin) or lib.is_float(origin):
603+
offset = Timestamp(origin, unit=unit)
604+
else:
605+
offset = Timestamp(origin)
603606
except OutOfBoundsDatetime as err:
604607
raise OutOfBoundsDatetime(f"origin {origin} is Out of Bounds") from err
605608
except ValueError as err:

pandas/tests/scalar/timedelta/test_constructors.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,15 @@ def test_construct_from_td64_with_unit():
193193
# results, and in non-overflow cases is irrelevant GH#46827
194194
obj = np.timedelta64(123456789000000000, "h")
195195

196+
msg = "The 'unit' keyword is only used when the Timedelta input is"
197+
196198
with pytest.raises(OutOfBoundsTimedelta, match="123456789000000000 hours"):
197-
Timedelta(obj, unit="ps")
199+
with tm.assert_produces_warning(UserWarning, match=msg):
200+
Timedelta(obj, unit="ps")
198201

199202
with pytest.raises(OutOfBoundsTimedelta, match="123456789000000000 hours"):
200-
Timedelta(obj, unit="ns")
203+
with tm.assert_produces_warning(UserWarning, match=msg):
204+
Timedelta(obj, unit="ns")
201205

202206
with pytest.raises(OutOfBoundsTimedelta, match="123456789000000000 hours"):
203207
Timedelta(obj)
@@ -633,6 +637,9 @@ def test_timedelta_pass_td_and_kwargs_raises():
633637
Timedelta(td, days=2)
634638

635639

640+
@pytest.mark.filterwarnings(
641+
"ignore:The 'unit' keyword is only used when the Timedelta input:UserWarning"
642+
)
636643
@pytest.mark.parametrize(
637644
"constructor, value, unit",
638645
[

pandas/tests/scalar/timedelta/test_timedelta.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_mul_preserves_reso(self, td, unit):
8383

8484
def test_cmp_cross_reso(self, td):
8585
# numpy gets this wrong because of silent overflow
86-
other = Timedelta(days=106751, unit="ns")
86+
other = Timedelta(days=106751)
8787
assert other < td
8888
assert td > other
8989
assert not other == td

pandas/tests/scalar/timestamp/test_constructors.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,9 @@ def test_timestamp_nano_range(nano):
10761076

10771077
def test_non_nano_value():
10781078
# https://github.com/pandas-dev/pandas/issues/49076
1079-
result = Timestamp("1800-01-01", unit="s").value
1079+
msg = "The 'unit' keyword is only used when"
1080+
with tm.assert_produces_warning(UserWarning, match=msg):
1081+
result = Timestamp("1800-01-01", unit="s").value
10801082
# `.value` shows nanoseconds, even though unit is 's'
10811083
assert result == -5364662400000000000
10821084

0 commit comments

Comments
 (0)