Skip to content

Commit 48d8d9d

Browse files
committed
BUG: fix closed='left' resample bug. test coverage #1245
1 parent dfec43f commit 48d8d9d

File tree

6 files changed

+136
-44
lines changed

6 files changed

+136
-44
lines changed

pandas/core/index.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -858,8 +858,11 @@ def join(self, other, how='left', level=None, return_indexers=False):
858858
return self._join_non_unique(other, how=how,
859859
return_indexers=return_indexers)
860860
elif self.is_monotonic and other.is_monotonic:
861-
return self._join_monotonic(other, how=how,
862-
return_indexers=return_indexers)
861+
try:
862+
return self._join_monotonic(other, how=how,
863+
return_indexers=return_indexers)
864+
except TypeError:
865+
pass
863866

864867
if how == 'left':
865868
join_index = self

pandas/tseries/index.py

+22-36
Original file line numberDiff line numberDiff line change
@@ -401,24 +401,6 @@ def __setstate__(self, state):
401401
self.offset = own_state[1]
402402
self.tz = own_state[2]
403403
np.ndarray.__setstate__(self, nd_state)
404-
elif len(state) == 3:
405-
# legacy format: daterange
406-
offset = state[1]
407-
408-
if len(state) > 2:
409-
tzinfo = state[2]
410-
else: # pragma: no cover
411-
tzinfo = None
412-
413-
self.offset = offset
414-
self.tzinfo = tzinfo
415-
416-
# extract the raw datetime data, turn into datetime64
417-
index_state = state[0]
418-
raw_data = index_state[0][4]
419-
raw_data = np.array(raw_data, dtype=_NS_DTYPE)
420-
new_state = raw_data.__reduce__()
421-
np.ndarray.__setstate__(self, new_state[2])
422404
else: # pragma: no cover
423405
np.ndarray.__setstate__(self, state)
424406

@@ -427,20 +409,24 @@ def __add__(self, other):
427409
return self.union(other)
428410
elif isinstance(other, (DateOffset, timedelta)):
429411
return self._add_delta(other)
412+
elif isinstance(other, np.timedelta64):
413+
raise NotImplementedError
430414
elif com.is_integer(other):
431415
return self.shift(other)
432-
else:
433-
return Index(self.view(np.ndarray) + other)
416+
else: # pragma: no cover
417+
raise TypeError(other)
434418

435419
def __sub__(self, other):
436420
if isinstance(other, Index):
437421
return self.diff(other)
438422
elif isinstance(other, (DateOffset, timedelta)):
439423
return self._add_delta(-other)
424+
elif isinstance(other, np.timedelta64):
425+
raise NotImplementedError
440426
elif com.is_integer(other):
441427
return self.shift(-other)
442-
else:
443-
return Index(self.view(np.ndarray) - other)
428+
else: # pragma: no cover
429+
raise TypeError(other)
444430

445431
def _add_delta(self, delta):
446432
if isinstance(delta, (Tick, timedelta)):
@@ -510,25 +496,23 @@ def astype(self, dtype):
510496

511497
if dtype == np.object_:
512498
return self.asobject
513-
return Index.astype(self, dtype)
499+
elif dtype == _INT64_DTYPE:
500+
return self.asi8.copy()
501+
else: # pragma: no cover
502+
raise ValueError('Cannot cast DatetimeIndex to dtype %s' % dtype)
514503

515504
@property
516505
def asi8(self):
517506
# do not cache or you'll create a memory leak
518507
return self.values.view('i8')
519508

520-
@property
521-
def asstruct(self):
522-
if self._sarr_cache is None:
523-
self._sarr_cache = self._get_field_sarr()
524-
return self._sarr_cache
525-
526-
def _get_field_sarr(self):
527-
utc = _utc()
528-
values = self.asi8
529-
if self.tz is not None and self.tz is not utc:
530-
values = lib.tz_convert(values, utc, self.tz)
531-
return lib.build_field_sarray(values)
509+
# @property
510+
# def asstruct(self):
511+
# utc = _utc()
512+
# values = self.asi8
513+
# if self.tz is not None and self.tz is not utc:
514+
# values = lib.tz_convert(values, utc, self.tz)
515+
# return lib.build_field_sarray(values)
532516

533517
def _get_time_micros(self):
534518
utc = _utc()
@@ -594,6 +578,8 @@ def order(self, return_indexer=False, ascending=True):
594578
return sorted_index, _as
595579
else:
596580
sorted_values = np.sort(self.values)
581+
if not ascending:
582+
sorted_values = sorted_values[::-1]
597583
return self._simple_new(sorted_values, self.name, None,
598584
self.tz)
599585

@@ -709,7 +695,7 @@ def join(self, other, how='left', level=None, return_indexers=False):
709695
if not isinstance(other, DatetimeIndex) and len(other) > 0:
710696
try:
711697
other = DatetimeIndex(other)
712-
except ValueError:
698+
except TypeError:
713699
pass
714700

715701
this, other = self._maybe_utc_convert(other)

pandas/tseries/resample.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def _get_time_bins(self, axis):
100100

101101
# a little hack
102102
trimmed = False
103-
if len(binner) > 2 and binner[-2] == axis[-1]:
103+
if len(binner) > 2 and binner[-2] == axis[-1] and self.closed == 'right':
104104
binner = binner[:-1]
105105
trimmed = True
106106

650 Bytes
Binary file not shown.

pandas/tseries/tests/test_resample.py

+4
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,10 @@ def test_closed_left_corner(self):
714714

715715
result = s.resample('10min', how='mean',closed='left', label='left')
716716
exp = s[1:].resample('10min', how='mean',closed='left', label='left')
717+
718+
ex_index = date_range(start='1/1/2012 9:30', freq='10min', periods=3)
719+
720+
self.assert_(result.index.equals(ex_index))
717721
assert_series_equal(result, exp)
718722

719723
class TestTimeGrouper(unittest.TestCase):

pandas/tseries/tests/test_timeseries.py

+104-5
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,14 @@ def test_append_concat(self):
924924
ex_index = DatetimeIndex(np.tile(rng.values, 3))
925925
self.assert_(appended.equals(ex_index))
926926

927+
# different index names
928+
rng1 = rng.copy()
929+
rng2 = rng.copy()
930+
rng1.name = 'foo'
931+
rng2.name = 'bar'
932+
self.assert_(rng1.append(rng1).name == 'foo')
933+
self.assert_(rng1.append(rng2).name is None)
934+
927935
def test_set_dataframe_column_ns_dtype(self):
928936
x = DataFrame([datetime.now(), datetime.now()])
929937
self.assert_(x[0].dtype == object)
@@ -953,13 +961,30 @@ def _simple_ts(start, end, freq='D'):
953961

954962
class TestDatetimeIndex(unittest.TestCase):
955963

956-
def test_append_nondatetimeindex(self):
964+
def test_append_join_nondatetimeindex(self):
957965
rng = date_range('1/1/2000', periods=10)
958966
idx = Index(['a', 'b', 'c', 'd'])
959967

960968
result = rng.append(idx)
961969
self.assert_(isinstance(result[0], Timestamp))
962970

971+
# it works
972+
rng.join(idx, how='outer')
973+
974+
def test_astype(self):
975+
rng = date_range('1/1/2000', periods=10)
976+
977+
result = rng.astype('i8')
978+
self.assert_(np.array_equal(result, rng.asi8))
979+
980+
def test_to_period_nofreq(self):
981+
idx = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-04'])
982+
self.assertRaises(ValueError, idx.to_period)
983+
984+
idx = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-03'],
985+
freq='infer')
986+
idx.to_period()
987+
963988
def test_constructor_coverage(self):
964989
rng = date_range('1/1/2000', periods=10.5)
965990
exp = date_range('1/1/2000', periods=10)
@@ -1018,6 +1043,62 @@ def test_map(self):
10181043
exp = [f(x) for x in rng]
10191044
self.assert_(np.array_equal(result, exp))
10201045

1046+
def test_add_union(self):
1047+
rng = date_range('1/1/2000', periods=5)
1048+
rng2 = date_range('1/6/2000', periods=5)
1049+
1050+
result = rng + rng2
1051+
expected = rng.union(rng2)
1052+
self.assert_(result.equals(expected))
1053+
1054+
def test_misc_coverage(self):
1055+
rng = date_range('1/1/2000', periods=5)
1056+
result = rng.groupby(rng.day)
1057+
self.assert_(isinstance(result.values()[0][0], Timestamp))
1058+
1059+
def test_union_coverage(self):
1060+
idx = DatetimeIndex(['2000-01-03', '2000-01-01', '2000-01-02'])
1061+
ordered = DatetimeIndex(idx.order(), freq='infer')
1062+
result = ordered.union(idx)
1063+
self.assert_(result.equals(ordered))
1064+
1065+
result = ordered[:0].union(ordered)
1066+
self.assert_(result.equals(ordered))
1067+
self.assert_(result.freq == ordered.freq)
1068+
1069+
# def test_add_timedelta64(self):
1070+
# rng = date_range('1/1/2000', periods=5)
1071+
# delta = rng.values[3] - rng.values[1]
1072+
1073+
# result = rng + delta
1074+
# expected = rng + timedelta(2)
1075+
# self.assert_(result.equals(expected))
1076+
1077+
def test_get_duplicates(self):
1078+
idx = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-02',
1079+
'2000-01-03', '2000-01-03', '2000-01-04'])
1080+
1081+
result = idx.get_duplicates()
1082+
ex = DatetimeIndex(['2000-01-02', '2000-01-03'])
1083+
self.assert_(result.equals(ex))
1084+
1085+
def test_order(self):
1086+
idx = DatetimeIndex(['2000-01-04', '2000-01-01', '2000-01-02'])
1087+
1088+
ordered = idx.order()
1089+
self.assert_(ordered.is_monotonic)
1090+
1091+
ordered = idx.order(ascending=False)
1092+
self.assert_(ordered[::-1].is_monotonic)
1093+
1094+
ordered, dexer = idx.order(return_indexer=True)
1095+
self.assert_(ordered.is_monotonic)
1096+
self.assert_(np.array_equal(dexer, [1, 2, 0]))
1097+
1098+
ordered, dexer = idx.order(return_indexer=True, ascending=False)
1099+
self.assert_(ordered[::-1].is_monotonic)
1100+
self.assert_(np.array_equal(dexer, [0, 2, 1]))
1101+
10211102

10221103
class TestLegacySupport(unittest.TestCase):
10231104

@@ -1119,6 +1200,15 @@ def _check_join(left, right, how='inner'):
11191200
_check_join(index[:15], obj_index[5:], how='right')
11201201
_check_join(index[:15], obj_index[5:], how='left')
11211202

1203+
def test_unpickle_daterange(self):
1204+
pth, _ = os.path.split(os.path.abspath(__file__))
1205+
filepath = os.path.join(pth, 'data', 'daterange_073.pickle')
1206+
1207+
rng = com.load(filepath)
1208+
self.assert_(type(rng[0]) == datetime)
1209+
self.assert_(isinstance(rng.offset, offsets.BDay))
1210+
self.assert_(rng.values.dtype == object)
1211+
11221212
def test_setops(self):
11231213
index = self.frame.index
11241214
obj_index = index.asobject
@@ -1290,17 +1380,26 @@ def test_timedelta(self):
12901380
self.assertEqual(shifted.freq, index.freq)
12911381
self.assertEqual(shifted.freq, back.freq)
12921382

1293-
def test_shift_multiple_of_same_base(self):
1294-
# GH #1063
1383+
result = index - timedelta(1)
1384+
expected = index + timedelta(-1)
1385+
self.assert_(result.equals(expected))
1386+
1387+
def test_shift(self):
12951388
ts = Series(np.random.randn(5),
12961389
index=date_range('1/1/2000', periods=5, freq='H'))
12971390

1298-
result = ts.shift(1, freq='4H')
1391+
result = ts.shift(1, freq='5T')
1392+
exp_index = ts.index.shift(1, freq='5T')
1393+
self.assert_(result.index.equals(exp_index))
12991394

1395+
# GH #1063, multiple of same base
1396+
result = ts.shift(1, freq='4H')
13001397
exp_index = ts.index + datetools.Hour(4)
1301-
13021398
self.assert_(result.index.equals(exp_index))
13031399

1400+
idx = DatetimeIndex(['2000-01-01', '2000-01-02', '2000-01-04'])
1401+
self.assertRaises(ValueError, idx.shift, 1)
1402+
13041403
def test_setops_preserve_freq(self):
13051404
rng = date_range('1/1/2000', '1/1/2002')
13061405

0 commit comments

Comments
 (0)