我正在使用python的dateutil模块来解析我日历中的重复规则。以下问题产生了一个问题:
来自dateutil.rrule import rrulestr
def test():
rrule = 'FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=30;UNTIL=20180331T2359'
dtstart = datetime.datetime(2018, 1, 1, 18, 0)
dates = list(rrulestr(rrule + ';UNTIL=', dtstart = dtstart ))
这导致以下输出(缺少2月):
datetime: 2018-01-30 18:00:00
datetime: 2018-03-30 18:00:00
这是dateutil
模块中的错误,我该如何解决?或者我做错了什么?
答案 0 :(得分:2)
根据我的回答on this equivalent question,这是dateutil
正在实施的iCalendar RFC的故意特征,因为dateutil
实现了RFC 2445并且不支持所有(或大多数)更新的RFC 5545的功能.RFC 2445的相关部分:
重复规则可以生成具有无效日期(例如,2月30日)或不存在的本地时间的重现实例(例如,在当地时间在凌晨1:00向前移动一小时的那天的1:30 AM)。必须忽略此类重复实例,并且不得将其视为重复集的一部分。
2月缺失,因为2018-02-30
是无效日期(它实际上是RFC中指定的示例)。
需要注意的一点是,this pull request实现了您想要的功能,但是(在撰写本文时)当前已阻止等待SKIP
中BYWEEKNO
的支持。合并之后,您将能够修改您的RRULE:
rrule = ('FREQ=MONTHLY;INTERVAL=1;BYMONTHDAY=30;UNTIL=20180331T2359;'+
'SKIP=BACKWARD;RSCALE=GREGORIAN')
在此之前,您最好的选择可能是使用BYMONTHDAY=28
,然后在结果中添加relativedelta(day=30)
,例如:
from dateutil.rrule import rrule, MONTHLY
from dateutil.relativedelta import relativedelta
def end_of_month(dtstart, until):
rr = rrule(freq=MONTHLY, interval=1, bymonthday=28,
dtstart=dtstart, until=until)
for dt in rr:
yield dt + relativedelta(day=30)
这是有效的,因为所有月份都存在第28个(因此rrule
将始终生成它),而relativedelta
在月末有#34;倒退"你正在寻找的行为。为了100%安全,您可以选择bymonthday=1
,在这种情况下它是等效的。