4

我正在尝试考虑最简洁/pythonic 的方法来创建仅包含工作日的日期对象列表,给定开始日期和结束日期。这是我能想到的:

sdate = datetime.date(2013, 9, 1)
edate = datetime.date(2013, 9, 30)
weekdays = [sdate + datetime.timedelta(days=i) 
            for i in range((edate - sdate).days+1) 
            if (sdate + datetime.timedelta(days=i)).weekday() not in (5, 6)]

或者

alldays = (sdate + datetime.timedelta(days=i) for i in range((edate - sdate).days+1))
weekdays = [d for d in alldays if d.weekday() not in (5, 6)]

这样的事情被认为是干净的,还是我只是荒谬,我应该把它吸起来并创建一个 for 循环?

4

3 回答 3

2

我会考虑dateutil.rrulepip install python-dateutil):

import datetime
from dateutil import rrule

start = datetime.datetime(2013, 9, 1)
end = datetime.datetime(2013, 9, 30)
rule = rrule.rrule(dtstart=start, freq=rrule.DAILY,
    byweekday=[rrule.MO, rrule.TU, rrule.WE, rrule.TH, rrule.FR]
)
rule.between(start, end, inc=True)


[datetime.datetime(2013, 9, 2, 0, 0),
 datetime.datetime(2013, 9, 3, 0, 0),
 datetime.datetime(2013, 9, 4, 0, 0),
 datetime.datetime(2013, 9, 5, 0, 0),
 datetime.datetime(2013, 9, 6, 0, 0),
 datetime.datetime(2013, 9, 9, 0, 0),
 datetime.datetime(2013, 9, 10, 0, 0),
 datetime.datetime(2013, 9, 11, 0, 0),
 datetime.datetime(2013, 9, 12, 0, 0),
 datetime.datetime(2013, 9, 13, 0, 0),
 datetime.datetime(2013, 9, 16, 0, 0),
 datetime.datetime(2013, 9, 17, 0, 0),
 datetime.datetime(2013, 9, 18, 0, 0),
 datetime.datetime(2013, 9, 19, 0, 0),
 datetime.datetime(2013, 9, 20, 0, 0),
 datetime.datetime(2013, 9, 23, 0, 0),
 datetime.datetime(2013, 9, 24, 0, 0),
 datetime.datetime(2013, 9, 25, 0, 0),
 datetime.datetime(2013, 9, 26, 0, 0),
 datetime.datetime(2013, 9, 27, 0, 0),
 datetime.datetime(2013, 9, 30, 0, 0)]
于 2013-10-03T19:20:35.040 回答
1

并不是说这一定比你的方法更 Pythonic,但有时生成器和的组合有助于使代码更具可读性而不会增加开销,再次 YMMV

from itertools import takewhile, count
import datetime
sdate = datetime.date(2013, 9, 1)
edate = datetime.date(2013, 9, 30)
g = (sdate + datetime.timedelta(days=x) for x in count(1))
g = (x for x in g if x.weekday() not in (5, 6))
g = takewhile(lambda x: x <= edate, g)
print list(g)
于 2013-10-03T19:44:51.950 回答
0

我不认为您的代码有任何不合理之处……但是如果您多次使用日期范围,则绝对可以通过将其分解为函数来使其更清晰。例如:

def date_range(start, stop, skip=1):
    daycount = (stop - start).days
    for i in range(0, daycount, skip):
        yield start + datetime.timedelta(days=i)

你可以把它做成一个yield from单线,就像你原来的genexpr一样,但我认为这不值得。

无论如何,一旦你有了这个,你可以这样做:

weekdays = [d for d in date_range(sdate, edate) if d.weekday() not in (5, 6)]

如果您正在做其他需要它的事情,您甚至可能想要一个timedelta_range可以date_range使用的:

def timedelta_range(start, stop=None, skip=1):
    if stop is None: start, stop = datetime.timedelta(0), start
    r = range(start.days, stop.days, skip)
    yield from (datetime.timedelta(days=i) for i in r)

def date_range(start, stop, skip=1):
    for i in timedelta_range(datetime.timedelta(days=0), stop-start, skip):
        yield start+i

(让range-like 函数执行神奇的“可选第一个参数”位总是很烦人......)

于 2013-10-03T19:21:19.833 回答