diff --git a/doc/source/whatsnew/v2.0.1.rst b/doc/source/whatsnew/v2.0.1.rst index 0122c84ba2a8e..02fdff0e904eb 100644 --- a/doc/source/whatsnew/v2.0.1.rst +++ b/doc/source/whatsnew/v2.0.1.rst @@ -20,7 +20,7 @@ Fixed regressions Bug fixes ~~~~~~~~~ -- +- Bug in :class:`Series` constructor when passing ``timedelta64`` dtype with non-nanosecond unit would not respect the unit (:issue:`48312`, :issue:`52457`) .. --------------------------------------------------------------------------- .. _whatsnew_201.other: diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 7731bb499cd21..237a5680eeab5 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -213,10 +213,12 @@ def _simple_new( # type: ignore[override] @classmethod def _from_sequence(cls, data, *, dtype=None, copy: bool = False) -> Self: + unit = None if dtype: dtype = _validate_td64_dtype(dtype) + unit = np.datetime_data(dtype)[0] - data, inferred_freq = sequence_to_td64ns(data, copy=copy, unit=None) + data, inferred_freq = sequence_to_td64ns(data, copy=copy, unit=unit) freq, _ = dtl.validate_inferred_freq(None, inferred_freq, False) freq = cast("Tick | None", freq) diff --git a/pandas/tests/indexing/test_scalar.py b/pandas/tests/indexing/test_scalar.py index 1cb8c4f808fbd..57ee46d4d06f5 100644 --- a/pandas/tests/indexing/test_scalar.py +++ b/pandas/tests/indexing/test_scalar.py @@ -90,7 +90,10 @@ def test_at_iat_coercion(self): Timestamp("2014-02-02"), ], [ - Series(["1 days", "2 days"], dtype="timedelta64[ns]"), + Series( + [86_400_000_000_000, 2 * 86_400_000_000_000], + dtype="timedelta64[ns]", + ), Timedelta("2 days"), ], ], diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py index d3cc3239da482..a02efdfeccd46 100644 --- a/pandas/tests/series/test_constructors.py +++ b/pandas/tests/series/test_constructors.py @@ -52,14 +52,15 @@ class TestSeriesConstructors: - def test_from_ints_with_non_nano_dt64_dtype(self, index_or_series): + @pytest.mark.parametrize("dtype", ["m8", "m8"]) + def test_from_ints_with_non_nano_dt64_dtype(self, index_or_series, dtype): values = np.arange(10) - res = index_or_series(values, dtype="M8[s]") - expected = index_or_series(values.astype("M8[s]")) + res = index_or_series(values, dtype=f"{dtype}[s]") + expected = index_or_series(values.astype(f"{dtype}[s]")) tm.assert_equal(res, expected) - res = index_or_series(list(values), dtype="M8[s]") + res = index_or_series(list(values), dtype=f"{dtype}[s]") tm.assert_equal(res, expected) def test_from_na_value_and_interval_of_datetime_dtype(self): @@ -1525,12 +1526,7 @@ def test_constructor_dtype_timedelta64(self): td.astype("int32") # this is an invalid casting - msg = "|".join( - [ - "Could not convert object to NumPy timedelta", - "Could not convert 'foo' to NumPy timedelta", - ] - ) + msg = "unit must not be specified if the input contains a str" with pytest.raises(ValueError, match=msg): Series([timedelta(days=1), "foo"], dtype="m8[ns]") @@ -1958,21 +1954,6 @@ def test_constructor_dtype_timedelta_ns_s(self): expected = Series([1000000, 200000, 3000000], dtype="timedelta64[s]") tm.assert_series_equal(result, expected) - @pytest.mark.xfail( - reason="Not clear what the correct expected behavior should be with " - "integers now that we support non-nano. ATM (2022-10-08) we treat ints " - "as nanoseconds, then cast to the requested dtype. xref #48312" - ) - def test_constructor_dtype_timedelta_ns_s_astype_int64(self): - # GH#35465 - result = Series([1000000, 200000, 3000000], dtype="timedelta64[ns]").astype( - "int64" - ) - expected = Series([1000000, 200000, 3000000], dtype="timedelta64[s]").astype( - "int64" - ) - tm.assert_series_equal(result, expected) - @pytest.mark.filterwarnings( "ignore:elementwise comparison failed:DeprecationWarning" ) @@ -2096,7 +2077,7 @@ def test_constructor_no_pandas_array(self, using_array_manager): @td.skip_array_manager_invalid_test def test_from_array(self): - result = Series(pd.array(["1H", "2H"], dtype="timedelta64[ns]")) + result = Series(pd.array([1, 2], dtype="timedelta64[ns]")) assert result._mgr.blocks[0].is_extension is False result = Series(pd.array(["2015"], dtype="datetime64[ns]")) @@ -2104,7 +2085,7 @@ def test_from_array(self): @td.skip_array_manager_invalid_test def test_from_list_dtype(self): - result = Series(["1H", "2H"], dtype="timedelta64[ns]") + result = Series([1, 2], dtype="timedelta64[ns]") assert result._mgr.blocks[0].is_extension is False result = Series(["2015"], dtype="datetime64[ns]")