даты правил сдвинуты на неделю

Я получаю неожиданный результат, используя модуль python-dateutil rrule, и мне интересно, не является ли это WAI.

Я динамически создаю rrule, используя:

dtstart = datetime.date(2019, 1, 7)
until = datetime.date(2029, 11, 29)
freq = MONTHLY
byweekday=MO(2)
interval = 4

Это приводит к следующему правилу

DTSTART:20190107T000000
RRULE:FREQ=MONTHLY;INTERVAL=4;UNTIL=20291129T000000;BYDAY=+2MO

Однако при генерации дат (зацикливая правило для этого модуля Python) я получаю следующие даты:

 [datetime.datetime(2019, 1, 14, 0, 0),
 datetime.datetime(2019, 5, 13, 0, 0),
 datetime.datetime(2019, 9, 9, 0, 0),
 datetime.datetime(2020, 1, 13, 0, 0),
 datetime.datetime(2020, 5, 11, 0, 0),
 datetime.datetime(2020, 9, 14, 0, 0),
 datetime.datetime(2021, 1, 11, 0, 0),
 datetime.datetime(2021, 5, 10, 0, 0),
 datetime.datetime(2021, 9, 13, 0, 0),
 datetime.datetime(2022, 1, 10, 0, 0),
 datetime.datetime(2022, 5, 9, 0, 0),
 datetime.datetime(2022, 9, 12, 0, 0),
 datetime.datetime(2023, 1, 9, 0, 0),
 datetime.datetime(2023, 5, 8, 0, 0),
 datetime.datetime(2023, 9, 11, 0, 0),
 datetime.datetime(2024, 1, 8, 0, 0),
 datetime.datetime(2024, 5, 13, 0, 0),
 datetime.datetime(2024, 9, 9, 0, 0),
 datetime.datetime(2025, 1, 13, 0, 0),
 datetime.datetime(2025, 5, 12, 0, 0),
 datetime.datetime(2025, 9, 8, 0, 0),
 datetime.datetime(2026, 1, 12, 0, 0),
 datetime.datetime(2026, 5, 11, 0, 0),
 datetime.datetime(2026, 9, 14, 0, 0),
 datetime.datetime(2027, 1, 11, 0, 0),
 datetime.datetime(2027, 5, 10, 0, 0),
 datetime.datetime(2027, 9, 13, 0, 0),
 datetime.datetime(2028, 1, 10, 0, 0),
 datetime.datetime(2028, 5, 8, 0, 0),
 datetime.datetime(2028, 9, 11, 0, 0),
 datetime.datetime(2029, 1, 8, 0, 0),
 datetime.datetime(2029, 5, 14, 0, 0),
 datetime.datetime(2029, 9, 10, 0, 0)]

Обратите внимание, что первая дата смещена на неделю! Почему это так? И это ошибка в библиотеке?

Спасибо, Дэвид


person David Ogutu    schedule 20.01.2019    source источник


Ответы (2)


Это не ошибка в библиотеке. 2019-01-14 – это первая дата, соответствующая вашему правилу (второй понедельник января 2019 года). По-видимому, python-dateutil решил не включать указанную вами дату начала, что совершенно законно.

RRULE указано в RFC 5545, в котором указано в Раздел 3.8.5.3 (в разделе "Описание"):

Набор повторений, сгенерированный со значением свойства "DTSTART", не синхронизированным с правилом повторения, не определен.

По сути, это означает, что нет правильной или неправильной интерпретации, потому что входные данные «сломаны», если дата начала не соответствует правилу.

Обратите внимание, что многие другие реализации, вероятно, вернут и дату начала 2019-01-07 и результат 2019-01-14. Я не думаю, что какая-либо реализация будет опускать 2019-01-14 просто потому, что это первая дата, соответствующая правилу. Можно спорить о том, должна ли быть в результатах дата начала 2019-01-07, но 2019-01-14 определенно должна быть там.

person Marten    schedule 29.01.2019
comment
Спасибо. Только что вернулся к этому. Понятно. Что я делал, так это просил второй понедельник, а не понедельник второй недели месяца. Как мне изменить свой запрос, чтобы запросить это? - person David Ogutu; 22.02.2019
comment
Какой второй понедельник? Ты имеешь в виду понедельник каждую неделю? Вот так FREQ=WEEKLY;INTERVAL=2;BYDAY=MO? - person Marten; 22.02.2019

В Python код by_weekly может быть реализован следующим образом.

from calendar import isleap

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

def bi_weekly(start_date=datetime.now(),count=53,interval=2):
    """
      dateTImeSart = bi_weekly(datetime.strptime('2021-01-01', '%Y-%m-%d'),53)
      print(dateTImeSart[0].strftime("%Y-%m-%d"))
      print(dateTImeSart[1].strftime("%Y-%m-%d"))
      print(dateTImeSart[50].strftime("%Y-%m-%d"))
      print(dateTImeSart[51].strftime("%Y-%m-%d"))
      print(dateTImeSart[52].strftime("%Y-%m-%d"))
      2021-01-01
      2021-01-15
      2022-12-02
      2022-12-16
      2022-12-30
    """
    # returns the datetime for an year and calculates them for 1 By weekly
    return list(rrule(WEEKLY, count=count,interval=interval, dtstart=start_date))
person Gautam    schedule 28.05.2021