Skip to content

Commit 7b806a7

Browse files
committed
BUG: DatetimeIndex.insert doesnt preserve name and tz
1 parent 18d0155 commit 7b806a7

File tree

3 files changed

+107
-11
lines changed

3 files changed

+107
-11
lines changed

doc/source/v0.14.1.txt

+3
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ Bug Fixes
166166

167167

168168

169+
- BUG in ``DatetimeIndex.insert`` doesn't preserve ``name`` and ``tz`` (:issue:`7299`)
170+
- BUG in ``DatetimeIndex.asobject`` doesn't preserve ``name`` (:issue:`7299`)
169171

170172

171173

@@ -218,3 +220,4 @@ Bug Fixes
218220
:issue:`7409`).
219221
- Bug where bool objects were converted to ``nan`` in ``convert_objects``
220222
(:issue:`7416`).
223+

pandas/tseries/index.py

+21-5
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ def tolist(self):
784784
def _get_object_index(self):
785785
boxfunc = lambda x: Timestamp(x, offset=self.offset, tz=self.tz)
786786
boxed_values = lib.map_infer(self.asi8, boxfunc)
787-
return Index(boxed_values, dtype=object)
787+
return Index(boxed_values, dtype=object, name=self.name)
788788

789789
def to_pydatetime(self):
790790
"""
@@ -1594,13 +1594,29 @@ def insert(self, loc, item):
15941594
-------
15951595
new_index : Index
15961596
"""
1597+
1598+
freq = None
15971599
if isinstance(item, datetime):
1600+
zone = tslib.get_timezone(self.tz)
1601+
izone = tslib.get_timezone(getattr(item, 'tzinfo', None))
1602+
if zone != izone:
1603+
raise ValueError('Passed item and index have different timezone')
1604+
# check freq can be preserved on edge cases
1605+
if self.freq is not None:
1606+
if (loc == 0 or loc == -len(self)) and item + self.freq == self[0]:
1607+
freq = self.freq
1608+
elif (loc == len(self)) and item - self.freq == self[-1]:
1609+
freq = self.freq
15981610
item = _to_m8(item, tz=self.tz)
15991611
try:
1600-
new_index = np.concatenate((self[:loc].asi8,
1601-
[item.view(np.int64)],
1602-
self[loc:].asi8))
1603-
return DatetimeIndex(new_index, freq='infer')
1612+
new_dates = np.concatenate((self[:loc].asi8, [item.view(np.int64)],
1613+
self[loc:].asi8))
1614+
if self.tz is not None:
1615+
f = lambda x: tslib.tz_convert_single(x, 'UTC', self.tz)
1616+
new_dates = np.vectorize(f)(new_dates)
1617+
# new_dates = tslib.tz_convert(new_dates, 'UTC', self.tz)
1618+
return DatetimeIndex(new_dates, name=self.name, freq=freq, tz=self.tz)
1619+
16041620
except (AttributeError, TypeError):
16051621

16061622
# fall back to object index

pandas/tseries/tests/test_timeseries.py

+83-6
Original file line numberDiff line numberDiff line change
@@ -2293,24 +2293,101 @@ def test_order(self):
22932293
self.assertTrue(ordered[::-1].is_monotonic)
22942294
self.assert_numpy_array_equal(dexer, [0, 2, 1])
22952295

2296+
def test_asobject(self):
2297+
idx = date_range(start='2013-01-01', periods=4, freq='M', name='idx')
2298+
expected = Index([Timestamp('2013-01-31'), Timestamp('2013-02-28'),
2299+
Timestamp('2013-03-31'), Timestamp('2013-04-30')],
2300+
dtype=object, name='idx')
2301+
2302+
result = idx.asobject
2303+
self.assertTrue(result.equals(expected))
2304+
self.assertEqual(result.name, expected.name)
2305+
22962306
def test_insert(self):
2297-
idx = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-02'])
2307+
idx = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-02'], name='idx')
22982308

22992309
result = idx.insert(2, datetime(2000, 1, 5))
23002310
exp = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-05',
2301-
'2000-01-02'])
2311+
'2000-01-02'], name='idx')
23022312
self.assertTrue(result.equals(exp))
23032313

23042314
# insertion of non-datetime should coerce to object index
23052315
result = idx.insert(1, 'inserted')
23062316
expected = Index([datetime(2000, 1, 4), 'inserted', datetime(2000, 1, 1),
2307-
datetime(2000, 1, 2)])
2317+
datetime(2000, 1, 2)], name='idx')
23082318
self.assertNotIsInstance(result, DatetimeIndex)
23092319
tm.assert_index_equal(result, expected)
2320+
self.assertEqual(result.name, expected.name)
2321+
2322+
idx = date_range('1/1/2000', periods=3, freq='M', name='idx')
2323+
2324+
# preserve freq
2325+
expected_0 = DatetimeIndex(['1999-12-31', '2000-01-31', '2000-02-29',
2326+
'2000-03-31'], name='idx', freq='M')
2327+
expected_3 = DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31',
2328+
'2000-04-30'], name='idx', freq='M')
2329+
2330+
# reset freq to None
2331+
expected_1_nofreq = DatetimeIndex(['2000-01-31', '2000-01-31', '2000-02-29',
2332+
'2000-03-31'], name='idx', freq=None)
2333+
expected_3_nofreq = DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31',
2334+
'2000-01-02'], name='idx', freq=None)
2335+
2336+
cases = [(0, datetime(1999, 12, 31), expected_0),
2337+
(-3, datetime(1999, 12, 31), expected_0),
2338+
(3, datetime(2000, 4, 30), expected_3),
2339+
(1, datetime(2000, 1, 31), expected_1_nofreq),
2340+
(3, datetime(2000, 1, 2), expected_3_nofreq)]
2341+
2342+
for n, d, expected in cases:
2343+
result = idx.insert(n, d)
2344+
self.assertTrue(result.equals(expected))
2345+
self.assertEqual(result.name, expected.name)
2346+
self.assertEqual(result.freq, expected.freq)
2347+
2348+
# reset freq to None
2349+
result = idx.insert(3, datetime(2000, 1, 2))
2350+
expected = DatetimeIndex(['2000-01-31', '2000-02-29', '2000-03-31',
2351+
'2000-01-02'], name='idx', freq=None)
2352+
self.assertTrue(result.equals(expected))
2353+
self.assertEqual(result.name, expected.name)
2354+
self.assertTrue(result.freq is None)
2355+
2356+
# GH 7299
2357+
_skip_if_no_pytz()
2358+
import pytz
2359+
2360+
idx = date_range('1/1/2000', periods=3, freq='D', tz='Asia/Tokyo', name='idx')
2361+
with tm.assertRaises(ValueError):
2362+
result = idx.insert(3, pd.Timestamp('2000-01-04'))
2363+
with tm.assertRaises(ValueError):
2364+
result = idx.insert(3, datetime(2000, 1, 4))
2365+
with tm.assertRaises(ValueError):
2366+
result = idx.insert(3, pd.Timestamp('2000-01-04', tz='US/Eastern'))
2367+
with tm.assertRaises(ValueError):
2368+
result = idx.insert(3, datetime(2000, 1, 4, tzinfo=pytz.timezone('US/Eastern')))
2369+
2370+
# preserve freq
2371+
expected = date_range('1/1/2000', periods=4, freq='D', tz='Asia/Tokyo', name='idx')
2372+
for d in [pd.Timestamp('2000-01-04', tz='Asia/Tokyo'),
2373+
datetime(2000, 1, 4, tzinfo=pytz.timezone('Asia/Tokyo'))]:
2374+
2375+
result = idx.insert(3, d)
2376+
self.assertTrue(result.equals(expected))
2377+
self.assertEqual(result.name, expected.name)
2378+
self.assertEqual(result.freqstr, expected.freq)
2379+
2380+
expected = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03',
2381+
'2000-01-02'], name='idx',
2382+
tz='Asia/Tokyo', freq=None)
2383+
# reset freq to None
2384+
for d in [pd.Timestamp('2000-01-02', tz='Asia/Tokyo'),
2385+
datetime(2000, 1, 2, tzinfo=pytz.timezone('Asia/Tokyo'))]:
2386+
result = idx.insert(3, d)
2387+
self.assertTrue(result.equals(expected))
2388+
self.assertEqual(result.name, expected.name)
2389+
self.assertTrue(result.freq is None)
23102390

2311-
idx = date_range('1/1/2000', periods=3, freq='M')
2312-
result = idx.insert(3, datetime(2000, 4, 30))
2313-
self.assertEqual(result.freqstr, 'M')
23142391

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

0 commit comments

Comments
 (0)