Skip to content

Commit 17f84af

Browse files
committed
Merge pull request #6398 from jreback/index_coerce
API: validate conversions of datetimeindex with tz, and fixup to_series() to handle (GH6032)
2 parents 20b35fb + fd35ad7 commit 17f84af

File tree

6 files changed

+82
-5
lines changed

6 files changed

+82
-5
lines changed

doc/source/api.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -1176,7 +1176,7 @@ Conversion
11761176
DatetimeIndex.to_datetime
11771177
DatetimeIndex.to_period
11781178
DatetimeIndex.to_pydatetime
1179-
1179+
DatetimeIndex.to_series
11801180

11811181
GroupBy
11821182
-------

pandas/core/frame.py

+2
Original file line numberDiff line numberDiff line change
@@ -2033,6 +2033,8 @@ def _sanitize_column(self, key, value):
20332033
value = com._asarray_tuplesafe(value)
20342034
elif isinstance(value, PeriodIndex):
20352035
value = value.asobject
2036+
elif isinstance(value, DatetimeIndex):
2037+
value = value._to_embed(keep_tz=True).copy()
20362038
elif value.ndim == 2:
20372039
value = value.copy().T
20382040
else:

pandas/core/index.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -266,13 +266,28 @@ def copy(self, names=None, name=None, dtype=None, deep=False):
266266
new_index = new_index.astype(dtype)
267267
return new_index
268268

269-
def to_series(self):
269+
def to_series(self, keep_tz=False):
270270
"""
271-
return a series with both index and values equal to the index keys
271+
Create a Series with both index and values equal to the index keys
272272
useful with map for returning an indexer based on an index
273+
274+
Parameters
275+
----------
276+
keep_tz : optional, defaults False.
277+
applies only to a DatetimeIndex
278+
279+
Returns
280+
-------
281+
Series : dtype will be based on the type of the Index values.
273282
"""
283+
274284
import pandas as pd
275-
return pd.Series(self.values, index=self, name=self.name)
285+
values = self._to_embed(keep_tz)
286+
return pd.Series(values, index=self, name=self.name)
287+
288+
def _to_embed(self, keep_tz=False):
289+
""" return an array repr of this object, potentially casting to object """
290+
return self.values
276291

277292
def astype(self, dtype):
278293
return Index(self.values.astype(dtype), name=self.name,

pandas/core/series.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ def __init__(self, data=None, index=None, dtype=None, name=None,
162162
# need to copy to avoid aliasing issues
163163
if name is None:
164164
name = data.name
165-
data = data.values
165+
166+
data = data._to_embed(keep_tz=True)
166167
copy = True
167168
elif isinstance(data, pa.Array):
168169
pass

pandas/tests/test_frame.py

+27
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,33 @@ def test_set_index_cast_datetimeindex(self):
20922092
idf = df.set_index('A')
20932093
tm.assert_isinstance(idf.index, DatetimeIndex)
20942094

2095+
# don't cast a DatetimeIndex WITH a tz, leave as object
2096+
# GH 6032
2097+
i = pd.DatetimeIndex(pd.tseries.tools.to_datetime(['2013-1-1 13:00','2013-1-2 14:00'], errors="raise")).tz_localize('US/Pacific')
2098+
df = DataFrame(np.random.randn(2,1),columns=['A'])
2099+
2100+
expected = Series(i)
2101+
self.assertTrue(expected.dtype == object)
2102+
self.assertTrue(i.equals(expected.values.values))
2103+
2104+
df['B'] = i
2105+
result = df['B']
2106+
assert_series_equal(result, expected)
2107+
2108+
result = i.to_series(keep_tz=True)
2109+
assert_series_equal(result.reset_index(drop=True), expected)
2110+
2111+
df['C'] = i.to_series().reset_index(drop=True)
2112+
result = df['C']
2113+
comp = DatetimeIndex(expected.values).copy()
2114+
comp.tz = None
2115+
self.assert_numpy_array_equal(result.values, comp.values)
2116+
2117+
# list of datetimes with a tz
2118+
df['D'] = i.to_pydatetime()
2119+
result = df['D']
2120+
assert_series_equal(result, expected)
2121+
20952122
def test_set_index_multiindexcolumns(self):
20962123
columns = MultiIndex.from_tuples([('foo', 1), ('foo', 2), ('bar', 1)])
20972124
df = DataFrame(np.random.randn(3, 3), columns=columns)

pandas/tseries/index.py

+32
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,38 @@ def _get_time_micros(self):
721721
values = self._local_timestamps()
722722
return tslib.get_time_micros(values)
723723

724+
def to_series(self, keep_tz=False):
725+
"""
726+
Create a Series with both index and values equal to the index keys
727+
useful with map for returning an indexer based on an index
728+
729+
Parameters
730+
----------
731+
keep_tz : optional, defaults False.
732+
return the data keeping the timezone.
733+
734+
If keep_tz is True:
735+
736+
If the timezone is not set or is UTC, the resulting
737+
Series will have a datetime64[ns] dtype.
738+
Otherwise the Series will have an object dtype.
739+
740+
If keep_tz is False:
741+
742+
Series will have a datetime64[ns] dtype.
743+
744+
Returns
745+
-------
746+
Series
747+
"""
748+
return super(DatetimeIndex, self).to_series(keep_tz=keep_tz)
749+
750+
def _to_embed(self, keep_tz=False):
751+
""" return an array repr of this object, potentially casting to object """
752+
if keep_tz and self.tz is not None and str(self.tz) != 'UTC':
753+
return self.asobject
754+
return self.values
755+
724756
@property
725757
def asobject(self):
726758
"""

0 commit comments

Comments
 (0)