Skip to content

Commit 5cf9e1f

Browse files
changhiskhanwesm
authored andcommitted
ENH: at_time and between_time for DataFrame #2131
1 parent 6247c8c commit 5cf9e1f

File tree

3 files changed

+132
-36
lines changed

3 files changed

+132
-36
lines changed

pandas/core/generic.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,48 @@ def asfreq(self, freq, method=None, how=None):
156156
from pandas.tseries.resample import asfreq
157157
return asfreq(self, freq, method=method, how=how)
158158

159+
def at_time(self, time, asof=False):
160+
"""
161+
Select values at particular time of day (e.g. 9:30AM)
162+
163+
Parameters
164+
----------
165+
time : datetime.time or string
166+
167+
Returns
168+
-------
169+
values_at_time : type of caller
170+
"""
171+
try:
172+
indexer = self.index.indexer_at_time(time, asof=asof)
173+
return self.take(indexer)
174+
except AttributeError:
175+
raise TypeError('Index must be DatetimeIndex')
176+
177+
def between_time(self, start_time, end_time, include_start=True,
178+
include_end=True):
179+
"""
180+
Select values between particular times of the day (e.g., 9:00-9:30 AM)
181+
182+
Parameters
183+
----------
184+
start_time : datetime.time or string
185+
end_time : datetime.time or string
186+
include_start : boolean, default True
187+
include_end : boolean, default True
188+
189+
Returns
190+
-------
191+
values_between_time : type of caller
192+
"""
193+
try:
194+
indexer = self.index.indexer_between_time(
195+
start_time, end_time, include_start=include_start,
196+
include_end=include_end)
197+
return self.take(indexer)
198+
except AttributeError:
199+
raise TypeError('Index must be DatetimeIndex')
200+
159201
def resample(self, rule, how=None, axis=0, fill_method=None,
160202
closed='right', label='right', convention=None,
161203
kind=None, loffset=None, limit=None, base=0):

pandas/core/series.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,42 +2935,6 @@ def _repr_footer(self):
29352935
namestr = "Name: %s, " % str(self.name) if self.name is not None else ""
29362936
return '%s%sLength: %d' % (freqstr, namestr, len(self))
29372937

2938-
def at_time(self, time, asof=False):
2939-
"""
2940-
Select values at particular time of day (e.g. 9:30AM)
2941-
2942-
Parameters
2943-
----------
2944-
time : datetime.time or string
2945-
2946-
Returns
2947-
-------
2948-
values_at_time : TimeSeries
2949-
"""
2950-
indexer = self.index.indexer_at_time(time, asof=asof)
2951-
return self.take(indexer)
2952-
2953-
def between_time(self, start_time, end_time, include_start=True,
2954-
include_end=True):
2955-
"""
2956-
Select values between particular times of the day (e.g., 9:00-9:30 AM)
2957-
2958-
Parameters
2959-
----------
2960-
start_time : datetime.time or string
2961-
end_time : datetime.time or string
2962-
include_start : boolean, default True
2963-
include_end : boolean, default True
2964-
2965-
Returns
2966-
-------
2967-
values_between_time : TimeSeries
2968-
"""
2969-
indexer = self.index.indexer_between_time(
2970-
start_time, end_time, include_start=include_start,
2971-
include_end=include_end)
2972-
return self.take(indexer)
2973-
29742938
def to_timestamp(self, freq=None, how='start', copy=True):
29752939
"""
29762940
Cast to datetimeindex of timestamps, at *beginning* of period

pandas/tseries/tests/test_timeseries.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,36 @@ def test_at_time(self):
863863
rs = ts.at_time('16:00')
864864
self.assert_(len(rs) == 0)
865865

866+
def test_at_time_frame(self):
867+
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
868+
ts = DataFrame(np.random.randn(len(rng), 2), index=rng)
869+
rs = ts.at_time(rng[1])
870+
self.assert_((rs.index.hour == rng[1].hour).all())
871+
self.assert_((rs.index.minute == rng[1].minute).all())
872+
self.assert_((rs.index.second == rng[1].second).all())
873+
874+
result = ts.at_time('9:30')
875+
expected = ts.at_time(time(9, 30))
876+
assert_frame_equal(result, expected)
877+
878+
result = ts.ix[time(9, 30)]
879+
expected = ts.ix[(rng.hour == 9) & (rng.minute == 30)]
880+
881+
assert_frame_equal(result, expected)
882+
883+
# midnight, everything
884+
rng = date_range('1/1/2000', '1/31/2000')
885+
ts = DataFrame(np.random.randn(len(rng), 3), index=rng)
886+
887+
result = ts.at_time(time(0, 0))
888+
assert_frame_equal(result, ts)
889+
890+
# time doesn't exist
891+
rng = date_range('1/1/2012', freq='23Min', periods=384)
892+
ts = DataFrame(np.random.randn(len(rng), 2), rng)
893+
rs = ts.at_time('16:00')
894+
self.assert_(len(rs) == 0)
895+
866896
def test_between_time(self):
867897
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
868898
ts = Series(np.random.randn(len(rng)), index=rng)
@@ -923,6 +953,66 @@ def test_between_time(self):
923953
else:
924954
self.assert_((t < etime) or (t >= stime))
925955

956+
def test_between_time_frame(self):
957+
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
958+
ts = DataFrame(np.random.randn(len(rng), 2), index=rng)
959+
stime = time(0, 0)
960+
etime = time(1, 0)
961+
962+
close_open = itertools.product([True, False], [True, False])
963+
for inc_start, inc_end in close_open:
964+
filtered = ts.between_time(stime, etime, inc_start, inc_end)
965+
exp_len = 13 * 4 + 1
966+
if not inc_start:
967+
exp_len -= 5
968+
if not inc_end:
969+
exp_len -= 4
970+
971+
self.assert_(len(filtered) == exp_len)
972+
for rs in filtered.index:
973+
t = rs.time()
974+
if inc_start:
975+
self.assert_(t >= stime)
976+
else:
977+
self.assert_(t > stime)
978+
979+
if inc_end:
980+
self.assert_(t <= etime)
981+
else:
982+
self.assert_(t < etime)
983+
984+
result = ts.between_time('00:00', '01:00')
985+
expected = ts.between_time(stime, etime)
986+
assert_frame_equal(result, expected)
987+
988+
#across midnight
989+
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
990+
ts = DataFrame(np.random.randn(len(rng), 2), index=rng)
991+
stime = time(22, 0)
992+
etime = time(9, 0)
993+
994+
close_open = itertools.product([True, False], [True, False])
995+
for inc_start, inc_end in close_open:
996+
filtered = ts.between_time(stime, etime, inc_start, inc_end)
997+
exp_len = (12 * 11 + 1) * 4 + 1
998+
if not inc_start:
999+
exp_len -= 4
1000+
if not inc_end:
1001+
exp_len -= 4
1002+
1003+
self.assert_(len(filtered) == exp_len)
1004+
for rs in filtered.index:
1005+
t = rs.time()
1006+
if inc_start:
1007+
self.assert_((t >= stime) or (t <= etime))
1008+
else:
1009+
self.assert_((t > stime) or (t <= etime))
1010+
1011+
if inc_end:
1012+
self.assert_((t <= etime) or (t >= stime))
1013+
else:
1014+
self.assert_((t < etime) or (t >= stime))
1015+
9261016
def test_dti_constructor_preserve_dti_freq(self):
9271017
rng = date_range('1/1/2000', '1/2/2000', freq='5min')
9281018

0 commit comments

Comments
 (0)