3
\$\begingroup\$
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 ?

\$\endgroup\$

3 Answers 3

5
\$\begingroup\$

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.

\$\endgroup\$
3
  • 2
    \$\begingroup\$ Note that this doesn't wrap around at midnight well (like the OP's). \$\endgroup\$
    – Danica
    Commented Oct 15, 2012 at 2:09
  • \$\begingroup\$ Maybe I'm not seeing that - what's a datetime that I can see the deficiency with? \$\endgroup\$
    – Thane Brimhall
    Commented Oct 15, 2012 at 2:12
  • 2
    \$\begingroup\$ 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. \$\endgroup\$
    – Danica
    Commented Oct 15, 2012 at 2:13
0
\$\begingroup\$

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
\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
4
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Commented Oct 15, 2012 at 2:43
  • \$\begingroup\$ Yes, you're possibly right. I understood it the other way because of the data. It would be nice if John Smith clarified it. \$\endgroup\$
    – DMunoz
    Commented Oct 15, 2012 at 2:52
  • \$\begingroup\$ @MarkRansom I made a change and now it works in the way you mentioned. \$\endgroup\$
    – DMunoz
    Commented Oct 15, 2012 at 13:58
  • \$\begingroup\$ Yes, that's much better. It still has a problem around midnight though - test with selected_hour=0 and 23:59. \$\endgroup\$ Commented Oct 15, 2012 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.