I'd like to find all the tuesdays and wednesdays (as datetime
object) between 2015-11-02 and 2015-12-14. This works:
from datetime import datetime, timedelta
l = []
for i in range(100):
d = datetime(2015,11,2) + timedelta(days=i)
if d > datetime(2015,12,14):
break
if d.weekday() == 1 or d.weekday() == 2: # tuesday or wednesday
l.append(d)
print l
[datetime.datetime(2015, 11, 3, 0, 0), datetime.datetime(2015, 11, 4, 0, 0), datetime.datetime(2015, 11, 10, 0, 0), datetime.datetime(2015, 11, 11, 0, 0), datetime.datetime(2015, 11, 17, 0, 0), datetime.datetime(2015, 11, 18, 0, 0), datetime.datetime(2015, 11, 24, 0, 0), datetime.datetime(2015, 11, 25, 0, 0), datetime.datetime(2015, 12, 1, 0, 0), datetime.datetime(2015, 12, 2, 0, 0), datetime.datetime(2015, 12, 8, 0, 0), datetime.datetime(2015, 12, 9, 0, 0)]
Is there a more pythonic way to do it?
from datetime import datetime, timedelta
start, end = datetime(2015, 11, 2), datetime(2015, 12, 14)
days = (start + timedelta(days=i) for i in range((end - start).days + 1))
l = [d for d in days if d.weekday() in [1,2] ]
This will be a lot faster if you are going over a long span:
def helper(d, i, inc):
while d.weekday() != i:
d += timedelta(days=inc)
return d.replace(hour=0, minute=0, second=0, microsecond=0)
start, end = datetime(2015, 11, 02), datetime(2015,12, 14)
def find_days(st, end, d1, d2):
if st >= end:
raise ValueError("Start must be before end")
else:
_st, _end = helper(st, d1, inc=-1), helper(end, d2, 1)
secs = (_end - _st).total_seconds() // 86400
if st.weekday() == d2:
yield st
for i in range(int(secs / 7) + 1):
if st <= _st <= end:
yield _st
nxt = _st + timedelta(days=1)
if nxt <= end:
yield nxt
_st += timedelta(days=7)
if _st <= end:
yield _st
from pprint import pprint as pp
from pprint import pprint as pp
pp(list(find_days(start, end, 1, 2)))
Output:
[datetime.datetime(2015, 11, 3, 0, 0),
datetime.datetime(2015, 11, 4, 0, 0),
datetime.datetime(2015, 11, 10, 0, 0),
datetime.datetime(2015, 11, 11, 0, 0),
datetime.datetime(2015, 11, 17, 0, 0),
datetime.datetime(2015, 11, 18, 0, 0),
datetime.datetime(2015, 11, 24, 0, 0),
datetime.datetime(2015, 11, 25, 0, 0),
datetime.datetime(2015, 12, 1, 0, 0),
datetime.datetime(2015, 12, 2, 0, 0),
datetime.datetime(2015, 12, 8, 0, 0),
datetime.datetime(2015, 12, 9, 0, 0)]
This does what dateutil does and does it faster:
In [12]: def dte():
....: results = rrule(DAILY,
....: dtstart = dt.datetime(2015,11, 2),
....: until = end,
....: byweekday=(TU, WE),
....: )
....: return list(results)
....:
In [38]: start, end = datetime(2015, 11, 2), datetime(2100, 11, 14)
In [39]: for i in range(600):
end += timedelta(days=1)
assert dte() == list(find_days(start, end,1,2 ))
....:
In [40]: start, end = datetime(2015, 11, 2), datetime(2017, 11, 14)
In [41]: timeit [d for d in date_range(start, end) if d.weekday() in (1, 2)]
10 loops, best of 3: 62.1 ms per loop
In [42]: timeit list(find_days(start, end, 1, 2))
100 loops, best of 3: 8.11 ms per loop
In [43]: timeit dte()
10 loops, best of 3: 131 ms per loop
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With