diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 9f111282473c2..b30751fcefe81 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -1529,16 +1529,10 @@ def try_datetime(v: np.ndarray) -> ArrayLike: # e.g. is not convertible to datetime return v.reshape(shape) else: - if dta.dtype == object or dta.tz is None: - # GH#19671 if we have mixed timezones we may have object-dtype - # here. - # This is reachable bc allow_object=True, means we cast things - # to mixed-tz datetime objects (mostly). Only 1 test - # relies on this behavior, see GH#40111 - # FIXME: conditional reshape is kludgy - return np.asarray(dta).reshape(shape) - # otherwise we have dt64tz - return dta + # GH#19761 we may have mixed timezones, in which cast 'dta' is + # an ndarray[object]. Only 1 test + # relies on this behavior, see GH#40111 + return dta.reshape(shape) def try_timedelta(v: np.ndarray) -> np.ndarray: # safe coerce to timedelta64 diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index 9a7ae39b9f8eb..814fd389bf644 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -57,7 +57,10 @@ algorithms, common as com, ) -from pandas.core.arrays import Categorical +from pandas.core.arrays import ( + Categorical, + DatetimeArray, +) from pandas.core.construction import ( extract_array, sanitize_array, @@ -70,6 +73,10 @@ union_indexes, ) from pandas.core.internals.array_manager import ArrayManager +from pandas.core.internals.blocks import ( + ensure_block_shape, + make_block, +) from pandas.core.internals.managers import ( BlockManager, create_block_manager_from_arrays, @@ -288,13 +295,10 @@ def ndarray_to_mgr( # transpose and separate blocks dvals_list = [maybe_infer_to_datetimelike(row) for row in values] - for n in range(len(dvals_list)): - if isinstance(dvals_list[n], np.ndarray): - dvals_list[n] = dvals_list[n].reshape(1, -1) - - from pandas.core.internals.blocks import make_block + dvals_list = [ensure_block_shape(dval, 2) for dval in dvals_list] # TODO: What about re-joining object columns? + dvals_list = [maybe_squeeze_dt64tz(x) for x in dvals_list] block_values = [ make_block(dvals_list[n], placement=[n], ndim=2) for n in range(len(dvals_list)) @@ -302,13 +306,25 @@ def ndarray_to_mgr( else: datelike_vals = maybe_infer_to_datetimelike(values) + datelike_vals = maybe_squeeze_dt64tz(datelike_vals) block_values = [datelike_vals] else: - block_values = [values] + block_values = [maybe_squeeze_dt64tz(values)] return create_block_manager_from_blocks(block_values, [columns, index]) +def maybe_squeeze_dt64tz(dta: ArrayLike) -> ArrayLike: + """ + If we have a tzaware DatetimeArray with shape (1, N), squeeze to (N,) + """ + # TODO(EA2D): kludge not needed with 2D EAs + if isinstance(dta, DatetimeArray) and dta.ndim == 2 and dta.tz is not None: + assert dta.shape[0] == 1 + dta = dta[0] + return dta + + def dict_to_mgr( data: Dict, index, columns, dtype: Optional[DtypeObj], typ: str ) -> Manager: