forked from Alsan/Post_finder
venv
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,80 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas.errors import OutOfBoundsTimedelta
|
||||
|
||||
from pandas import Timedelta
|
||||
|
||||
|
||||
class TestAsUnit:
|
||||
def test_as_unit(self):
|
||||
td = Timedelta(days=1)
|
||||
|
||||
assert td.as_unit("ns") is td
|
||||
|
||||
res = td.as_unit("us")
|
||||
assert res._value == td._value // 1000
|
||||
assert res._creso == NpyDatetimeUnit.NPY_FR_us.value
|
||||
|
||||
rt = res.as_unit("ns")
|
||||
assert rt._value == td._value
|
||||
assert rt._creso == td._creso
|
||||
|
||||
res = td.as_unit("ms")
|
||||
assert res._value == td._value // 1_000_000
|
||||
assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
|
||||
rt = res.as_unit("ns")
|
||||
assert rt._value == td._value
|
||||
assert rt._creso == td._creso
|
||||
|
||||
res = td.as_unit("s")
|
||||
assert res._value == td._value // 1_000_000_000
|
||||
assert res._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
|
||||
rt = res.as_unit("ns")
|
||||
assert rt._value == td._value
|
||||
assert rt._creso == td._creso
|
||||
|
||||
def test_as_unit_overflows(self):
|
||||
# microsecond that would be just out of bounds for nano
|
||||
us = 9223372800000000
|
||||
td = Timedelta._from_value_and_reso(us, NpyDatetimeUnit.NPY_FR_us.value)
|
||||
|
||||
msg = "Cannot cast 106752 days 00:00:00 to unit='ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td.as_unit("ns")
|
||||
|
||||
res = td.as_unit("ms")
|
||||
assert res._value == us // 1000
|
||||
assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
|
||||
def test_as_unit_rounding(self):
|
||||
td = Timedelta(microseconds=1500)
|
||||
res = td.as_unit("ms")
|
||||
|
||||
expected = Timedelta(milliseconds=1)
|
||||
assert res == expected
|
||||
|
||||
assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
assert res._value == 1
|
||||
|
||||
with pytest.raises(ValueError, match="Cannot losslessly convert units"):
|
||||
td.as_unit("ms", round_ok=False)
|
||||
|
||||
def test_as_unit_non_nano(self):
|
||||
# case where we are going neither to nor from nano
|
||||
td = Timedelta(days=1).as_unit("ms")
|
||||
assert td.days == 1
|
||||
assert td._value == 86_400_000
|
||||
assert td.components.days == 1
|
||||
assert td._d == 1
|
||||
assert td.total_seconds() == 86400
|
||||
|
||||
res = td.as_unit("us")
|
||||
assert res._value == 86_400_000_000
|
||||
assert res.components.days == 1
|
||||
assert res.components.hours == 0
|
||||
assert res._d == 1
|
||||
assert res._h == 0
|
||||
assert res.total_seconds() == 86400
|
@ -0,0 +1,187 @@
|
||||
from hypothesis import (
|
||||
given,
|
||||
strategies as st,
|
||||
)
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs import lib
|
||||
from pandas._libs.tslibs import iNaT
|
||||
from pandas.errors import OutOfBoundsTimedelta
|
||||
|
||||
from pandas import Timedelta
|
||||
|
||||
|
||||
class TestTimedeltaRound:
|
||||
@pytest.mark.parametrize(
|
||||
"freq,s1,s2",
|
||||
[
|
||||
# This first case has s1, s2 being the same as t1,t2 below
|
||||
(
|
||||
"ns",
|
||||
Timedelta("1 days 02:34:56.789123456"),
|
||||
Timedelta("-1 days 02:34:56.789123456"),
|
||||
),
|
||||
(
|
||||
"us",
|
||||
Timedelta("1 days 02:34:56.789123000"),
|
||||
Timedelta("-1 days 02:34:56.789123000"),
|
||||
),
|
||||
(
|
||||
"ms",
|
||||
Timedelta("1 days 02:34:56.789000000"),
|
||||
Timedelta("-1 days 02:34:56.789000000"),
|
||||
),
|
||||
("s", Timedelta("1 days 02:34:57"), Timedelta("-1 days 02:34:57")),
|
||||
("2s", Timedelta("1 days 02:34:56"), Timedelta("-1 days 02:34:56")),
|
||||
("5s", Timedelta("1 days 02:34:55"), Timedelta("-1 days 02:34:55")),
|
||||
("min", Timedelta("1 days 02:35:00"), Timedelta("-1 days 02:35:00")),
|
||||
("12min", Timedelta("1 days 02:36:00"), Timedelta("-1 days 02:36:00")),
|
||||
("h", Timedelta("1 days 03:00:00"), Timedelta("-1 days 03:00:00")),
|
||||
("d", Timedelta("1 days"), Timedelta("-1 days")),
|
||||
],
|
||||
)
|
||||
def test_round(self, freq, s1, s2):
|
||||
t1 = Timedelta("1 days 02:34:56.789123456")
|
||||
t2 = Timedelta("-1 days 02:34:56.789123456")
|
||||
|
||||
r1 = t1.round(freq)
|
||||
assert r1 == s1
|
||||
r2 = t2.round(freq)
|
||||
assert r2 == s2
|
||||
|
||||
def test_round_invalid(self):
|
||||
t1 = Timedelta("1 days 02:34:56.789123456")
|
||||
|
||||
for freq, msg in [
|
||||
("YE", "<YearEnd: month=12> is a non-fixed frequency"),
|
||||
("ME", "<MonthEnd> is a non-fixed frequency"),
|
||||
("foobar", "Invalid frequency: foobar"),
|
||||
]:
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
t1.round(freq)
|
||||
|
||||
@pytest.mark.skip_ubsan
|
||||
def test_round_implementation_bounds(self):
|
||||
# See also: analogous test for Timestamp
|
||||
# GH#38964
|
||||
result = Timedelta.min.ceil("s")
|
||||
expected = Timedelta.min + Timedelta(seconds=1) - Timedelta(145224193)
|
||||
assert result == expected
|
||||
|
||||
result = Timedelta.max.floor("s")
|
||||
expected = Timedelta.max - Timedelta(854775807)
|
||||
assert result == expected
|
||||
|
||||
msg = (
|
||||
r"Cannot round -106752 days \+00:12:43.145224193 to freq=s without overflow"
|
||||
)
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta.min.floor("s")
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta.min.round("s")
|
||||
|
||||
msg = "Cannot round 106751 days 23:47:16.854775807 to freq=s without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta.max.ceil("s")
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta.max.round("s")
|
||||
|
||||
@pytest.mark.skip_ubsan
|
||||
@given(val=st.integers(min_value=iNaT + 1, max_value=lib.i8max))
|
||||
@pytest.mark.parametrize(
|
||||
"method", [Timedelta.round, Timedelta.floor, Timedelta.ceil]
|
||||
)
|
||||
def test_round_sanity(self, val, method):
|
||||
cls = Timedelta
|
||||
err_cls = OutOfBoundsTimedelta
|
||||
|
||||
val = np.int64(val)
|
||||
td = cls(val)
|
||||
|
||||
def checker(ts, nanos, unit):
|
||||
# First check that we do raise in cases where we should
|
||||
if nanos == 1:
|
||||
pass
|
||||
else:
|
||||
div, mod = divmod(ts._value, nanos)
|
||||
diff = int(nanos - mod)
|
||||
lb = ts._value - mod
|
||||
assert lb <= ts._value # i.e. no overflows with python ints
|
||||
ub = ts._value + diff
|
||||
assert ub > ts._value # i.e. no overflows with python ints
|
||||
|
||||
msg = "without overflow"
|
||||
if mod == 0:
|
||||
# We should never be raising in this
|
||||
pass
|
||||
elif method is cls.ceil:
|
||||
if ub > cls.max._value:
|
||||
with pytest.raises(err_cls, match=msg):
|
||||
method(ts, unit)
|
||||
return
|
||||
elif method is cls.floor:
|
||||
if lb < cls.min._value:
|
||||
with pytest.raises(err_cls, match=msg):
|
||||
method(ts, unit)
|
||||
return
|
||||
elif mod >= diff:
|
||||
if ub > cls.max._value:
|
||||
with pytest.raises(err_cls, match=msg):
|
||||
method(ts, unit)
|
||||
return
|
||||
elif lb < cls.min._value:
|
||||
with pytest.raises(err_cls, match=msg):
|
||||
method(ts, unit)
|
||||
return
|
||||
|
||||
res = method(ts, unit)
|
||||
|
||||
td = res - ts
|
||||
diff = abs(td._value)
|
||||
assert diff < nanos
|
||||
assert res._value % nanos == 0
|
||||
|
||||
if method is cls.round:
|
||||
assert diff <= nanos / 2
|
||||
elif method is cls.floor:
|
||||
assert res <= ts
|
||||
elif method is cls.ceil:
|
||||
assert res >= ts
|
||||
|
||||
nanos = 1
|
||||
checker(td, nanos, "ns")
|
||||
|
||||
nanos = 1000
|
||||
checker(td, nanos, "us")
|
||||
|
||||
nanos = 1_000_000
|
||||
checker(td, nanos, "ms")
|
||||
|
||||
nanos = 1_000_000_000
|
||||
checker(td, nanos, "s")
|
||||
|
||||
nanos = 60 * 1_000_000_000
|
||||
checker(td, nanos, "min")
|
||||
|
||||
nanos = 60 * 60 * 1_000_000_000
|
||||
checker(td, nanos, "h")
|
||||
|
||||
nanos = 24 * 60 * 60 * 1_000_000_000
|
||||
checker(td, nanos, "D")
|
||||
|
||||
@pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"])
|
||||
def test_round_non_nano(self, unit):
|
||||
td = Timedelta("1 days 02:34:57").as_unit(unit)
|
||||
|
||||
res = td.round("min")
|
||||
assert res == Timedelta("1 days 02:35:00")
|
||||
assert res._creso == td._creso
|
||||
|
||||
res = td.floor("min")
|
||||
assert res == Timedelta("1 days 02:34:00")
|
||||
assert res._creso == td._creso
|
||||
|
||||
res = td.ceil("min")
|
||||
assert res == Timedelta("1 days 02:35:00")
|
||||
assert res._creso == td._creso
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,698 @@
|
||||
from datetime import timedelta
|
||||
from itertools import product
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import OutOfBoundsTimedelta
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
|
||||
from pandas import (
|
||||
Index,
|
||||
NaT,
|
||||
Timedelta,
|
||||
TimedeltaIndex,
|
||||
offsets,
|
||||
to_timedelta,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
class TestTimedeltaConstructorUnitKeyword:
|
||||
@pytest.mark.parametrize("unit", ["Y", "y", "M"])
|
||||
def test_unit_m_y_raises(self, unit):
|
||||
msg = "Units 'M', 'Y', and 'y' are no longer supported"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta(10, unit)
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
to_timedelta(10, unit)
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
to_timedelta([1, 2], unit)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"unit,unit_depr",
|
||||
[
|
||||
("h", "H"),
|
||||
("min", "T"),
|
||||
("s", "S"),
|
||||
("ms", "L"),
|
||||
("ns", "N"),
|
||||
("us", "U"),
|
||||
],
|
||||
)
|
||||
def test_units_H_T_S_L_N_U_deprecated(self, unit, unit_depr):
|
||||
# GH#52536
|
||||
msg = f"'{unit_depr}' is deprecated and will be removed in a future version."
|
||||
|
||||
expected = Timedelta(1, unit=unit)
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
result = Timedelta(1, unit=unit_depr)
|
||||
tm.assert_equal(result, expected)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"unit, np_unit",
|
||||
[(value, "W") for value in ["W", "w"]]
|
||||
+ [(value, "D") for value in ["D", "d", "days", "day", "Days", "Day"]]
|
||||
+ [
|
||||
(value, "m")
|
||||
for value in [
|
||||
"m",
|
||||
"minute",
|
||||
"min",
|
||||
"minutes",
|
||||
"Minute",
|
||||
"Min",
|
||||
"Minutes",
|
||||
]
|
||||
]
|
||||
+ [
|
||||
(value, "s")
|
||||
for value in [
|
||||
"s",
|
||||
"seconds",
|
||||
"sec",
|
||||
"second",
|
||||
"Seconds",
|
||||
"Sec",
|
||||
"Second",
|
||||
]
|
||||
]
|
||||
+ [
|
||||
(value, "ms")
|
||||
for value in [
|
||||
"ms",
|
||||
"milliseconds",
|
||||
"millisecond",
|
||||
"milli",
|
||||
"millis",
|
||||
"MS",
|
||||
"Milliseconds",
|
||||
"Millisecond",
|
||||
"Milli",
|
||||
"Millis",
|
||||
]
|
||||
]
|
||||
+ [
|
||||
(value, "us")
|
||||
for value in [
|
||||
"us",
|
||||
"microseconds",
|
||||
"microsecond",
|
||||
"micro",
|
||||
"micros",
|
||||
"u",
|
||||
"US",
|
||||
"Microseconds",
|
||||
"Microsecond",
|
||||
"Micro",
|
||||
"Micros",
|
||||
"U",
|
||||
]
|
||||
]
|
||||
+ [
|
||||
(value, "ns")
|
||||
for value in [
|
||||
"ns",
|
||||
"nanoseconds",
|
||||
"nanosecond",
|
||||
"nano",
|
||||
"nanos",
|
||||
"n",
|
||||
"NS",
|
||||
"Nanoseconds",
|
||||
"Nanosecond",
|
||||
"Nano",
|
||||
"Nanos",
|
||||
"N",
|
||||
]
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("wrapper", [np.array, list, Index])
|
||||
def test_unit_parser(self, unit, np_unit, wrapper):
|
||||
# validate all units, GH 6855, GH 21762
|
||||
# array-likes
|
||||
expected = TimedeltaIndex(
|
||||
[np.timedelta64(i, np_unit) for i in np.arange(5).tolist()],
|
||||
dtype="m8[ns]",
|
||||
)
|
||||
# TODO(2.0): the desired output dtype may have non-nano resolution
|
||||
msg = f"'{unit}' is deprecated and will be removed in a future version."
|
||||
|
||||
if (unit, np_unit) in (("u", "us"), ("U", "us"), ("n", "ns"), ("N", "ns")):
|
||||
warn = FutureWarning
|
||||
else:
|
||||
warn = FutureWarning
|
||||
msg = "The 'unit' keyword in TimedeltaIndex construction is deprecated"
|
||||
with tm.assert_produces_warning(warn, match=msg):
|
||||
result = to_timedelta(wrapper(range(5)), unit=unit)
|
||||
tm.assert_index_equal(result, expected)
|
||||
result = TimedeltaIndex(wrapper(range(5)), unit=unit)
|
||||
tm.assert_index_equal(result, expected)
|
||||
|
||||
str_repr = [f"{x}{unit}" for x in np.arange(5)]
|
||||
result = to_timedelta(wrapper(str_repr))
|
||||
tm.assert_index_equal(result, expected)
|
||||
result = to_timedelta(wrapper(str_repr))
|
||||
tm.assert_index_equal(result, expected)
|
||||
|
||||
# scalar
|
||||
expected = Timedelta(np.timedelta64(2, np_unit).astype("timedelta64[ns]"))
|
||||
result = to_timedelta(2, unit=unit)
|
||||
assert result == expected
|
||||
result = Timedelta(2, unit=unit)
|
||||
assert result == expected
|
||||
|
||||
result = to_timedelta(f"2{unit}")
|
||||
assert result == expected
|
||||
result = Timedelta(f"2{unit}")
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_construct_from_kwargs_overflow():
|
||||
# GH#55503
|
||||
msg = "seconds=86400000000000000000, milliseconds=0, microseconds=0, nanoseconds=0"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta(days=10**6)
|
||||
msg = "seconds=60000000000000000000, milliseconds=0, microseconds=0, nanoseconds=0"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta(minutes=10**9)
|
||||
|
||||
|
||||
def test_construct_with_weeks_unit_overflow():
|
||||
# GH#47268 don't silently wrap around
|
||||
with pytest.raises(OutOfBoundsTimedelta, match="without overflow"):
|
||||
Timedelta(1000000000000000000, unit="W")
|
||||
|
||||
with pytest.raises(OutOfBoundsTimedelta, match="without overflow"):
|
||||
Timedelta(1000000000000000000.0, unit="W")
|
||||
|
||||
|
||||
def test_construct_from_td64_with_unit():
|
||||
# ignore the unit, as it may cause silently overflows leading to incorrect
|
||||
# results, and in non-overflow cases is irrelevant GH#46827
|
||||
obj = np.timedelta64(123456789000000000, "h")
|
||||
|
||||
with pytest.raises(OutOfBoundsTimedelta, match="123456789000000000 hours"):
|
||||
Timedelta(obj, unit="ps")
|
||||
|
||||
with pytest.raises(OutOfBoundsTimedelta, match="123456789000000000 hours"):
|
||||
Timedelta(obj, unit="ns")
|
||||
|
||||
with pytest.raises(OutOfBoundsTimedelta, match="123456789000000000 hours"):
|
||||
Timedelta(obj)
|
||||
|
||||
|
||||
def test_from_td64_retain_resolution():
|
||||
# case where we retain millisecond resolution
|
||||
obj = np.timedelta64(12345, "ms")
|
||||
|
||||
td = Timedelta(obj)
|
||||
assert td._value == obj.view("i8")
|
||||
assert td._creso == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
|
||||
# Case where we cast to nearest-supported reso
|
||||
obj2 = np.timedelta64(1234, "D")
|
||||
td2 = Timedelta(obj2)
|
||||
assert td2._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
assert td2 == obj2
|
||||
assert td2.days == 1234
|
||||
|
||||
# Case that _would_ overflow if we didn't support non-nano
|
||||
obj3 = np.timedelta64(1000000000000000000, "us")
|
||||
td3 = Timedelta(obj3)
|
||||
assert td3.total_seconds() == 1000000000000
|
||||
assert td3._creso == NpyDatetimeUnit.NPY_FR_us.value
|
||||
|
||||
|
||||
def test_from_pytimedelta_us_reso():
|
||||
# pytimedelta has microsecond resolution, so Timedelta(pytd) inherits that
|
||||
td = timedelta(days=4, minutes=3)
|
||||
result = Timedelta(td)
|
||||
assert result.to_pytimedelta() == td
|
||||
assert result._creso == NpyDatetimeUnit.NPY_FR_us.value
|
||||
|
||||
|
||||
def test_from_tick_reso():
|
||||
tick = offsets.Nano()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_ns.value
|
||||
|
||||
tick = offsets.Micro()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_us.value
|
||||
|
||||
tick = offsets.Milli()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
|
||||
tick = offsets.Second()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
|
||||
# everything above Second gets cast to the closest supported reso: second
|
||||
tick = offsets.Minute()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
|
||||
tick = offsets.Hour()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
|
||||
tick = offsets.Day()
|
||||
assert Timedelta(tick)._creso == NpyDatetimeUnit.NPY_FR_s.value
|
||||
|
||||
|
||||
def test_construction():
|
||||
expected = np.timedelta64(10, "D").astype("m8[ns]").view("i8")
|
||||
assert Timedelta(10, unit="d")._value == expected
|
||||
assert Timedelta(10.0, unit="d")._value == expected
|
||||
assert Timedelta("10 days")._value == expected
|
||||
assert Timedelta(days=10)._value == expected
|
||||
assert Timedelta(days=10.0)._value == expected
|
||||
|
||||
expected += np.timedelta64(10, "s").astype("m8[ns]").view("i8")
|
||||
assert Timedelta("10 days 00:00:10")._value == expected
|
||||
assert Timedelta(days=10, seconds=10)._value == expected
|
||||
assert Timedelta(days=10, milliseconds=10 * 1000)._value == expected
|
||||
assert Timedelta(days=10, microseconds=10 * 1000 * 1000)._value == expected
|
||||
|
||||
# rounding cases
|
||||
assert Timedelta(82739999850000)._value == 82739999850000
|
||||
assert "0 days 22:58:59.999850" in str(Timedelta(82739999850000))
|
||||
assert Timedelta(123072001000000)._value == 123072001000000
|
||||
assert "1 days 10:11:12.001" in str(Timedelta(123072001000000))
|
||||
|
||||
# string conversion with/without leading zero
|
||||
# GH#9570
|
||||
assert Timedelta("0:00:00") == timedelta(hours=0)
|
||||
assert Timedelta("00:00:00") == timedelta(hours=0)
|
||||
assert Timedelta("-1:00:00") == -timedelta(hours=1)
|
||||
assert Timedelta("-01:00:00") == -timedelta(hours=1)
|
||||
|
||||
# more strings & abbrevs
|
||||
# GH#8190
|
||||
assert Timedelta("1 h") == timedelta(hours=1)
|
||||
assert Timedelta("1 hour") == timedelta(hours=1)
|
||||
assert Timedelta("1 hr") == timedelta(hours=1)
|
||||
assert Timedelta("1 hours") == timedelta(hours=1)
|
||||
assert Timedelta("-1 hours") == -timedelta(hours=1)
|
||||
assert Timedelta("1 m") == timedelta(minutes=1)
|
||||
assert Timedelta("1.5 m") == timedelta(seconds=90)
|
||||
assert Timedelta("1 minute") == timedelta(minutes=1)
|
||||
assert Timedelta("1 minutes") == timedelta(minutes=1)
|
||||
assert Timedelta("1 s") == timedelta(seconds=1)
|
||||
assert Timedelta("1 second") == timedelta(seconds=1)
|
||||
assert Timedelta("1 seconds") == timedelta(seconds=1)
|
||||
assert Timedelta("1 ms") == timedelta(milliseconds=1)
|
||||
assert Timedelta("1 milli") == timedelta(milliseconds=1)
|
||||
assert Timedelta("1 millisecond") == timedelta(milliseconds=1)
|
||||
assert Timedelta("1 us") == timedelta(microseconds=1)
|
||||
assert Timedelta("1 µs") == timedelta(microseconds=1)
|
||||
assert Timedelta("1 micros") == timedelta(microseconds=1)
|
||||
assert Timedelta("1 microsecond") == timedelta(microseconds=1)
|
||||
assert Timedelta("1.5 microsecond") == Timedelta("00:00:00.000001500")
|
||||
assert Timedelta("1 ns") == Timedelta("00:00:00.000000001")
|
||||
assert Timedelta("1 nano") == Timedelta("00:00:00.000000001")
|
||||
assert Timedelta("1 nanosecond") == Timedelta("00:00:00.000000001")
|
||||
|
||||
# combos
|
||||
assert Timedelta("10 days 1 hour") == timedelta(days=10, hours=1)
|
||||
assert Timedelta("10 days 1 h") == timedelta(days=10, hours=1)
|
||||
assert Timedelta("10 days 1 h 1m 1s") == timedelta(
|
||||
days=10, hours=1, minutes=1, seconds=1
|
||||
)
|
||||
assert Timedelta("-10 days 1 h 1m 1s") == -timedelta(
|
||||
days=10, hours=1, minutes=1, seconds=1
|
||||
)
|
||||
assert Timedelta("-10 days 1 h 1m 1s") == -timedelta(
|
||||
days=10, hours=1, minutes=1, seconds=1
|
||||
)
|
||||
assert Timedelta("-10 days 1 h 1m 1s 3us") == -timedelta(
|
||||
days=10, hours=1, minutes=1, seconds=1, microseconds=3
|
||||
)
|
||||
assert Timedelta("-10 days 1 h 1.5m 1s 3us") == -timedelta(
|
||||
days=10, hours=1, minutes=1, seconds=31, microseconds=3
|
||||
)
|
||||
|
||||
# Currently invalid as it has a - on the hh:mm:dd part
|
||||
# (only allowed on the days)
|
||||
msg = "only leading negative signs are allowed"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("-10 days -1 h 1.5m 1s 3us")
|
||||
|
||||
# only leading neg signs are allowed
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("10 days -1 h 1.5m 1s 3us")
|
||||
|
||||
# no units specified
|
||||
msg = "no units specified"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("3.1415")
|
||||
|
||||
# invalid construction
|
||||
msg = "cannot construct a Timedelta"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta()
|
||||
|
||||
msg = "unit abbreviation w/o a number"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("foo")
|
||||
|
||||
msg = (
|
||||
"cannot construct a Timedelta from "
|
||||
"the passed arguments, allowed keywords are "
|
||||
)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta(day=10)
|
||||
|
||||
# floats
|
||||
expected = np.timedelta64(10, "s").astype("m8[ns]").view("i8") + np.timedelta64(
|
||||
500, "ms"
|
||||
).astype("m8[ns]").view("i8")
|
||||
assert Timedelta(10.5, unit="s")._value == expected
|
||||
|
||||
# offset
|
||||
assert to_timedelta(offsets.Hour(2)) == Timedelta(hours=2)
|
||||
assert Timedelta(offsets.Hour(2)) == Timedelta(hours=2)
|
||||
assert Timedelta(offsets.Second(2)) == Timedelta(seconds=2)
|
||||
|
||||
# GH#11995: unicode
|
||||
expected = Timedelta("1h")
|
||||
result = Timedelta("1h")
|
||||
assert result == expected
|
||||
assert to_timedelta(offsets.Hour(2)) == Timedelta("0 days, 02:00:00")
|
||||
|
||||
msg = "unit abbreviation w/o a number"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("foo bar")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"item",
|
||||
list(
|
||||
{
|
||||
"days": "D",
|
||||
"seconds": "s",
|
||||
"microseconds": "us",
|
||||
"milliseconds": "ms",
|
||||
"minutes": "m",
|
||||
"hours": "h",
|
||||
"weeks": "W",
|
||||
}.items()
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"npdtype", [np.int64, np.int32, np.int16, np.float64, np.float32, np.float16]
|
||||
)
|
||||
def test_td_construction_with_np_dtypes(npdtype, item):
|
||||
# GH#8757: test construction with np dtypes
|
||||
pykwarg, npkwarg = item
|
||||
expected = np.timedelta64(1, npkwarg).astype("m8[ns]").view("i8")
|
||||
assert Timedelta(**{pykwarg: npdtype(1)})._value == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"val",
|
||||
[
|
||||
"1s",
|
||||
"-1s",
|
||||
"1us",
|
||||
"-1us",
|
||||
"1 day",
|
||||
"-1 day",
|
||||
"-23:59:59.999999",
|
||||
"-1 days +23:59:59.999999",
|
||||
"-1ns",
|
||||
"1ns",
|
||||
"-23:59:59.999999999",
|
||||
],
|
||||
)
|
||||
def test_td_from_repr_roundtrip(val):
|
||||
# round-trip both for string and value
|
||||
td = Timedelta(val)
|
||||
assert Timedelta(td._value) == td
|
||||
|
||||
assert Timedelta(str(td)) == td
|
||||
assert Timedelta(td._repr_base(format="all")) == td
|
||||
assert Timedelta(td._repr_base()) == td
|
||||
|
||||
|
||||
def test_overflow_on_construction():
|
||||
# GH#3374
|
||||
value = Timedelta("1day")._value * 20169940
|
||||
msg = "Cannot cast 1742682816000000000000 from ns to 'ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta(value)
|
||||
|
||||
# xref GH#17637
|
||||
msg = "Cannot cast 139993 from D to 'ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta(7 * 19999, unit="D")
|
||||
|
||||
# used to overflow before non-ns support
|
||||
td = Timedelta(timedelta(days=13 * 19999))
|
||||
assert td._creso == NpyDatetimeUnit.NPY_FR_us.value
|
||||
assert td.days == 13 * 19999
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"val, unit",
|
||||
[
|
||||
(15251, "W"), # 1
|
||||
(106752, "D"), # change from previous:
|
||||
(2562048, "h"), # 0 hours
|
||||
(153722868, "m"), # 13 minutes
|
||||
(9223372037, "s"), # 44 seconds
|
||||
],
|
||||
)
|
||||
def test_construction_out_of_bounds_td64ns(val, unit):
|
||||
# TODO: parametrize over units just above/below the implementation bounds
|
||||
# once GH#38964 is resolved
|
||||
|
||||
# Timedelta.max is just under 106752 days
|
||||
td64 = np.timedelta64(val, unit)
|
||||
assert td64.astype("m8[ns]").view("i8") < 0 # i.e. naive astype will be wrong
|
||||
|
||||
td = Timedelta(td64)
|
||||
if unit != "M":
|
||||
# with unit="M" the conversion to "s" is poorly defined
|
||||
# (and numpy issues DeprecationWarning)
|
||||
assert td.asm8 == td64
|
||||
assert td.asm8.dtype == "m8[s]"
|
||||
msg = r"Cannot cast 1067\d\d days .* to unit='ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td.as_unit("ns")
|
||||
|
||||
# But just back in bounds and we are OK
|
||||
assert Timedelta(td64 - 1) == td64 - 1
|
||||
|
||||
td64 *= -1
|
||||
assert td64.astype("m8[ns]").view("i8") > 0 # i.e. naive astype will be wrong
|
||||
|
||||
td2 = Timedelta(td64)
|
||||
msg = r"Cannot cast -1067\d\d days .* to unit='ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td2.as_unit("ns")
|
||||
|
||||
# But just back in bounds and we are OK
|
||||
assert Timedelta(td64 + 1) == td64 + 1
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"val, unit",
|
||||
[
|
||||
(15251 * 10**9, "W"),
|
||||
(106752 * 10**9, "D"),
|
||||
(2562048 * 10**9, "h"),
|
||||
(153722868 * 10**9, "m"),
|
||||
],
|
||||
)
|
||||
def test_construction_out_of_bounds_td64s(val, unit):
|
||||
td64 = np.timedelta64(val, unit)
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=str(td64)):
|
||||
Timedelta(td64)
|
||||
|
||||
# But just back in bounds and we are OK
|
||||
assert Timedelta(td64 - 10**9) == td64 - 10**9
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"fmt,exp",
|
||||
[
|
||||
(
|
||||
"P6DT0H50M3.010010012S",
|
||||
Timedelta(
|
||||
days=6,
|
||||
minutes=50,
|
||||
seconds=3,
|
||||
milliseconds=10,
|
||||
microseconds=10,
|
||||
nanoseconds=12,
|
||||
),
|
||||
),
|
||||
(
|
||||
"P-6DT0H50M3.010010012S",
|
||||
Timedelta(
|
||||
days=-6,
|
||||
minutes=50,
|
||||
seconds=3,
|
||||
milliseconds=10,
|
||||
microseconds=10,
|
||||
nanoseconds=12,
|
||||
),
|
||||
),
|
||||
("P4DT12H30M5S", Timedelta(days=4, hours=12, minutes=30, seconds=5)),
|
||||
("P0DT0H0M0.000000123S", Timedelta(nanoseconds=123)),
|
||||
("P0DT0H0M0.00001S", Timedelta(microseconds=10)),
|
||||
("P0DT0H0M0.001S", Timedelta(milliseconds=1)),
|
||||
("P0DT0H1M0S", Timedelta(minutes=1)),
|
||||
("P1DT25H61M61S", Timedelta(days=1, hours=25, minutes=61, seconds=61)),
|
||||
("PT1S", Timedelta(seconds=1)),
|
||||
("PT0S", Timedelta(seconds=0)),
|
||||
("P1WT0S", Timedelta(days=7, seconds=0)),
|
||||
("P1D", Timedelta(days=1)),
|
||||
("P1DT1H", Timedelta(days=1, hours=1)),
|
||||
("P1W", Timedelta(days=7)),
|
||||
("PT300S", Timedelta(seconds=300)),
|
||||
("P1DT0H0M00000000000S", Timedelta(days=1)),
|
||||
("PT-6H3M", Timedelta(hours=-6, minutes=3)),
|
||||
("-PT6H3M", Timedelta(hours=-6, minutes=-3)),
|
||||
("-PT-6H+3M", Timedelta(hours=6, minutes=-3)),
|
||||
],
|
||||
)
|
||||
def test_iso_constructor(fmt, exp):
|
||||
assert Timedelta(fmt) == exp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"fmt",
|
||||
[
|
||||
"PPPPPPPPPPPP",
|
||||
"PDTHMS",
|
||||
"P0DT999H999M999S",
|
||||
"P1DT0H0M0.0000000000000S",
|
||||
"P1DT0H0M0.S",
|
||||
"P",
|
||||
"-P",
|
||||
],
|
||||
)
|
||||
def test_iso_constructor_raises(fmt):
|
||||
msg = f"Invalid ISO 8601 Duration format - {fmt}"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta(fmt)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"constructed_td, conversion",
|
||||
[
|
||||
(Timedelta(nanoseconds=100), "100ns"),
|
||||
(
|
||||
Timedelta(
|
||||
days=1,
|
||||
hours=1,
|
||||
minutes=1,
|
||||
weeks=1,
|
||||
seconds=1,
|
||||
milliseconds=1,
|
||||
microseconds=1,
|
||||
nanoseconds=1,
|
||||
),
|
||||
694861001001001,
|
||||
),
|
||||
(Timedelta(microseconds=1) + Timedelta(nanoseconds=1), "1us1ns"),
|
||||
(Timedelta(microseconds=1) - Timedelta(nanoseconds=1), "999ns"),
|
||||
(Timedelta(microseconds=1) + 5 * Timedelta(nanoseconds=-2), "990ns"),
|
||||
],
|
||||
)
|
||||
def test_td_constructor_on_nanoseconds(constructed_td, conversion):
|
||||
# GH#9273
|
||||
assert constructed_td == Timedelta(conversion)
|
||||
|
||||
|
||||
def test_td_constructor_value_error():
|
||||
msg = "Invalid type <class 'str'>. Must be int or float."
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
Timedelta(nanoseconds="abc")
|
||||
|
||||
|
||||
def test_timedelta_constructor_identity():
|
||||
# Test for #30543
|
||||
expected = Timedelta(np.timedelta64(1, "s"))
|
||||
result = Timedelta(expected)
|
||||
assert result is expected
|
||||
|
||||
|
||||
def test_timedelta_pass_td_and_kwargs_raises():
|
||||
# don't silently ignore the kwargs GH#48898
|
||||
td = Timedelta(days=1)
|
||||
msg = (
|
||||
"Cannot pass both a Timedelta input and timedelta keyword arguments, "
|
||||
r"got \['days'\]"
|
||||
)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta(td, days=2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"constructor, value, unit, expectation",
|
||||
[
|
||||
(Timedelta, "10s", "ms", (ValueError, "unit must not be specified")),
|
||||
(to_timedelta, "10s", "ms", (ValueError, "unit must not be specified")),
|
||||
(to_timedelta, ["1", 2, 3], "s", (ValueError, "unit must not be specified")),
|
||||
],
|
||||
)
|
||||
def test_string_with_unit(constructor, value, unit, expectation):
|
||||
exp, match = expectation
|
||||
with pytest.raises(exp, match=match):
|
||||
_ = constructor(value, unit=unit)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value",
|
||||
[
|
||||
"".join(elements)
|
||||
for repetition in (1, 2)
|
||||
for elements in product("+-, ", repeat=repetition)
|
||||
],
|
||||
)
|
||||
def test_string_without_numbers(value):
|
||||
# GH39710 Timedelta input string with only symbols and no digits raises an error
|
||||
msg = (
|
||||
"symbols w/o a number"
|
||||
if value != "--"
|
||||
else "only leading negative signs are allowed"
|
||||
)
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta(value)
|
||||
|
||||
|
||||
def test_timedelta_new_npnat():
|
||||
# GH#48898
|
||||
nat = np.timedelta64("NaT", "h")
|
||||
assert Timedelta(nat) is NaT
|
||||
|
||||
|
||||
def test_subclass_respected():
|
||||
# GH#49579
|
||||
class MyCustomTimedelta(Timedelta):
|
||||
pass
|
||||
|
||||
td = MyCustomTimedelta("1 minute")
|
||||
assert isinstance(td, MyCustomTimedelta)
|
||||
|
||||
|
||||
def test_non_nano_value():
|
||||
# https://github.com/pandas-dev/pandas/issues/49076
|
||||
result = Timedelta(10, unit="D").as_unit("s").value
|
||||
# `.value` shows nanoseconds, even though unit is 's'
|
||||
assert result == 864000000000000
|
||||
|
||||
# out-of-nanoseconds-bounds `.value` raises informative message
|
||||
msg = (
|
||||
r"Cannot convert Timedelta to nanoseconds without overflow. "
|
||||
r"Use `.asm8.view\('i8'\)` to cast represent Timedelta in its "
|
||||
r"own unit \(here, s\).$"
|
||||
)
|
||||
td = Timedelta(1_000, "D").as_unit("s") * 1_000
|
||||
with pytest.raises(OverflowError, match=msg):
|
||||
td.value
|
||||
# check that the suggested workaround actually works
|
||||
result = td.asm8.view("i8")
|
||||
assert result == 86400000000
|
@ -0,0 +1,109 @@
|
||||
import pytest
|
||||
|
||||
from pandas import Timedelta
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"td, expected_repr",
|
||||
[
|
||||
(Timedelta(10, unit="d"), "Timedelta('10 days 00:00:00')"),
|
||||
(Timedelta(10, unit="s"), "Timedelta('0 days 00:00:10')"),
|
||||
(Timedelta(10, unit="ms"), "Timedelta('0 days 00:00:00.010000')"),
|
||||
(Timedelta(-10, unit="ms"), "Timedelta('-1 days +23:59:59.990000')"),
|
||||
],
|
||||
)
|
||||
def test_repr(td, expected_repr):
|
||||
assert repr(td) == expected_repr
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"td, expected_iso",
|
||||
[
|
||||
(
|
||||
Timedelta(
|
||||
days=6,
|
||||
minutes=50,
|
||||
seconds=3,
|
||||
milliseconds=10,
|
||||
microseconds=10,
|
||||
nanoseconds=12,
|
||||
),
|
||||
"P6DT0H50M3.010010012S",
|
||||
),
|
||||
(Timedelta(days=4, hours=12, minutes=30, seconds=5), "P4DT12H30M5S"),
|
||||
(Timedelta(nanoseconds=123), "P0DT0H0M0.000000123S"),
|
||||
# trim nano
|
||||
(Timedelta(microseconds=10), "P0DT0H0M0.00001S"),
|
||||
# trim micro
|
||||
(Timedelta(milliseconds=1), "P0DT0H0M0.001S"),
|
||||
# don't strip every 0
|
||||
(Timedelta(minutes=1), "P0DT0H1M0S"),
|
||||
],
|
||||
)
|
||||
def test_isoformat(td, expected_iso):
|
||||
assert td.isoformat() == expected_iso
|
||||
|
||||
|
||||
class TestReprBase:
|
||||
def test_none(self):
|
||||
delta_1d = Timedelta(1, unit="D")
|
||||
delta_0d = Timedelta(0, unit="D")
|
||||
delta_1s = Timedelta(1, unit="s")
|
||||
delta_500ms = Timedelta(500, unit="ms")
|
||||
|
||||
drepr = lambda x: x._repr_base()
|
||||
assert drepr(delta_1d) == "1 days"
|
||||
assert drepr(-delta_1d) == "-1 days"
|
||||
assert drepr(delta_0d) == "0 days"
|
||||
assert drepr(delta_1s) == "0 days 00:00:01"
|
||||
assert drepr(delta_500ms) == "0 days 00:00:00.500000"
|
||||
assert drepr(delta_1d + delta_1s) == "1 days 00:00:01"
|
||||
assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01"
|
||||
assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000"
|
||||
assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000"
|
||||
|
||||
def test_sub_day(self):
|
||||
delta_1d = Timedelta(1, unit="D")
|
||||
delta_0d = Timedelta(0, unit="D")
|
||||
delta_1s = Timedelta(1, unit="s")
|
||||
delta_500ms = Timedelta(500, unit="ms")
|
||||
|
||||
drepr = lambda x: x._repr_base(format="sub_day")
|
||||
assert drepr(delta_1d) == "1 days"
|
||||
assert drepr(-delta_1d) == "-1 days"
|
||||
assert drepr(delta_0d) == "00:00:00"
|
||||
assert drepr(delta_1s) == "00:00:01"
|
||||
assert drepr(delta_500ms) == "00:00:00.500000"
|
||||
assert drepr(delta_1d + delta_1s) == "1 days 00:00:01"
|
||||
assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01"
|
||||
assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000"
|
||||
assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000"
|
||||
|
||||
def test_long(self):
|
||||
delta_1d = Timedelta(1, unit="D")
|
||||
delta_0d = Timedelta(0, unit="D")
|
||||
delta_1s = Timedelta(1, unit="s")
|
||||
delta_500ms = Timedelta(500, unit="ms")
|
||||
|
||||
drepr = lambda x: x._repr_base(format="long")
|
||||
assert drepr(delta_1d) == "1 days 00:00:00"
|
||||
assert drepr(-delta_1d) == "-1 days +00:00:00"
|
||||
assert drepr(delta_0d) == "0 days 00:00:00"
|
||||
assert drepr(delta_1s) == "0 days 00:00:01"
|
||||
assert drepr(delta_500ms) == "0 days 00:00:00.500000"
|
||||
assert drepr(delta_1d + delta_1s) == "1 days 00:00:01"
|
||||
assert drepr(-delta_1d + delta_1s) == "-1 days +00:00:01"
|
||||
assert drepr(delta_1d + delta_500ms) == "1 days 00:00:00.500000"
|
||||
assert drepr(-delta_1d + delta_500ms) == "-1 days +00:00:00.500000"
|
||||
|
||||
def test_all(self):
|
||||
delta_1d = Timedelta(1, unit="D")
|
||||
delta_0d = Timedelta(0, unit="D")
|
||||
delta_1ns = Timedelta(1, unit="ns")
|
||||
|
||||
drepr = lambda x: x._repr_base(format="all")
|
||||
assert drepr(delta_1d) == "1 days 00:00:00.000000000"
|
||||
assert drepr(-delta_1d) == "-1 days +00:00:00.000000000"
|
||||
assert drepr(delta_0d) == "0 days 00:00:00.000000000"
|
||||
assert drepr(delta_1ns) == "0 days 00:00:00.000000001"
|
||||
assert drepr(-delta_1d + delta_1ns) == "-1 days +00:00:00.000000001"
|
@ -0,0 +1,666 @@
|
||||
""" test the scalar Timedelta """
|
||||
from datetime import timedelta
|
||||
import sys
|
||||
|
||||
from hypothesis import (
|
||||
given,
|
||||
strategies as st,
|
||||
)
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs import lib
|
||||
from pandas._libs.tslibs import (
|
||||
NaT,
|
||||
iNaT,
|
||||
)
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas.errors import OutOfBoundsTimedelta
|
||||
|
||||
from pandas import (
|
||||
Timedelta,
|
||||
to_timedelta,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
class TestNonNano:
|
||||
@pytest.fixture(params=["s", "ms", "us"])
|
||||
def unit_str(self, request):
|
||||
return request.param
|
||||
|
||||
@pytest.fixture
|
||||
def unit(self, unit_str):
|
||||
# 7, 8, 9 correspond to second, millisecond, and microsecond, respectively
|
||||
attr = f"NPY_FR_{unit_str}"
|
||||
return getattr(NpyDatetimeUnit, attr).value
|
||||
|
||||
@pytest.fixture
|
||||
def val(self, unit):
|
||||
# microsecond that would be just out of bounds for nano
|
||||
us = 9223372800000000
|
||||
if unit == NpyDatetimeUnit.NPY_FR_us.value:
|
||||
value = us
|
||||
elif unit == NpyDatetimeUnit.NPY_FR_ms.value:
|
||||
value = us // 1000
|
||||
else:
|
||||
value = us // 1_000_000
|
||||
return value
|
||||
|
||||
@pytest.fixture
|
||||
def td(self, unit, val):
|
||||
return Timedelta._from_value_and_reso(val, unit)
|
||||
|
||||
def test_from_value_and_reso(self, unit, val):
|
||||
# Just checking that the fixture is giving us what we asked for
|
||||
td = Timedelta._from_value_and_reso(val, unit)
|
||||
assert td._value == val
|
||||
assert td._creso == unit
|
||||
assert td.days == 106752
|
||||
|
||||
def test_unary_non_nano(self, td, unit):
|
||||
assert abs(td)._creso == unit
|
||||
assert (-td)._creso == unit
|
||||
assert (+td)._creso == unit
|
||||
|
||||
def test_sub_preserves_reso(self, td, unit):
|
||||
res = td - td
|
||||
expected = Timedelta._from_value_and_reso(0, unit)
|
||||
assert res == expected
|
||||
assert res._creso == unit
|
||||
|
||||
def test_mul_preserves_reso(self, td, unit):
|
||||
# The td fixture should always be far from the implementation
|
||||
# bound, so doubling does not risk overflow.
|
||||
res = td * 2
|
||||
assert res._value == td._value * 2
|
||||
assert res._creso == unit
|
||||
|
||||
def test_cmp_cross_reso(self, td):
|
||||
# numpy gets this wrong because of silent overflow
|
||||
other = Timedelta(days=106751, unit="ns")
|
||||
assert other < td
|
||||
assert td > other
|
||||
assert not other == td
|
||||
assert td != other
|
||||
|
||||
def test_to_pytimedelta(self, td):
|
||||
res = td.to_pytimedelta()
|
||||
expected = timedelta(days=106752)
|
||||
assert type(res) is timedelta
|
||||
assert res == expected
|
||||
|
||||
def test_to_timedelta64(self, td, unit):
|
||||
for res in [td.to_timedelta64(), td.to_numpy(), td.asm8]:
|
||||
assert isinstance(res, np.timedelta64)
|
||||
assert res.view("i8") == td._value
|
||||
if unit == NpyDatetimeUnit.NPY_FR_s.value:
|
||||
assert res.dtype == "m8[s]"
|
||||
elif unit == NpyDatetimeUnit.NPY_FR_ms.value:
|
||||
assert res.dtype == "m8[ms]"
|
||||
elif unit == NpyDatetimeUnit.NPY_FR_us.value:
|
||||
assert res.dtype == "m8[us]"
|
||||
|
||||
def test_truediv_timedeltalike(self, td):
|
||||
assert td / td == 1
|
||||
assert (2.5 * td) / td == 2.5
|
||||
|
||||
other = Timedelta(td._value)
|
||||
msg = "Cannot cast 106752 days 00:00:00 to unit='ns' without overflow."
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td / other
|
||||
|
||||
# Timedelta(other.to_pytimedelta()) has microsecond resolution,
|
||||
# so the division doesn't require casting all the way to nanos,
|
||||
# so succeeds
|
||||
res = other.to_pytimedelta() / td
|
||||
expected = other.to_pytimedelta() / td.to_pytimedelta()
|
||||
assert res == expected
|
||||
|
||||
# if there's no overflow, we cast to the higher reso
|
||||
left = Timedelta._from_value_and_reso(50, NpyDatetimeUnit.NPY_FR_us.value)
|
||||
right = Timedelta._from_value_and_reso(50, NpyDatetimeUnit.NPY_FR_ms.value)
|
||||
result = left / right
|
||||
assert result == 0.001
|
||||
|
||||
result = right / left
|
||||
assert result == 1000
|
||||
|
||||
def test_truediv_numeric(self, td):
|
||||
assert td / np.nan is NaT
|
||||
|
||||
res = td / 2
|
||||
assert res._value == td._value / 2
|
||||
assert res._creso == td._creso
|
||||
|
||||
res = td / 2.0
|
||||
assert res._value == td._value / 2
|
||||
assert res._creso == td._creso
|
||||
|
||||
def test_floordiv_timedeltalike(self, td):
|
||||
assert td // td == 1
|
||||
assert (2.5 * td) // td == 2
|
||||
|
||||
other = Timedelta(td._value)
|
||||
msg = "Cannot cast 106752 days 00:00:00 to unit='ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td // other
|
||||
|
||||
# Timedelta(other.to_pytimedelta()) has microsecond resolution,
|
||||
# so the floordiv doesn't require casting all the way to nanos,
|
||||
# so succeeds
|
||||
res = other.to_pytimedelta() // td
|
||||
assert res == 0
|
||||
|
||||
# if there's no overflow, we cast to the higher reso
|
||||
left = Timedelta._from_value_and_reso(50050, NpyDatetimeUnit.NPY_FR_us.value)
|
||||
right = Timedelta._from_value_and_reso(50, NpyDatetimeUnit.NPY_FR_ms.value)
|
||||
result = left // right
|
||||
assert result == 1
|
||||
result = right // left
|
||||
assert result == 0
|
||||
|
||||
def test_floordiv_numeric(self, td):
|
||||
assert td // np.nan is NaT
|
||||
|
||||
res = td // 2
|
||||
assert res._value == td._value // 2
|
||||
assert res._creso == td._creso
|
||||
|
||||
res = td // 2.0
|
||||
assert res._value == td._value // 2
|
||||
assert res._creso == td._creso
|
||||
|
||||
assert td // np.array(np.nan) is NaT
|
||||
|
||||
res = td // np.array(2)
|
||||
assert res._value == td._value // 2
|
||||
assert res._creso == td._creso
|
||||
|
||||
res = td // np.array(2.0)
|
||||
assert res._value == td._value // 2
|
||||
assert res._creso == td._creso
|
||||
|
||||
def test_addsub_mismatched_reso(self, td):
|
||||
# need to cast to since td is out of bounds for ns, so
|
||||
# so we would raise OverflowError without casting
|
||||
other = Timedelta(days=1).as_unit("us")
|
||||
|
||||
# td is out of bounds for ns
|
||||
result = td + other
|
||||
assert result._creso == other._creso
|
||||
assert result.days == td.days + 1
|
||||
|
||||
result = other + td
|
||||
assert result._creso == other._creso
|
||||
assert result.days == td.days + 1
|
||||
|
||||
result = td - other
|
||||
assert result._creso == other._creso
|
||||
assert result.days == td.days - 1
|
||||
|
||||
result = other - td
|
||||
assert result._creso == other._creso
|
||||
assert result.days == 1 - td.days
|
||||
|
||||
other2 = Timedelta(500)
|
||||
msg = "Cannot cast 106752 days 00:00:00 to unit='ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td + other2
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
other2 + td
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
td - other2
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
other2 - td
|
||||
|
||||
def test_min(self, td):
|
||||
assert td.min <= td
|
||||
assert td.min._creso == td._creso
|
||||
assert td.min._value == NaT._value + 1
|
||||
|
||||
def test_max(self, td):
|
||||
assert td.max >= td
|
||||
assert td.max._creso == td._creso
|
||||
assert td.max._value == np.iinfo(np.int64).max
|
||||
|
||||
def test_resolution(self, td):
|
||||
expected = Timedelta._from_value_and_reso(1, td._creso)
|
||||
result = td.resolution
|
||||
assert result == expected
|
||||
assert result._creso == expected._creso
|
||||
|
||||
def test_hash(self) -> None:
|
||||
# GH#54037
|
||||
second_resolution_max = Timedelta(0).as_unit("s").max
|
||||
|
||||
assert hash(second_resolution_max)
|
||||
|
||||
|
||||
def test_timedelta_class_min_max_resolution():
|
||||
# when accessed on the class (as opposed to an instance), we default
|
||||
# to nanoseconds
|
||||
assert Timedelta.min == Timedelta(NaT._value + 1)
|
||||
assert Timedelta.min._creso == NpyDatetimeUnit.NPY_FR_ns.value
|
||||
|
||||
assert Timedelta.max == Timedelta(np.iinfo(np.int64).max)
|
||||
assert Timedelta.max._creso == NpyDatetimeUnit.NPY_FR_ns.value
|
||||
|
||||
assert Timedelta.resolution == Timedelta(1)
|
||||
assert Timedelta.resolution._creso == NpyDatetimeUnit.NPY_FR_ns.value
|
||||
|
||||
|
||||
class TestTimedeltaUnaryOps:
|
||||
def test_invert(self):
|
||||
td = Timedelta(10, unit="d")
|
||||
|
||||
msg = "bad operand type for unary ~"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
~td
|
||||
|
||||
# check this matches pytimedelta and timedelta64
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
~(td.to_pytimedelta())
|
||||
|
||||
umsg = "ufunc 'invert' not supported for the input types"
|
||||
with pytest.raises(TypeError, match=umsg):
|
||||
~(td.to_timedelta64())
|
||||
|
||||
def test_unary_ops(self):
|
||||
td = Timedelta(10, unit="d")
|
||||
|
||||
# __neg__, __pos__
|
||||
assert -td == Timedelta(-10, unit="d")
|
||||
assert -td == Timedelta("-10d")
|
||||
assert +td == Timedelta(10, unit="d")
|
||||
|
||||
# __abs__, __abs__(__neg__)
|
||||
assert abs(td) == td
|
||||
assert abs(-td) == td
|
||||
assert abs(-td) == Timedelta("10d")
|
||||
|
||||
|
||||
class TestTimedeltas:
|
||||
@pytest.mark.parametrize(
|
||||
"unit, value, expected",
|
||||
[
|
||||
("us", 9.999, 9999),
|
||||
("ms", 9.999999, 9999999),
|
||||
("s", 9.999999999, 9999999999),
|
||||
],
|
||||
)
|
||||
def test_rounding_on_int_unit_construction(self, unit, value, expected):
|
||||
# GH 12690
|
||||
result = Timedelta(value, unit=unit)
|
||||
assert result._value == expected
|
||||
result = Timedelta(str(value) + unit)
|
||||
assert result._value == expected
|
||||
|
||||
def test_total_seconds_scalar(self):
|
||||
# see gh-10939
|
||||
rng = Timedelta("1 days, 10:11:12.100123456")
|
||||
expt = 1 * 86400 + 10 * 3600 + 11 * 60 + 12 + 100123456.0 / 1e9
|
||||
tm.assert_almost_equal(rng.total_seconds(), expt)
|
||||
|
||||
rng = Timedelta(np.nan)
|
||||
assert np.isnan(rng.total_seconds())
|
||||
|
||||
def test_conversion(self):
|
||||
for td in [Timedelta(10, unit="d"), Timedelta("1 days, 10:11:12.012345")]:
|
||||
pydt = td.to_pytimedelta()
|
||||
assert td == Timedelta(pydt)
|
||||
assert td == pydt
|
||||
assert isinstance(pydt, timedelta) and not isinstance(pydt, Timedelta)
|
||||
|
||||
assert td == np.timedelta64(td._value, "ns")
|
||||
td64 = td.to_timedelta64()
|
||||
|
||||
assert td64 == np.timedelta64(td._value, "ns")
|
||||
assert td == td64
|
||||
|
||||
assert isinstance(td64, np.timedelta64)
|
||||
|
||||
# this is NOT equal and cannot be roundtripped (because of the nanos)
|
||||
td = Timedelta("1 days, 10:11:12.012345678")
|
||||
assert td != td.to_pytimedelta()
|
||||
|
||||
def test_fields(self):
|
||||
def check(value):
|
||||
# that we are int
|
||||
assert isinstance(value, int)
|
||||
|
||||
# compat to datetime.timedelta
|
||||
rng = to_timedelta("1 days, 10:11:12")
|
||||
assert rng.days == 1
|
||||
assert rng.seconds == 10 * 3600 + 11 * 60 + 12
|
||||
assert rng.microseconds == 0
|
||||
assert rng.nanoseconds == 0
|
||||
|
||||
msg = "'Timedelta' object has no attribute '{}'"
|
||||
with pytest.raises(AttributeError, match=msg.format("hours")):
|
||||
rng.hours
|
||||
with pytest.raises(AttributeError, match=msg.format("minutes")):
|
||||
rng.minutes
|
||||
with pytest.raises(AttributeError, match=msg.format("milliseconds")):
|
||||
rng.milliseconds
|
||||
|
||||
# GH 10050
|
||||
check(rng.days)
|
||||
check(rng.seconds)
|
||||
check(rng.microseconds)
|
||||
check(rng.nanoseconds)
|
||||
|
||||
td = Timedelta("-1 days, 10:11:12")
|
||||
assert abs(td) == Timedelta("13:48:48")
|
||||
assert str(td) == "-1 days +10:11:12"
|
||||
assert -td == Timedelta("0 days 13:48:48")
|
||||
assert -Timedelta("-1 days, 10:11:12")._value == 49728000000000
|
||||
assert Timedelta("-1 days, 10:11:12")._value == -49728000000000
|
||||
|
||||
rng = to_timedelta("-1 days, 10:11:12.100123456")
|
||||
assert rng.days == -1
|
||||
assert rng.seconds == 10 * 3600 + 11 * 60 + 12
|
||||
assert rng.microseconds == 100 * 1000 + 123
|
||||
assert rng.nanoseconds == 456
|
||||
msg = "'Timedelta' object has no attribute '{}'"
|
||||
with pytest.raises(AttributeError, match=msg.format("hours")):
|
||||
rng.hours
|
||||
with pytest.raises(AttributeError, match=msg.format("minutes")):
|
||||
rng.minutes
|
||||
with pytest.raises(AttributeError, match=msg.format("milliseconds")):
|
||||
rng.milliseconds
|
||||
|
||||
# components
|
||||
tup = to_timedelta(-1, "us").components
|
||||
assert tup.days == -1
|
||||
assert tup.hours == 23
|
||||
assert tup.minutes == 59
|
||||
assert tup.seconds == 59
|
||||
assert tup.milliseconds == 999
|
||||
assert tup.microseconds == 999
|
||||
assert tup.nanoseconds == 0
|
||||
|
||||
# GH 10050
|
||||
check(tup.days)
|
||||
check(tup.hours)
|
||||
check(tup.minutes)
|
||||
check(tup.seconds)
|
||||
check(tup.milliseconds)
|
||||
check(tup.microseconds)
|
||||
check(tup.nanoseconds)
|
||||
|
||||
tup = Timedelta("-1 days 1 us").components
|
||||
assert tup.days == -2
|
||||
assert tup.hours == 23
|
||||
assert tup.minutes == 59
|
||||
assert tup.seconds == 59
|
||||
assert tup.milliseconds == 999
|
||||
assert tup.microseconds == 999
|
||||
assert tup.nanoseconds == 0
|
||||
|
||||
# TODO: this is a test of to_timedelta string parsing
|
||||
def test_iso_conversion(self):
|
||||
# GH #21877
|
||||
expected = Timedelta(1, unit="s")
|
||||
assert to_timedelta("P0DT0H0M1S") == expected
|
||||
|
||||
# TODO: this is a test of to_timedelta returning NaT
|
||||
def test_nat_converters(self):
|
||||
result = to_timedelta("nat").to_numpy()
|
||||
assert result.dtype.kind == "M"
|
||||
assert result.astype("int64") == iNaT
|
||||
|
||||
result = to_timedelta("nan").to_numpy()
|
||||
assert result.dtype.kind == "M"
|
||||
assert result.astype("int64") == iNaT
|
||||
|
||||
def test_numeric_conversions(self):
|
||||
assert Timedelta(0) == np.timedelta64(0, "ns")
|
||||
assert Timedelta(10) == np.timedelta64(10, "ns")
|
||||
assert Timedelta(10, unit="ns") == np.timedelta64(10, "ns")
|
||||
|
||||
assert Timedelta(10, unit="us") == np.timedelta64(10, "us")
|
||||
assert Timedelta(10, unit="ms") == np.timedelta64(10, "ms")
|
||||
assert Timedelta(10, unit="s") == np.timedelta64(10, "s")
|
||||
assert Timedelta(10, unit="d") == np.timedelta64(10, "D")
|
||||
|
||||
def test_timedelta_conversions(self):
|
||||
assert Timedelta(timedelta(seconds=1)) == np.timedelta64(1, "s").astype(
|
||||
"m8[ns]"
|
||||
)
|
||||
assert Timedelta(timedelta(microseconds=1)) == np.timedelta64(1, "us").astype(
|
||||
"m8[ns]"
|
||||
)
|
||||
assert Timedelta(timedelta(days=1)) == np.timedelta64(1, "D").astype("m8[ns]")
|
||||
|
||||
def test_to_numpy_alias(self):
|
||||
# GH 24653: alias .to_numpy() for scalars
|
||||
td = Timedelta("10m7s")
|
||||
assert td.to_timedelta64() == td.to_numpy()
|
||||
|
||||
# GH#44460
|
||||
msg = "dtype and copy arguments are ignored"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
td.to_numpy("m8[s]")
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
td.to_numpy(copy=True)
|
||||
|
||||
def test_identity(self):
|
||||
td = Timedelta(10, unit="d")
|
||||
assert isinstance(td, Timedelta)
|
||||
assert isinstance(td, timedelta)
|
||||
|
||||
def test_short_format_converters(self):
|
||||
def conv(v):
|
||||
return v.astype("m8[ns]")
|
||||
|
||||
assert Timedelta("10") == np.timedelta64(10, "ns")
|
||||
assert Timedelta("10ns") == np.timedelta64(10, "ns")
|
||||
assert Timedelta("100") == np.timedelta64(100, "ns")
|
||||
assert Timedelta("100ns") == np.timedelta64(100, "ns")
|
||||
|
||||
assert Timedelta("1000") == np.timedelta64(1000, "ns")
|
||||
assert Timedelta("1000ns") == np.timedelta64(1000, "ns")
|
||||
assert Timedelta("1000NS") == np.timedelta64(1000, "ns")
|
||||
|
||||
assert Timedelta("10us") == np.timedelta64(10000, "ns")
|
||||
assert Timedelta("100us") == np.timedelta64(100000, "ns")
|
||||
assert Timedelta("1000us") == np.timedelta64(1000000, "ns")
|
||||
assert Timedelta("1000Us") == np.timedelta64(1000000, "ns")
|
||||
assert Timedelta("1000uS") == np.timedelta64(1000000, "ns")
|
||||
|
||||
assert Timedelta("1ms") == np.timedelta64(1000000, "ns")
|
||||
assert Timedelta("10ms") == np.timedelta64(10000000, "ns")
|
||||
assert Timedelta("100ms") == np.timedelta64(100000000, "ns")
|
||||
assert Timedelta("1000ms") == np.timedelta64(1000000000, "ns")
|
||||
|
||||
assert Timedelta("-1s") == -np.timedelta64(1000000000, "ns")
|
||||
assert Timedelta("1s") == np.timedelta64(1000000000, "ns")
|
||||
assert Timedelta("10s") == np.timedelta64(10000000000, "ns")
|
||||
assert Timedelta("100s") == np.timedelta64(100000000000, "ns")
|
||||
assert Timedelta("1000s") == np.timedelta64(1000000000000, "ns")
|
||||
|
||||
assert Timedelta("1d") == conv(np.timedelta64(1, "D"))
|
||||
assert Timedelta("-1d") == -conv(np.timedelta64(1, "D"))
|
||||
assert Timedelta("1D") == conv(np.timedelta64(1, "D"))
|
||||
assert Timedelta("10D") == conv(np.timedelta64(10, "D"))
|
||||
assert Timedelta("100D") == conv(np.timedelta64(100, "D"))
|
||||
assert Timedelta("1000D") == conv(np.timedelta64(1000, "D"))
|
||||
assert Timedelta("10000D") == conv(np.timedelta64(10000, "D"))
|
||||
|
||||
# space
|
||||
assert Timedelta(" 10000D ") == conv(np.timedelta64(10000, "D"))
|
||||
assert Timedelta(" - 10000D ") == -conv(np.timedelta64(10000, "D"))
|
||||
|
||||
# invalid
|
||||
msg = "invalid unit abbreviation"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("1foo")
|
||||
msg = "unit abbreviation w/o a number"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("foo")
|
||||
|
||||
def test_full_format_converters(self):
|
||||
def conv(v):
|
||||
return v.astype("m8[ns]")
|
||||
|
||||
d1 = np.timedelta64(1, "D")
|
||||
|
||||
assert Timedelta("1days") == conv(d1)
|
||||
assert Timedelta("1days,") == conv(d1)
|
||||
assert Timedelta("- 1days,") == -conv(d1)
|
||||
|
||||
assert Timedelta("00:00:01") == conv(np.timedelta64(1, "s"))
|
||||
assert Timedelta("06:00:01") == conv(np.timedelta64(6 * 3600 + 1, "s"))
|
||||
assert Timedelta("06:00:01.0") == conv(np.timedelta64(6 * 3600 + 1, "s"))
|
||||
assert Timedelta("06:00:01.01") == conv(
|
||||
np.timedelta64(1000 * (6 * 3600 + 1) + 10, "ms")
|
||||
)
|
||||
|
||||
assert Timedelta("- 1days, 00:00:01") == conv(-d1 + np.timedelta64(1, "s"))
|
||||
assert Timedelta("1days, 06:00:01") == conv(
|
||||
d1 + np.timedelta64(6 * 3600 + 1, "s")
|
||||
)
|
||||
assert Timedelta("1days, 06:00:01.01") == conv(
|
||||
d1 + np.timedelta64(1000 * (6 * 3600 + 1) + 10, "ms")
|
||||
)
|
||||
|
||||
# invalid
|
||||
msg = "have leftover units"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
Timedelta("- 1days, 00")
|
||||
|
||||
def test_pickle(self):
|
||||
v = Timedelta("1 days 10:11:12.0123456")
|
||||
v_p = tm.round_trip_pickle(v)
|
||||
assert v == v_p
|
||||
|
||||
def test_timedelta_hash_equality(self):
|
||||
# GH 11129
|
||||
v = Timedelta(1, "D")
|
||||
td = timedelta(days=1)
|
||||
assert hash(v) == hash(td)
|
||||
|
||||
d = {td: 2}
|
||||
assert d[v] == 2
|
||||
|
||||
tds = [Timedelta(seconds=1) + Timedelta(days=n) for n in range(20)]
|
||||
assert all(hash(td) == hash(td.to_pytimedelta()) for td in tds)
|
||||
|
||||
# python timedeltas drop ns resolution
|
||||
ns_td = Timedelta(1, "ns")
|
||||
assert hash(ns_td) != hash(ns_td.to_pytimedelta())
|
||||
|
||||
@pytest.mark.skip_ubsan
|
||||
@pytest.mark.xfail(
|
||||
reason="pd.Timedelta violates the Python hash invariant (GH#44504).",
|
||||
)
|
||||
@given(
|
||||
st.integers(
|
||||
min_value=(-sys.maxsize - 1) // 500,
|
||||
max_value=sys.maxsize // 500,
|
||||
)
|
||||
)
|
||||
def test_hash_equality_invariance(self, half_microseconds: int) -> None:
|
||||
# GH#44504
|
||||
|
||||
nanoseconds = half_microseconds * 500
|
||||
|
||||
pandas_timedelta = Timedelta(nanoseconds)
|
||||
numpy_timedelta = np.timedelta64(nanoseconds)
|
||||
|
||||
# See: https://docs.python.org/3/glossary.html#term-hashable
|
||||
# Hashable objects which compare equal must have the same hash value.
|
||||
assert pandas_timedelta != numpy_timedelta or hash(pandas_timedelta) == hash(
|
||||
numpy_timedelta
|
||||
)
|
||||
|
||||
def test_implementation_limits(self):
|
||||
min_td = Timedelta(Timedelta.min)
|
||||
max_td = Timedelta(Timedelta.max)
|
||||
|
||||
# GH 12727
|
||||
# timedelta limits correspond to int64 boundaries
|
||||
assert min_td._value == iNaT + 1
|
||||
assert max_td._value == lib.i8max
|
||||
|
||||
# Beyond lower limit, a NAT before the Overflow
|
||||
assert (min_td - Timedelta(1, "ns")) is NaT
|
||||
|
||||
msg = "int too (large|big) to convert"
|
||||
with pytest.raises(OverflowError, match=msg):
|
||||
min_td - Timedelta(2, "ns")
|
||||
|
||||
with pytest.raises(OverflowError, match=msg):
|
||||
max_td + Timedelta(1, "ns")
|
||||
|
||||
# Same tests using the internal nanosecond values
|
||||
td = Timedelta(min_td._value - 1, "ns")
|
||||
assert td is NaT
|
||||
|
||||
msg = "Cannot cast -9223372036854775809 from ns to 'ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta(min_td._value - 2, "ns")
|
||||
|
||||
msg = "Cannot cast 9223372036854775808 from ns to 'ns' without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
Timedelta(max_td._value + 1, "ns")
|
||||
|
||||
def test_total_seconds_precision(self):
|
||||
# GH 19458
|
||||
assert Timedelta("30s").total_seconds() == 30.0
|
||||
assert Timedelta("0").total_seconds() == 0.0
|
||||
assert Timedelta("-2s").total_seconds() == -2.0
|
||||
assert Timedelta("5.324s").total_seconds() == 5.324
|
||||
assert (Timedelta("30s").total_seconds() - 30.0) < 1e-20
|
||||
assert (30.0 - Timedelta("30s").total_seconds()) < 1e-20
|
||||
|
||||
def test_resolution_string(self):
|
||||
assert Timedelta(days=1).resolution_string == "D"
|
||||
assert Timedelta(days=1, hours=6).resolution_string == "h"
|
||||
assert Timedelta(days=1, minutes=6).resolution_string == "min"
|
||||
assert Timedelta(days=1, seconds=6).resolution_string == "s"
|
||||
assert Timedelta(days=1, milliseconds=6).resolution_string == "ms"
|
||||
assert Timedelta(days=1, microseconds=6).resolution_string == "us"
|
||||
assert Timedelta(days=1, nanoseconds=6).resolution_string == "ns"
|
||||
|
||||
def test_resolution_deprecated(self):
|
||||
# GH#21344
|
||||
td = Timedelta(days=4, hours=3)
|
||||
result = td.resolution
|
||||
assert result == Timedelta(nanoseconds=1)
|
||||
|
||||
# Check that the attribute is available on the class, mirroring
|
||||
# the stdlib timedelta behavior
|
||||
result = Timedelta.resolution
|
||||
assert result == Timedelta(nanoseconds=1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"value, expected",
|
||||
[
|
||||
(Timedelta("10s"), True),
|
||||
(Timedelta("-10s"), True),
|
||||
(Timedelta(10, unit="ns"), True),
|
||||
(Timedelta(0, unit="ns"), False),
|
||||
(Timedelta(-10, unit="ns"), True),
|
||||
(Timedelta(None), True),
|
||||
(NaT, True),
|
||||
],
|
||||
)
|
||||
def test_truthiness(value, expected):
|
||||
# https://github.com/pandas-dev/pandas/issues/21484
|
||||
assert bool(value) is expected
|
||||
|
||||
|
||||
def test_timedelta_attribute_precision():
|
||||
# GH 31354
|
||||
td = Timedelta(1552211999999999872, unit="ns")
|
||||
result = td.days * 86400
|
||||
result += td.seconds
|
||||
result *= 1000000
|
||||
result += td.microseconds
|
||||
result *= 1000
|
||||
result += td.nanoseconds
|
||||
expected = td._value
|
||||
assert result == expected
|
Reference in New Issue
Block a user