diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 731406394ed46..eeabda282e85d 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -412,6 +412,7 @@ Numeric Conversion ^^^^^^^^^^ +- Bug in :class:`Series` constructor responsible for bad datetime to str dtype conversions in ``read_csv``. (:issue:`57512`) - Bug in :meth:`DataFrame.astype` not casting ``values`` for Arrow-based dictionary dtype correctly (:issue:`58479`) - Bug in :meth:`DataFrame.update` bool dtype being converted to object (:issue:`55509`) - Bug in :meth:`Series.astype` might modify read-only array inplace when casting to a string dtype (:issue:`57212`) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index 83373cb4b1d9f..6cc70c91707c1 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -758,7 +758,8 @@ cpdef ndarray[object] ensure_string_array( # dtype check to exclude DataFrame # GH#41409 TODO: not a great place for this out = arr.astype(str).astype(object) - out[arr.isna()] = na_value + if convert_na_value: + out[arr.isna()] = na_value return out arr = arr.to_numpy(dtype=object) elif not util.is_array(arr): diff --git a/pandas/core/construction.py b/pandas/core/construction.py index f01d8822241c9..7c49b97a2b115 100644 --- a/pandas/core/construction.py +++ b/pandas/core/construction.py @@ -799,6 +799,7 @@ def _try_cast( shape = arr.shape if arr.ndim > 1: arr = arr.ravel() + arr = ensure_wrapped_if_datetimelike(arr) else: shape = (len(arr),) return lib.ensure_string_array(arr, convert_na_value=False, copy=copy).reshape( diff --git a/pandas/tests/series/test_constructors.py b/pandas/tests/series/test_constructors.py index 3f9d5bbe806bb..2700e3964bdc4 100644 --- a/pandas/tests/series/test_constructors.py +++ b/pandas/tests/series/test_constructors.py @@ -79,6 +79,23 @@ def test_infer_with_date_and_datetime(self): expected = Index(vals, dtype=object) tm.assert_index_equal(idx, expected) + @pytest.mark.parametrize("dtype", ["M8[s]", "M8[ms]", "M8[us]", "M8[ns]"]) + def test_constructor_str_object_dtypes_dt64_array(self, dtype): + # GH 57512 + dt_arr = np.array( + [ + "2024-01-03T00:00:00.000000000", + "2024-01-01T00:00:00.000000000", + ], + dtype=dtype, + ) + result = Series(Series(dt_arr, dtype=str), dtype=dtype) + expected = Series(dt_arr, dtype=dtype) + tm.assert_series_equal(result, expected) + + result = Series(Series(dt_arr, dtype=object), dtype=dtype) + tm.assert_series_equal(result, expected) + def test_unparsable_strings_with_dt64_dtype(self): # pre-2.0 these would be silently ignored and come back with object dtype vals = ["aa"]