Skip to content

Commit

Permalink
BUG: DatetimeIndes.insert doesnt preserve name and tz
Browse files Browse the repository at this point in the history
  • Loading branch information
sinhrks committed Jun 6, 2014
1 parent fa21ad8 commit e22c856
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 14 deletions.
2 changes: 2 additions & 0 deletions doc/source/v0.14.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,5 @@ Bug Fixes
- Bug where a string column name assignment to a ``DataFrame`` with a
``Float64Index`` raised a ``TypeError`` during a call to ``np.isnan``
(:issue:`7366`).
- BUG in ``DatetimeIndex.insert`` doesn't preserve ``name`` and ``tz`` (:issue:`7299`)
- BUG in ``DatetimeIndex.asobject`` doesn't preserve ``name`` (:issue:`7299`)
27 changes: 21 additions & 6 deletions pandas/tseries/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,7 @@ def tolist(self):
def _get_object_index(self):
boxfunc = lambda x: Timestamp(x, offset=self.offset, tz=self.tz)
boxed_values = lib.map_infer(self.asi8, boxfunc)
return Index(boxed_values, dtype=object)
return Index(boxed_values, dtype=object, name=self.name)

def to_pydatetime(self):
"""
Expand Down Expand Up @@ -1594,15 +1594,30 @@ def insert(self, loc, item):
-------
new_index : Index
"""
freq = None
if isinstance(item, datetime):
zone = tslib.get_timezone(self.tz)
izone = tslib.get_timezone(getattr(item, 'tzinfo', None))
if zone != izone:
raise ValueError('Passed item and index have different timezone')

# check freq can be preserved on edge cases
if self.freq is not None:
if (loc == 0 or loc == -len(self)) and item + self.freq == self[0]:
freq = self.freq
elif (loc == len(self)) and item - self.freq == self[-1]:
freq = self.freq

item = _to_m8(item, tz=self.tz)

try:
new_index = np.concatenate((self[:loc].asi8,
[item.view(np.int64)],
self[loc:].asi8))
return DatetimeIndex(new_index, freq='infer')
except (AttributeError, TypeError):
new_dates = np.concatenate((self[:loc].asi8, [item.view(np.int64)],
self[loc:].asi8))
if self.tz is not None:
new_dates = tslib.date_normalize(new_dates, self.tz)
return DatetimeIndex(new_dates, name=self.name, freq=freq, tz=self.tz)

except (AttributeError, TypeError):
# fall back to object index
if isinstance(item,compat.string_types):
return self.asobject.insert(loc, item)
Expand Down
93 changes: 85 additions & 8 deletions pandas/tseries/tests/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -2273,24 +2273,101 @@ def test_order(self):
self.assertTrue(ordered[::-1].is_monotonic)
self.assert_numpy_array_equal(dexer, [0, 2, 1])

def test_asobject(self):
idx = date_range(start='2013-01-01', periods=4, freq='M', name='idx')
expected = Index([Timestamp('2013-01-31'), Timestamp('2013-02-28'),
Timestamp('2013-03-31'), Timestamp('2013-04-30')],
dtype=object, name='idx')

result = idx.asobject
self.assertTrue(result.equals(expected))
self.assertEqual(result.name, expected.name)

def test_insert(self):
idx = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-02'])
idx = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-02'], name='idx')

result = idx.insert(2, datetime(2000, 1, 5))
exp = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-05',
'2000-01-02'])
self.assertTrue(result.equals(exp))
expected = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-05',
'2000-01-02'], name='idx')
self.assertTrue(result.equals(expected))
self.assertEqual(result.name, expected.name)

# insertion of non-datetime should coerce to object index
result = idx.insert(1, 'inserted')
expected = Index([datetime(2000, 1, 4), 'inserted', datetime(2000, 1, 1),
datetime(2000, 1, 2)])
datetime(2000, 1, 2)], name='idx')
self.assertNotIsInstance(result, DatetimeIndex)
tm.assert_index_equal(result, expected)
self.assertEqual(result.name, expected.name)

idx = date_range('1/1/2000', periods=3, freq='M', name='idx')

# preserve freq
expected_0 = DatetimeIndex(['1999-12-31', '2000-01-31', '2000-02-29',
'2000-03-31'], name='idx', freq='M')
expected_3 = DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31',
'2000-04-30'], name='idx', freq='M')

# reset freq to None
expected_1_nofreq = DatetimeIndex(['2000-01-31', '2000-01-31', '2000-02-29',
'2000-03-31'], name='idx', freq=None)
expected_3_nofreq = DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31',
'2000-01-02'], name='idx', freq=None)

cases = [(0, datetime(1999, 12, 31), expected_0),
(-3, datetime(1999, 12, 31), expected_0),
(3, datetime(2000, 4, 30), expected_3),
(1, datetime(2000, 1, 31), expected_1_nofreq),
(3, datetime(2000, 1, 2), expected_3_nofreq)]

for n, d, expected in cases:
result = idx.insert(n, d)
self.assertTrue(result.equals(expected))
self.assertEqual(result.name, expected.name)
self.assertEqual(result.freq, expected.freq)

idx = date_range('1/1/2000', periods=3, freq='M')
result = idx.insert(3, datetime(2000, 4, 30))
self.assertEqual(result.freqstr, 'M')
# reset freq to None
result = idx.insert(3, datetime(2000, 1, 2))
expected = DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31',
'2000-01-02'], name='idx', freq=None)
self.assertTrue(result.equals(expected))
self.assertEqual(result.name, expected.name)
self.assertTrue(result.freq is None)

# GH 7299
_skip_if_no_pytz()
import pytz

idx = date_range('1/1/2000', periods=3, freq='D', tz='US/Pacific', name='idx')
with tm.assertRaises(ValueError):
result = idx.insert(3, pd.Timestamp('2000-01-04'))
with tm.assertRaises(ValueError):
result = idx.insert(3, datetime(2000, 1, 4))
with tm.assertRaises(ValueError):
result = idx.insert(3, pd.Timestamp('2000-01-04', tz='US/Eastern'))
with tm.assertRaises(ValueError):
result = idx.insert(3, datetime(2000, 1, 4, tzinfo=pytz.timezone('US/Eastern')))

# preserve freq
expected = date_range('1/1/2000', periods=4, freq='D', tz='US/Pacific', name='idx')
for d in [pd.Timestamp('2000-01-04', tz='US/Pacific'),
datetime(2000, 1, 4, tzinfo=pytz.timezone('US/Pacific'))]:

result = idx.insert(3, d)
self.assertTrue(result.equals(expected))
self.assertEqual(result.name, expected.name)
self.assertEqual(result.freqstr, 'D')

expected = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03',
'2000-01-02'], name='idx',
tz='US/Pacific', freq=None)
# reset freq to None
for d in [pd.Timestamp('2000-01-02', tz='US/Pacific'),
datetime(2000, 1, 2, tzinfo=pytz.timezone('US/Pacific'))]:
result = idx.insert(3, d)
self.assertTrue(result.equals(expected))
self.assertEqual(result.name, expected.name)
self.assertTrue(result.freq is None)

def test_delete(self):
idx = date_range(start='2000-01-01', periods=5, freq='M', name='idx')
Expand Down

0 comments on commit e22c856

Please sign in to comment.