# filter date for a specific hour and minute

selected_hour=12
dates=[]
date1 = datetime.datetime(2012, 9, 10, 11, 46, 45)
date2 = datetime.datetime(2012, 9, 10, 12, 46, 45)
date3 = datetime.datetime(2012, 9, 10, 13, 47, 45)
date4 = datetime.datetime(2012, 9, 10, 13, 06, 45)
dates.append(date1)
dates.append(date2)
dates.append(date3)
dates.append(date4)

for i in dates:
if (i.hour<=selected_hour+1 and i.hour>=selected_hour-1):
if not i.hour==selected_hour:
if i.hour==selected_hour-1 and i.minute>45:
print i
if i.hour==selected_hour+1 and i.minute<=15:
print i
if i.hour==selected_hour:
print i


Result is :

    2012-09-10 11:46:45
2012-09-10 12:46:45
2012-09-10 13:06:45


I want to filter my dates based on selected_hour. The output should be 15 minutes later and before of the selected_hour including all selected_hour's minutes. This codes does what I want but, i am looking for a nicer way to do that. How to get same results in a shorter and better way ?

Try something like this:

for i in dates:
if i.hour == selected_hour:
print i
elif i.hour == (selected_hour - 1) % 24 and i.minute > 45:
print i
elif i.hour == (selected_hour + 1) % 24 and i.minute <= 15:
print i


The biggest technique I used to condense your code basically was "Don't repeat yourself"! You have a lot of redundant if statements in your code which can be simplified.

Another thing that makes my code more understandable is that it's flat, not nested. Ideally, you'd want to minimize the number of logic branches.

Edit: As @Dougal mentioned, my original code wouldn't work on the special case of midnight. I added in a modulus operator on my two elif conditions so that the selected_hour test wraps in a 24 digit circle, just like real time.

• Note that this doesn't wrap around at midnight well (like the OP's). – Dougal Oct 15 '12 at 2:09
• Maybe I'm not seeing that - what's a datetime that I can see the deficiency with? – Thane Brimhall Oct 15 '12 at 2:12
• If we're selecting for 11pm (i.hour == 23), then it should presumably allow times up through 12:15am, but this would look for i.hour == 24, which won't happen. – Dougal Oct 15 '12 at 2:13

If you want to ignore the date, then you could use combine to shift every date to some arbitrary base date. Then you can still use datetime inequalities to compare the times:

import datetime as dt
selected_hour=12
date1 = dt.datetime(2011, 9, 10, 11, 46, 45)
date2 = dt.datetime(2012, 8, 10, 12, 46, 45)
date3 = dt.datetime(2012, 9, 11, 13, 47, 45)
date4 = dt.datetime(2012, 10, 10, 13, 06, 45)
dates=[date1, date2, date3, date4]

base_date = dt.date(2000,1,1)
base_time = dt.time(selected_hour,0,0)
base = dt.datetime.combine(base_date, base_time)
min15 = dt.timedelta(minutes = 15)
start = base - min15
end = base + 5*min15

for d in dates:
if start <= dt.datetime.combine(base_date, d.time()) <= end:
print(d)


yields

2011-09-10 11:46:45
2012-08-10 12:46:45
2012-10-10 13:06:45


I have a question before the answer. I don't know if you want to filter this case, but if you take this datetime:

selected_hour=12
date4 = datetime.datetime(2012, 9, 10, 13, 15, 45)


you don't filter that result, and being strict, that datetime is over 15 minutes your selected_hour.

Anyway, if you have the year, month and day too, you can use datetime data type and timedelta to solve this problem.

import datetime
from datetime import timedelta

selected_hour=12
dates=[]
date1 = datetime.datetime(2012, 9, 10, 11, 44, 59)
date2 = datetime.datetime(2012, 9, 10, 11, 45, 00)
date3 = datetime.datetime(2012, 9, 10, 13, 15, 00)
date4 = datetime.datetime(2012, 9, 10, 13, 15, 01)
date5 = datetime.datetime(2011, 5, 11, 13, 15, 00)
date6 = datetime.datetime(2011, 5, 11, 13, 15, 01)
dates.append(date1)
dates.append(date2)
dates.append(date3)
dates.append(date4)
dates.append(date5)
dates.append(date6)

for i in dates:
ref_date = datetime.datetime(i.year, i.month, i.day, selected_hour, 0, 0)
time_difference = abs( (i-ref_date).total_seconds() )
if (i < ref_date):
if time_difference <= 15 * 60:
print i
else:
if time_difference <= 75 * 60:
print i


Result is:

2012-09-10 11:45:00
2012-09-10 13:15:00
2011-05-11 13:15:00

• I read the question as selecting on the hour without depending on the date itself. It's unfortunate that all the examples used the same date. – Mark Ransom Oct 15 '12 at 2:43
• Yes, you're possibly right. I understood it the other way because of the data. It would be nice if John Smith clarified it. – DMunoz Oct 15 '12 at 2:52
• @MarkRansom I made a change and now it works in the way you mentioned. – DMunoz Oct 15 '12 at 13:58
• Yes, that's much better. It still has a problem around midnight though - test with selected_hour=0 and 23:59. – Mark Ransom Oct 15 '12 at 14:32