Skip to content

Commit 8813faf

Browse files
authored
API: Timedelta constructor from keywords give microseconds (#63216)
1 parent a4393db commit 8813faf

File tree

13 files changed

+78
-40
lines changed

13 files changed

+78
-40
lines changed

pandas/_libs/tslibs/timedeltas.pyx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2114,7 +2114,7 @@ class Timedelta(_Timedelta):
21142114
int(ns)
21152115
+ int(us * 1_000)
21162116
+ int(ms * 1_000_000)
2117-
+ seconds
2117+
+ seconds, "ns"
21182118
)
21192119
except OverflowError as err:
21202120
# GH#55503
@@ -2124,6 +2124,13 @@ class Timedelta(_Timedelta):
21242124
)
21252125
raise OutOfBoundsTimedelta(msg) from err
21262126

2127+
if (
2128+
"nanoseconds" not in kwargs
2129+
and cnp.get_timedelta64_value(value) % 1000 == 0
2130+
):
2131+
# If possible, give a microsecond unit
2132+
value = value.astype("m8[us]")
2133+
21272134
disallow_ambiguous_unit(unit)
21282135

21292136
cdef:

pandas/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ def rand_series_with_duplicate_datetimeindex() -> Series:
938938
Timestamp("2011-01-01", tz="US/Eastern").as_unit("s"),
939939
DatetimeTZDtype(unit="s", tz="US/Eastern"),
940940
),
941-
(Timedelta(seconds=500), "timedelta64[ns]"),
941+
(Timedelta(seconds=500), "timedelta64[us]"),
942942
]
943943
)
944944
def ea_scalar_and_dtype(request):

pandas/tests/arithmetic/test_numeric.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,8 @@ def test_div_td64arr(self, left, box_cls):
223223
@pytest.mark.parametrize(
224224
"scalar_td",
225225
[
226-
Timedelta(days=1),
227-
Timedelta(days=1).to_timedelta64(),
226+
Timedelta(days=1).as_unit("ns"),
227+
Timedelta(days=1).as_unit("ns").to_timedelta64(),
228228
Timedelta(days=1).to_pytimedelta(),
229229
Timedelta(days=1).to_timedelta64().astype("timedelta64[s]"),
230230
Timedelta(days=1).to_timedelta64().astype("timedelta64[ms]"),
@@ -235,7 +235,9 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box_with_array):
235235
# GH#19333
236236
box = box_with_array
237237
index = numeric_idx
238-
expected = TimedeltaIndex([Timedelta(days=n) for n in range(len(index))])
238+
expected = TimedeltaIndex(
239+
[Timedelta(days=n) for n in range(len(index))], dtype="m8[ns]"
240+
)
239241
if isinstance(scalar_td, np.timedelta64):
240242
dtype = scalar_td.dtype
241243
expected = expected.astype(dtype)
@@ -254,9 +256,9 @@ def test_numeric_arr_mul_tdscalar(self, scalar_td, numeric_idx, box_with_array):
254256
@pytest.mark.parametrize(
255257
"scalar_td",
256258
[
257-
Timedelta(days=1),
258-
Timedelta(days=1).to_timedelta64(),
259-
Timedelta(days=1).to_pytimedelta(),
259+
Timedelta(days=1).as_unit("ns"),
260+
Timedelta(days=1).as_unit("ns").to_timedelta64(),
261+
Timedelta(days=1).as_unit("ns").to_pytimedelta(),
260262
],
261263
ids=lambda x: type(x).__name__,
262264
)

pandas/tests/arithmetic/test_timedelta64.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,8 +1255,14 @@ def test_td64arr_add_sub_tdi(self, box_with_array, names):
12551255

12561256
tdi = TimedeltaIndex(["0 days", "1 day"], name=names[1])
12571257
tdi = np.array(tdi) if box in [tm.to_array, pd.array] else tdi
1258-
ser = Series([Timedelta(hours=3), Timedelta(hours=4)], name=names[0])
1259-
expected = Series([Timedelta(hours=3), Timedelta(days=1, hours=4)], name=exname)
1258+
ser = Series(
1259+
[Timedelta(hours=3), Timedelta(hours=4)], name=names[0], dtype="m8[ns]"
1260+
)
1261+
expected = Series(
1262+
[Timedelta(hours=3), Timedelta(days=1, hours=4)],
1263+
name=exname,
1264+
dtype="m8[ns]",
1265+
)
12601266

12611267
ser = tm.box_expected(ser, box)
12621268
expected = tm.box_expected(expected, box)
@@ -1270,7 +1276,9 @@ def test_td64arr_add_sub_tdi(self, box_with_array, names):
12701276
assert_dtype(result, "timedelta64[ns]")
12711277

12721278
expected = Series(
1273-
[Timedelta(hours=-3), Timedelta(days=1, hours=-4)], name=exname
1279+
[Timedelta(hours=-3), Timedelta(days=1, hours=-4)],
1280+
name=exname,
1281+
dtype="m8[ns]",
12741282
)
12751283
expected = tm.box_expected(expected, box)
12761284

@@ -1666,7 +1674,7 @@ def test_td64arr_mul_masked(self, dtype, box_with_array):
16661674
other = Series(np.arange(5), dtype=dtype)
16671675
other = tm.box_expected(other, box_with_array)
16681676

1669-
expected = Series([Timedelta(hours=n**2) for n in range(5)])
1677+
expected = Series([Timedelta(hours=n**2) for n in range(5)], dtype="m8[ns]")
16701678
expected = tm.box_expected(expected, box_with_array)
16711679
if dtype == "int64[pyarrow]":
16721680
expected = expected.astype("duration[ns][pyarrow]")

pandas/tests/arrays/timedeltas/test_reductions.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ def test_sum_2d_skipna_false(self):
109109
assert result is pd.NaT
110110

111111
result = tda.sum(axis=0, skipna=False)
112-
expected = pd.TimedeltaIndex([Timedelta(seconds=12), pd.NaT])._values
112+
expected = pd.TimedeltaIndex(
113+
[Timedelta(seconds=12), pd.NaT], dtype="m8[ns]"
114+
)._values
113115
tm.assert_timedelta_array_equal(result, expected)
114116

115117
result = tda.sum(axis=1, skipna=False)
@@ -119,7 +121,8 @@ def test_sum_2d_skipna_false(self):
119121
Timedelta(seconds=5),
120122
Timedelta(seconds=9),
121123
pd.NaT,
122-
]
124+
],
125+
dtype="m8[ns]",
123126
)._values
124127
tm.assert_timedelta_array_equal(result, expected)
125128

pandas/tests/base/test_value_counts.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,15 +359,15 @@ def test_value_counts_object_inference_deprecated():
359359
+ [Timestamp("2016-01-02")]
360360
+ [Timestamp("2016-01-01") + Timedelta(days=i) for i in range(1, 5)]
361361
),
362-
DatetimeIndex(pd.date_range("2016-01-01", periods=5, freq="D", unit="ns")),
362+
DatetimeIndex(pd.date_range("2016-01-01", periods=5, freq="D", unit="us")),
363363
],
364364
[
365365
TimedeltaIndex(
366366
[Timedelta(hours=i) for i in range(1)]
367367
+ [Timedelta(hours=1)]
368368
+ [Timedelta(hours=i) for i in range(1, 5)],
369369
),
370-
TimedeltaIndex(pd.timedelta_range(Timedelta(0), periods=5, freq="h")),
370+
TimedeltaIndex(pd.timedelta_range(Timedelta(hours=0), periods=5, freq="h")),
371371
],
372372
[
373373
DatetimeIndex(

pandas/tests/indexes/datetimes/test_arithmetic.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ def test_sub_datetime_preserves_freq_across_dst(self):
5555
Timedelta(days=1),
5656
Timedelta(days=2),
5757
Timedelta(days=2, hours=23),
58-
]
58+
],
59+
dtype="m8[ns]",
5960
)
6061
tm.assert_index_equal(res, expected)
6162
assert res.freq == expected.freq

pandas/tests/indexes/timedeltas/test_constructors.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ def test_float64_ns_rounded(self):
104104
def test_float64_unit_conversion(self):
105105
# GH#23539
106106
tdi = to_timedelta([1.5, 2.25], unit="D")
107-
expected = TimedeltaIndex([Timedelta(days=1.5), Timedelta(days=2.25)])
107+
expected = TimedeltaIndex(
108+
[Timedelta(days=1.5), Timedelta(days=2.25)], dtype="m8[ns]"
109+
)
108110
tm.assert_index_equal(tdi, expected)
109111

110112
def test_construction_base_constructor(self):

pandas/tests/scalar/timedelta/methods/test_as_unit.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,29 @@ class TestAsUnit:
1010
def test_as_unit(self):
1111
td = Timedelta(days=1)
1212

13-
assert td.as_unit("ns") is td
13+
assert td.as_unit("us") is td
1414

15-
res = td.as_unit("us")
16-
assert res._value == td._value // 1000
17-
assert res._creso == NpyDatetimeUnit.NPY_FR_us.value
15+
res = td.as_unit("ns")
16+
assert res._value == td._value * 1000
17+
assert res._creso == NpyDatetimeUnit.NPY_FR_ns.value
1818

19-
rt = res.as_unit("ns")
19+
rt = res.as_unit("us")
2020
assert rt._value == td._value
2121
assert rt._creso == td._creso
2222

2323
res = td.as_unit("ms")
24-
assert res._value == td._value // 1_000_000
24+
assert res._value == td._value // 1_000
2525
assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value
2626

27-
rt = res.as_unit("ns")
27+
rt = res.as_unit("us")
2828
assert rt._value == td._value
2929
assert rt._creso == td._creso
3030

3131
res = td.as_unit("s")
32-
assert res._value == td._value // 1_000_000_000
32+
assert res._value == td._value // 1_000_000
3333
assert res._creso == NpyDatetimeUnit.NPY_FR_s.value
3434

35-
rt = res.as_unit("ns")
35+
rt = res.as_unit("us")
3636
assert rt._value == td._value
3737
assert rt._creso == td._creso
3838

pandas/tests/scalar/timedelta/test_arithmetic.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -818,11 +818,11 @@ def test_mod_numeric(self):
818818
assert isinstance(result, Timedelta)
819819
assert result == Timedelta(0)
820820

821-
result = td % 1e12
821+
result = td % 1e9
822822
assert isinstance(result, Timedelta)
823823
assert result == Timedelta(minutes=3, seconds=20)
824824

825-
result = td % int(1e12)
825+
result = td % int(1e9)
826826
assert isinstance(result, Timedelta)
827827
assert result == Timedelta(minutes=3, seconds=20)
828828

@@ -876,8 +876,8 @@ def test_divmod_numeric(self):
876876
# GH#19365
877877
td = Timedelta(days=2, hours=6)
878878

879-
result = divmod(td, 53 * 3600 * 1e9)
880-
assert result[0] == Timedelta(1, unit="ns")
879+
result = divmod(td, 53 * 3600 * 1e6)
880+
assert result[0] == Timedelta(1, unit="us").as_unit("us")
881881
assert isinstance(result[1], Timedelta)
882882
assert result[1] == Timedelta(hours=1)
883883

0 commit comments

Comments
 (0)