CLN/BUG: Consolidate Index.astype and fix tz aware bugs
State: closed

- [X] closes #18704
- [X] closes #18951
- [X] tests added / passed
- [X] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [X] whatsnew entry

Only behavioral changes:
 - Allowed `.astype(str)` on `TimedeltaIndex` and `PeriodIndex`, which previously raised.
    - Couldn't see a reason why it shouldn't be supported. 
 - Fixed issues related to tz-aware conversion in #18951
 - `RangeIndex.astype('int64')` now remains a `RangeIndex`
    - Previously returned a `Int64Index`

Labels:
name: Dtype Conversions
description: Unexpected or buggy dtype conversions
name: Clean

Comments:
# [Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18937?src=pr&el=h1) Report
> Merging [#18937](https://codecov.io/gh/pandas-dev/pandas/pull/18937?src=pr&el=desc) into [master](https://codecov.io/gh/pandas-dev/pandas/commit/a18d7259e385732540392aab2532fa09b168207e?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##           master   #18937      +/-   ##
==========================================
- Coverage   91.59%   91.59%   -0.01%     
==========================================
  Files         150      150              
  Lines       48964    48939      -25     
==========================================
- Hits        44850    44826      -24     
+ Misses       4114     4113       -1
```

| Flag | Coverage Δ | |
|---|---|---|
| #multiple | `89.95% <100%> (-0.01%)` | :arrow_down: |
| #single | `41.16% <51.11%> (+0.02%)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/pandas-dev/pandas/pull/18937?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pandas/core/indexes/datetimes.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9kYXRldGltZXMucHk=) | `95.57% <100%> (-0.05%)` | :arrow_down: |
| [pandas/core/indexes/interval.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9pbnRlcnZhbC5weQ==) | `93.81% <100%> (-0.08%)` | :arrow_down: |
| [pandas/core/indexes/base.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9iYXNlLnB5) | `96.45% <100%> (+0.01%)` | :arrow_up: |
| [pandas/core/indexes/datetimelike.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9kYXRldGltZWxpa2UucHk=) | `97.19% <100%> (+0.06%)` | :arrow_up: |
| [pandas/core/indexes/numeric.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9udW1lcmljLnB5) | `97.28% <100%> (-0.09%)` | :arrow_down: |
| [pandas/core/indexes/period.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy9wZXJpb2QucHk=) | `93% <100%> (+0.06%)` | :arrow_up: |
| [pandas/core/indexes/timedeltas.py](https://codecov.io/gh/pandas-dev/pandas/pull/18937/diff?src=pr&el=tree#diff-cGFuZGFzL2NvcmUvaW5kZXhlcy90aW1lZGVsdGFzLnB5) | `91.08% <100%> (-0.18%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pandas-dev/pandas/pull/18937?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/18937?src=pr&el=footer). Last update [a18d725...d7c7b9d](https://codecov.io/gh/pandas-dev/pandas/pull/18937?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

lgtm. ex @sinhrks comment. ping when resolved.
Hello @jschendel! Thanks for updating the PR.

























Cheers ! There are no PEP8 issues in this Pull Request. :beers: 

##### Comment last updated on December 27, 2017 at 04:17 Hours UTC
Made the change suggested by @sinhrks, and fixed #18951 at the same time, since it was closely tied to code I was changing without any other dependencies.

Bringing `is_dtype_equal(self.dtype, dtype)` check down to `base.py` appears to have slightly changed the behavior of `RangeIndex`.  Previous `RangeIndex.astype('int64')` returned an `Int64Index`, but with the change it now remains a `RangeIndex`.  This seems fine to me, but not 100% sure.

Bringing `is_dtype_equal(self.dtype, dtype)` check down to `base.py` _should_ also allow for further cleaning of `IntervalIndex.astype`, but there are some larger issues there that don't allow it to work right now.  Specifically, `IntervalDtype(*) == 'interval'` returns `False`, unlike `CategoricalDtype`, which breaks things when relying on `is_dtype_equal` and trying `.astype('interval')`.  Casting between subtypes also doesn't work, e.g `IntervalDtype('int64')` to `IntervalDtype('float64')`.  These issues seem independent from the changes being made here, and big enough to require a separate PR.
thanks @jschendel nice patch!

keep em coming!