BUG: Issues with DatetimeTZ values in where and combine_first (#21469 + #21546)
State: closed

- [ ] closes #21469
- [ ] closes #21546
- [ ] tests added / passed
- [ ] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [ ] whatsnew entry

CC: @jreback. Replacement for PR #21544; fixes for #21469 (`Series.combine_first` fails on tz values input) and #21546 (`where` fails on tz values input). Series.combine_first now delegates to `where` for the bulk of its operations.

Labels:
name: Bug
name: Indexing
description: Related to indexing on series/frames, not to indexes themselves
name: Timezones
description: Timezone data dtype
name: MultiIndex

Comments:
One note: in the old code, combining first a datetime-valued Series with a string-valued Series would return a datetime-valued Series:
```
ser = pd.Series(pd.date_range('20110101', '20110102'))
mask = np.array([True, False])
ser.where(mask).combine_first(pd.Series(['20120101', '20120202']))
# result: 
# 0   2011-01-01
# 1   2012-02-02
# dtype: datetime64[ns]
```

There was a unit test to this effect, so I kept the behavior.

However, combining a datetime-valued Series with an int-valued Series did not promote:
```
ser = pd.Series(pd.date_range('20110101', '20110102'))  
mask = np.array([True, False])                          
ser.where(mask).combine_first(pd.Series([1, 2]))        
# result:
# 0    2011-01-01 00:00:00
# 1                      2
# dtype: object
```
There was no unit test to this effect, however, and it seems inconsistent with the string-promoting behavior above.

A side effect of my current implementation is that now combining first a datetime-valued Series with an int-valued Series now generates a datetime index:
```
ser = pd.Series(pd.date_range('20110101', '20110102'))  
mask = np.array([True, False])                          
ser.where(mask).combine_first(pd.Series([1, 2]))        
# result: 
# 0   2011-01-01 00:00:00.000000000
# 1   1970-01-01 00:00:00.000000002
# dtype: datetime64[ns]
```

Arguably I think combine_first shouldn't be in the business of type promotion at all in either the string or integer case-- I'd just leave it as object. 

Thoughts? Should we:
 * promote on both strings and ints 
 * promote on strings but not on ints
 * leave combining datetimes with either strings or ints as object dtype?
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21660?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@823478c`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/pandas-dev/pandas/pull/21660/graphs/tree.svg?width=650&height=150&src=pr&token=eZ4WkYLtcO)](https://codecov.io/gh/pandas-dev/pandas/pull/21660?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master   #21660   +/-   ##
=========================================
  Coverage          ?    91.9%           
=========================================
  Files             ?      154           
  Lines             ?    49651           
  Branches          ?        0           
=========================================
  Hits              ?    45633           
  Misses            ?     4018           
  Partials          ?        0
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `90.28% <100%> (?)` | |
| #single | `41.9% <20%> (?)` | |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/21660?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/internals.py](https://codecov.io/gh/pandas-dev/pandas/pull/21660/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW50ZXJuYWxzLnB5) | `95.59% <100%> (ø)` | |
| [pandas/core/series.py](https://codecov.io/gh/pandas-dev/pandas/pull/21660/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvc2VyaWVzLnB5) | `94.2% <100%> (ø)` | |
| [pandas/core/common.py](https://codecov.io/gh/pandas-dev/pandas/pull/21660/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvY29tbW9uLnB5) | `92.19% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21660?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/21660?src=pr&el=footer). Last update [823478c...c97b951](https://codecov.io/gh/pandas-dev/pandas/pull/21660?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

thanks @Liam3851 

nice patch! keep em coming!