done
This commit is contained in:
		| @ -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