2016-07-12 35 views
1

我是Python新手,也是dateutil模塊。我傳遞了以下參數:dateutils rrule返回相隔2個月的日期

disclosure_start_date = resultsDict['fd_disclosure_start_date'] 
disclosure_end_date = datetime.datetime.now() 
disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)] 

這裏其轉換爲datetime是datetime.datetime(2012, 10, 31, 0, 0)

結束日期是截至目前。

當我使用:

disclosure_dates = [dt for dt in rrule(MONTHLY, dtstart=disclosure_start_date, until=disclosure_end_date)] 

我得到每隔一個月的日期或2個月外。結果是:

>>> list(disclosure_dates) 
[datetime.datetime(2012, 10, 31, 0, 0), 
datetime.datetime(2012, 12, 31, 0, 0), 
datetime.datetime(2013, 1, 31, 0, 0), 
datetime.datetime(2013, 3, 31, 0, 0), 
datetime.datetime(2013, 5, 31, 0, 0), 
datetime.datetime(2013, 7, 31, 0, 0), 
datetime.datetime(2013, 8, 31, 0, 0), 
datetime.datetime(2013, 10, 31, 0, 0), 
datetime.datetime(2013, 12, 31, 0, 0), 
datetime.datetime(2014, 1, 31, 0, 0), 
datetime.datetime(2014, 3, 31, 0, 0), 
datetime.datetime(2014, 5, 31, 0, 0), 
datetime.datetime(2014, 7, 31, 0, 0), 
datetime.datetime(2014, 8, 31, 0, 0), 
datetime.datetime(2014, 10, 31, 0, 0), 
datetime.datetime(2014, 12, 31, 0, 0), 
datetime.datetime(2015, 1, 31, 0, 0), 
datetime.datetime(2015, 3, 31, 0, 0), 
datetime.datetime(2015, 5, 31, 0, 0), 
datetime.datetime(2015, 7, 31, 0, 0), 
datetime.datetime(2015, 8, 31, 0, 0), 
datetime.datetime(2015, 10, 31, 0, 0), 
datetime.datetime(2015, 12, 31, 0, 0), 
datetime.datetime(2016, 1, 31, 0, 0), 
datetime.datetime(2016, 3, 31, 0, 0), 
datetime.datetime(2016, 5, 31, 0, 0)] 

我不知道我在做什麼錯。有人能指出這裏的錯誤嗎?

回答

2

您遇到的問題來自於datetime.datetime(2012, 10, 31, 0, 0)是本月31號這一事實,並非所有月份都有第31次。由於rrule模塊是RFC 2445的實現每RFC 3.3.10:

復發規則可能產生帶有無效日期(例如,2月30日)或不存在的本地時間(例如,上午1:30復發情況在當地時間在凌晨1點向前移動一個小時的那一天)。這樣的重複實例必須被忽略,並且不能被計爲重複集合的一部分。

由於您每個月都會生成一個月的第31個月的規則,因此它將跳過所有有30天或更少天數的月份。您可以在dateutil中看到有關此問題的this bug report

如果你只是想在每月的最後一天,你應該使用bymonthday=-1參數:

from dateutil.rrule import rrule, MONTHLY 
from datetime import datetime 

disclosure_start_date = datetime(2012, 10, 31, 0, 0) 

rr = rrule(freq=MONTHLY, dtstart=disclosure_start_date, bymonthday=-1) 
# >>>rr.between(datetime(2013, 1, 1), datetime(2013, 5, 1)) 
# [datetime.datetime(2013, 1, 31, 0, 0), 
# datetime.datetime(2013, 2, 28, 0, 0), 
# datetime.datetime(2013, 3, 31, 0, 0), 
# datetime.datetime(2013, 4, 30, 0, 0)] 

不幸的是,我不認爲有一個符合RFC的方式來生成一個簡單的RRULE,只是下降如果有必要的話,可以回到本月月底(如果有必要的話)(例如,你在1月30日做了什麼 - 你需要2月份的後備時間,但是你不想使用bymonthday=-2,因爲這會給你2月27日,等等)。

另外,對於這樣一個簡單的每月執行的規則,一個更好的選擇可能是隻使用relativedelta,這確實回落至月末:

from dateutil.relativedelta import relativedelta 
from datetime import datetime 

def disclosure_dates(dtstart, rd, dtend=None): 
    ii = 0 
    while True: 
     cdate = dtstart + ii*rd 
     ii += 1 

     yield cdate 
     if dtend is not None and cdate >= dtend: 
      break 


dtstart = datetime(2013, 1, 31, 0, 0) 
rd = relativedelta(months=1) 
rr = disclosure_dates(dtstart, rd, dtend=datetime(2013, 5, 1)) 

# >>> list(rr) 
# [datetime.datetime(2013, 1, 31, 0, 0), 
# datetime.datetime(2013, 2, 28, 0, 0), 
# datetime.datetime(2013, 3, 31, 0, 0), 
# datetime.datetime(2013, 4, 30, 0, 0), 
# datetime.datetime(2013, 5, 31, 0, 0)] 

請注意,我專門用於cdate = dtstart + ii * rd ,你只想保持一個「流水賬」,因爲這將引腳以最短一個月的訊號已經看到:

dt_base = datetime(2013, 1, 31) 
dt = dt_base 
for ii in range(5): 
    cdt = dt_base + ii*rd 
    print('{} | {}'.format(dt, cdt)) 
    dt += rd 

回覆SULT:

2013-01-31 00:00:00 | 2013-01-31 00:00:00 
2013-02-28 00:00:00 | 2013-02-28 00:00:00 
2013-03-28 00:00:00 | 2013-03-31 00:00:00 
2013-04-28 00:00:00 | 2013-04-30 00:00:00 
2013-05-28 00:00:00 | 2013-05-31 00:00:00 
+3

FYI,有[RFC 7529](https://tools.ietf.org/html/rfc7529),其(尤其)通過回退到一個模式延伸'RRULE'如果一天不存在,則在一個月的最後一天。規則'FREQ = MONTHLY; RSCALE = GREGORIAN; SKIP = BACKWARD; BYMONTHDAY = 30'會這樣做。今年2月,這將導致第28位(或閏年第29位)。不幸的是,目前還沒有太多的支持。 – Marten

+0

@Marten真棒,不知道。我會閱讀並實施dateutil。 – Paul

+0

謝謝保羅。 upvoted你的答案。 – DrBug

相關問題