Skip to content

Commit 10753c1

Browse files
committed
review edits and fix issue
1 parent 414695d commit 10753c1

File tree

6 files changed

+28
-9
lines changed

6 files changed

+28
-9
lines changed

doc/source/whatsnew/v0.23.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ Conversion
288288
- Bug in :class:`Series` constructor with an int or float list where specifying ``dtype=str``, ``dtype='str'`` or ``dtype='U'`` failed to convert the data elements to strings (:issue:`16605`)
289289
- Bug in :class:`Timestamp` where comparison with an array of ``Timestamp`` objects would result in a ``RecursionError`` (:issue:`15183`)
290290
- Bug in :class:`WeekOfMonth` and class:`Week` where addition and subtraction did not roll correctly (:issue:`18510`,:issue:`18672`,:issue:`18864`)
291+
- Bug in :meth:`DatetimeIndex.astype` when converting between timezone aware dtypes, and converting from timezone aware to naive (:issue:`18951`)
291292

292293

293294
Indexing

pandas/core/indexes/base.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,9 @@ def _to_embed(self, keep_tz=False, dtype=None):
10651065

10661066
@Appender(_index_shared_docs['astype'])
10671067
def astype(self, dtype, copy=True):
1068-
if is_categorical_dtype(dtype):
1068+
if is_dtype_equal(self.dtype, dtype):
1069+
return self.copy() if copy else self
1070+
elif is_categorical_dtype(dtype):
10691071
from .category import CategoricalIndex
10701072
return CategoricalIndex(self.values, name=self.name, dtype=dtype,
10711073
copy=copy)

pandas/core/indexes/datetimelike.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,10 @@ def astype(self, dtype, copy=True):
876876
elif is_integer_dtype(dtype):
877877
return Index(self.values.astype('i8', copy=copy), name=self.name,
878878
dtype='i8')
879-
elif is_float_dtype(dtype) or is_datetime_or_timedelta_dtype(dtype):
879+
elif (is_datetime_or_timedelta_dtype(dtype) and
880+
not is_dtype_equal(self.dtype, dtype)) or is_float_dtype(dtype):
881+
# disallow conversion between datetime/timedelta,
882+
# and conversions for any datetimelike to float
880883
msg = 'Cannot cast {name} to dtype {dtype}'
881884
raise TypeError(msg.format(name=type(self).__name__, dtype=dtype))
882885
return super(DatetimeIndexOpsMixin, self).astype(dtype, copy=copy)

pandas/core/indexes/datetimes.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -905,10 +905,13 @@ def _format_native_types(self, na_rep='NaT', date_format=None, **kwargs):
905905
@Appender(_index_shared_docs['astype'])
906906
def astype(self, dtype, copy=True):
907907
dtype = pandas_dtype(dtype)
908-
if is_datetime64_ns_dtype(dtype):
909-
if self.tz is not None:
910-
return self.tz_convert('UTC').tz_localize(None)
911-
return self.copy() if copy else self
908+
if (is_datetime64_ns_dtype(dtype) and
909+
not is_dtype_equal(dtype, self.dtype)):
910+
# GH 18951: datetime64_ns dtype but not equal means different tz
911+
new_tz = getattr(dtype, 'tz', None)
912+
if getattr(self.dtype, 'tz', None) is None:
913+
return self.tz_localize(new_tz)
914+
return self.tz_convert(new_tz)
912915
elif is_period_dtype(dtype):
913916
return self.to_period(freq=dtype.freq)
914917
return super(DatetimeIndex, self).astype(dtype, copy=copy)

pandas/core/indexes/timedeltas.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,7 @@ def to_pytimedelta(self):
480480
@Appender(_index_shared_docs['astype'])
481481
def astype(self, dtype, copy=True):
482482
dtype = pandas_dtype(dtype)
483-
if is_timedelta64_ns_dtype(dtype):
484-
return self.copy() if copy else self
485-
elif is_timedelta64_dtype(dtype):
483+
if is_timedelta64_dtype(dtype) and not is_timedelta64_ns_dtype(dtype):
486484
# return an index (essentially this is division)
487485
result = self.values.astype(dtype, copy=copy)
488486
if self.hasnans:

pandas/tests/indexes/datetimes/test_astype.py

+12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ def test_astype_with_tz(self):
5757
dtype=object)
5858
tm.assert_series_equal(result, expected)
5959

60+
# GH 18951: tz-aware to tz-aware
61+
idx = date_range('20170101', periods=4, tz='US/Pacific')
62+
result = idx.astype('datetime64[ns, US/Eastern]')
63+
expected = date_range('20170101 03:00:00', periods=4, tz='US/Eastern')
64+
tm.assert_index_equal(result, expected)
65+
66+
# GH 18951: tz-naive to tz-aware
67+
idx = date_range('20170101', periods=4)
68+
result = idx.astype('datetime64[ns, US/Eastern]')
69+
expected = date_range('20170101', periods=4, tz='US/Eastern')
70+
tm.assert_index_equal(result, expected)
71+
6072
def test_astype_str_compat(self):
6173
# GH 13149, GH 13209
6274
# verify that we are returing NaT as a string (and not unicode)

0 commit comments

Comments
 (0)