Согласно моему ответу на этот эквивалентный вопрос, это преднамеренная функция RFC iCalendar, которую реализует dateutil
, потому что dateutil
реализует RFC 2445 и не поддерживает все (или большинство) функций обновленного RFC 5545. Соответствующий раздел RFC 2445:
Правила повторения могут генерировать экземпляры повторения с недопустимой датой (например, 30 февраля) или несуществующим местным временем (например, 1:30 в день, когда местное время сдвинуто на час вперед в 1:00). Такие экземпляры повторения ДОЛЖНЫ игнорироваться и НЕ ДОЛЖНЫ учитываться как часть набора повторений.
Февраль отсутствует, потому что 2018-02-30
— недопустимая дата (на самом деле это пример, указанный в RFC).
Следует отметить, что этот запрос на вытягивание реализует нужные вам функции, но он (на момент написания этой статьи) в настоящее время заблокирован в ожидании поддержки 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
имеет поведение "откат назад в конце месяца", которое вы ищете. Чтобы быть на 100% безопасным, вы можете вместо этого выбрать bymonthday=1
, в данном случае это эквивалентно.
person
Paul
schedule
08.02.2018