diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 1ea86254d35..52088090468 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -210,8 +210,9 @@ def _maybe_wrap_data(data): def _possibly_convert_objects(values): """Convert object arrays into datetime64 and timedelta64 according - to the pandas convention. For backwards compat, as of 3.0.0 pandas, - object dtype inputs are cast to strings by `pandas.Series` + to the pandas convention. Object dtype inputs that are inferred to be + strings are returned unchanged. For backwards compat, as of 3.0.0 pandas, + the remaining object dtype inputs are cast to strings by `pandas.Series` but we output them as object dtype with the input metadata preserved as well. @@ -220,8 +221,22 @@ def _possibly_convert_objects(values): * pd.Timestamp * pd.Timedelta """ - as_series = pd.Series(values.ravel(), copy=False) - result = np.asarray(as_series).reshape(values.shape) + inferred = pd.api.types.infer_dtype(values.ravel(), skipna=True) + + if inferred == "string": + return values + elif inferred == "datetime": + result = pd.to_datetime(values.ravel()).to_numpy().reshape(values.shape) + elif inferred == "timedelta": + result = pd.to_timedelta(values.ravel()).to_numpy().reshape(values.shape) + elif inferred in ["datetime64", "timedelta64"]: + # Casting drops unit info for these cases; + # fall back to pd.Series roundtrip, which preserves them. + as_series = pd.Series(values.ravel(), copy=False) + result = np.asarray(as_series).reshape(values.shape) + else: + return values + if not result.flags.writeable: # GH8843, pandas copy-on-write mode creates read-only arrays by default try: diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index c2bc73f70b9..0ebde435697 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -70,6 +70,9 @@ def var(): [ np.array(["a", "bc", "def"], dtype=object), np.array(["2019-01-01", "2019-01-02", "2019-01-03"], dtype="datetime64[ns]"), + np.array([datetime(2000, 1, 1), datetime(2000, 1, 2)], dtype=object), + np.array([timedelta(seconds=1), timedelta(seconds=2)], dtype=object), + np.array([1, "a"], dtype=object), ], ) def test_as_compatible_data_writeable(data):