diff --git a/pandas/core/common.py b/pandas/core/common.py index 1de8269c9a0c6..ec516d9d80023 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -410,19 +410,6 @@ def _apply_if_callable(maybe_callable, obj, **kwargs): return maybe_callable -def _where_compat(mask, arr1, arr2): - if arr1.dtype == _NS_DTYPE and arr2.dtype == _NS_DTYPE: - new_vals = np.where(mask, arr1.view('i8'), arr2.view('i8')) - return new_vals.view(_NS_DTYPE) - - if arr1.dtype == _NS_DTYPE: - arr1 = tslib.ints_to_pydatetime(arr1.view('i8')) - if arr2.dtype == _NS_DTYPE: - arr2 = tslib.ints_to_pydatetime(arr2.view('i8')) - - return np.where(mask, arr1, arr2) - - def _dict_compat(d): """ Helper function to convert datetimelike-keyed dicts to Timestamp-keyed dict diff --git a/pandas/core/series.py b/pandas/core/series.py index 0450f28087f66..801a8ddeb67f7 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -29,13 +29,16 @@ is_hashable, is_iterator, is_dict_like, + is_dtype_equal, is_scalar, _is_unorderable_exception, _ensure_platform_int, - pandas_dtype) + pandas_dtype, + needs_i8_conversion) from pandas.core.dtypes.generic import ( ABCSparseArray, ABCDataFrame, ABCIndexClass) from pandas.core.dtypes.cast import ( + find_common_type, maybe_downcast_to_dtype, maybe_upcast, infer_dtype_from_scalar, maybe_convert_platform, maybe_cast_to_datetime, maybe_castable, @@ -2304,7 +2307,24 @@ def combine_first(self, other): other = other.reindex(new_index, copy=False) # TODO: do we need name? name = ops.get_op_result_name(self, other) # noqa - rs_vals = com._where_compat(isna(this), other._values, this._values) + if not is_dtype_equal(this.dtype, other.dtype): + new_dtype = find_common_type([this.dtype, other.dtype]) + if not is_dtype_equal(this.dtype, new_dtype): + this = this.astype(new_dtype) + if not is_dtype_equal(other.dtype, new_dtype): + other = other.astype(new_dtype) + + if needs_i8_conversion(this.dtype): + mask = isna(this) + this_values = this.values.view('i8') + other_values = other.values.view('i8') + else: + this_values = this.values + other_values = other.values + mask = isna(this_values) + + rs_vals = np.where(mask, other_values, this_values) + rs_vals = maybe_downcast_to_dtype(rs_vals, this.dtype) return self._constructor(rs_vals, index=new_index).__finalize__(self) def update(self, other): diff --git a/pandas/tests/series/test_combine_concat.py b/pandas/tests/series/test_combine_concat.py index f35cce6ac9d71..d3e4720a756f1 100644 --- a/pandas/tests/series/test_combine_concat.py +++ b/pandas/tests/series/test_combine_concat.py @@ -170,6 +170,19 @@ def get_result_type(dtype, dtype2): ]).dtype assert result.kind == expected + def test_combine_first_dt_tz_values(self): + dts1 = pd.date_range('20150101', '20150105', tz='America/New_York') + df1 = pd.DataFrame({'date': dts1}) + dts2 = pd.date_range('20160514', '20160518', tz='America/New_York') + df2 = pd.DataFrame({'date': dts2}, index=range(3, 8)) + result = df1.date.combine_first(df2.date) + exp_vals = pd.DatetimeIndex(['20150101', '20150102', '20150103', + '20150104', '20150105', '20160516', + '20160517', '20160518'], + tz='America/New_York') + exp = pd.Series(exp_vals, name='date') + assert_series_equal(exp, result) + def test_concat_empty_series_dtypes(self): # booleans