2012-07-18 38 views
8

Tôi đang cố gắng tạo một hàm máy phát để lặp qua các ngày làm việc (các ngày trong tuần), bỏ qua cuối tuần (và ngày lễ cũng sẽ tốt đẹp!). Cho đến nay, tôi chỉ có một chức năng mà chỉ đơn giản lặp trên ngày:Trình tạo phạm vi ngày của Python trong các ngày làm việc

def daterange(startDate, endDate): 
    for i in xrange(int((endDate - startDate).days)): 
     yield startDate + timedelta(i) 

Tôi đang đấu tranh để tìm ra một cách sạch, hiệu quả và pythonic để làm cho máy phát điện bỏ qua ngày cuối tuần và ngày lễ. Cảm ơn trước!

+1

Xem câu hỏi này cho những ngày nghỉ: http://stackoverflow.com/questions/1986207/holiday-calendars-file -formats-et-al –

Trả lời

23

tôi sẽ mạnh mẽ khuyên bạn nên sử dụng thư viện dateutil cho các nhiệm vụ như vậy. A (không lễ bỏ qua) iterator cơ bản qua ngày làm việc sau đó chỉ đơn giản là:

from dateutil.rrule import DAILY, rrule, MO, TU, WE, TH, FR 

def daterange(start_date, end_date): 
    return rrule(DAILY, dtstart=start_date, until=end_date, byweekday=(MO,TU,WE,TH,FR)) 
+0

Ví dụ hay! +1 –

+0

Điều này có thực sự làm những gì bạn nói không? Tôi đã thử nó trên Python 2.7 và 3.3 trên Linux và Mac OS, và trong mọi trường hợp nó trả về tất cả các ngày, kể cả cuối tuần. Nếu bạn nhìn vào 'dateutil.rrule.WDAYMASK' bạn có thể thấy rằng đó là danh sách 0-6, tức là tất cả các ngày, không chỉ từ thứ Hai đến thứ Sáu. –

+0

@JohnZwinck Right, WDAYMASK thực sự là không chính xác (ít nhất là với các phiên bản hiện tại của dateutil). Tôi đã cập nhật câu trả lời để phản ánh điều này. – earl

6

Giả sử startDateendDate là đối tượng ngày giờ hoặc ngày, bạn có thể sử dụng the weekday method để nhận ngày trong tuần, sau đó bỏ qua nếu đó là thứ Bảy hoặc Chủ Nhật. Chỉ cần làm:

def daterange(startDate, endDate): 
    for i in xrange(int((endDate - startDate).days)): 
     nextDate = startDate + timedelta(i) 
     if nextDate.weekday() not in (5, 6): 
      yield startDate + timedelta(i) 

Đối với ngày lễ, bạn sẽ phải kiểm tra thủ công cho mỗi kỳ nghỉ bạn muốn. Một số ngày lễ được định nghĩa theo những cách phức tạp để điều này có thể hơi phức tạp một chút.

7

Có một thư viện hữu ích được gọi là dateutil có thể làm việc này cho bạn. Nó có thể tạo ra phạm vi ngày (hoặc ngày dựa trên các quy tắc tùy chỉnh), ngoại trừ một số ngày nhất định, xem xét một tuần bắt đầu vào một ngày vv ... Cũng có một timedelta hơi linh hoạt hơn so với thư viện datetime dựng sẵn.

Documents tại http://labix.org/python-dateutil/ - và có sẵn trên PyPi

0
def get_date_range(start, end, workdays=None, holidays=None, skip_non_workdays=True): 
""" 
This function calculates the durations between 2 dates skipping non workdays and holidays as specified 
:rtype : tuple 
:param start: date 
:param end: date 
:param workdays: string [Comma Separated Values, 0 - Monday through to 6 - Sunday e.g "0,1,2,3,4"] 
:param holidays: list 
:param skip_non_workdays: boolean 
:return: 
""" 
from datetime import timedelta 

duration = 0 

# define workdays 
if workdays is None: 
    workdays = [0, 1, 2, 3, 4] 
else: 
    workdays = workdays.split(",") 

# check if we need to skip non workdays 
if skip_non_workdays is False: 
    workdays = [0, 1, 2, 3, 4, 5, 6] 

# validate dates 
if end < start: 
    return False, "End date is before start date" 

# now its time for us to iterate 
i = start 
while i <= end: 

    # first let's give benefit of the doubt 
    incr = True 

    # lets see if day is in the workday array if not then fault it's existence here 
    try: 
     workdays.index(i.weekday()) 
    except ValueError: 
     incr = False 

    # lets check if day is an holiday, charge guilty if so. 
    # We are checking the index in holiday array 
    try: 
     holidays.index(i) 
     incr = False 
    except (ValueError, AttributeError): 
     pass 

    if incr: 
     duration += 1 
     print "This day passed the criterion %s" % i 

    i += timedelta(1) 

return True, duration 
Các vấn đề liên quan