from datetime import timedelta import numpy as np import pytest from pandas import Timedelta, offsets, to_timedelta 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(): msg = "int too (large|big) to convert" # GH#3374 value = Timedelta("1day").value * 20169940 with pytest.raises(OverflowError, match=msg): Timedelta(value) # xref GH#17637 with pytest.raises(OverflowError, match=msg): Timedelta(7 * 19999, unit="D") with pytest.raises(OverflowError, match=msg): Timedelta(timedelta(days=13 * 19999)) @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)), ], ) def test_iso_constructor(fmt, exp): assert Timedelta(fmt) == exp @pytest.mark.parametrize( "fmt", [ "PPPPPPPPPPPP", "PDTHMS", "P0DT999H999M999S", "P1DT0H0M0.0000000000000S", "P1DT0H0M0.S", ], ) 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 . 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 @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)