Месяц после 31 января: календарный сдвиг и MonthEnd в pandas
Расписание платежей задаёт списание в последний день месяца. Для первого платежа 31 января прибавили тридцать дней и получили март. Затем заменили Timedelta на DateOffset(months=1), но последовательные прибавления начали давать 28-е число следующих месяцев. Это два разных правила календаря.
Timedelta описывает длительность, DateOffset(months=1) — календарный сдвиг с адаптацией к существующему дню. Если после февраля снова сдвигать уже полученное 28-е число, исходное намерение последнего дня месяца теряется. MonthEnd выражает именно привязку к концу месяца.
Как изменить решение
import pandas as pd
start = pd.Timestamp('2026-01-31')
feb = start + pd.DateOffset(months=1)
mar_drift = feb + pd.DateOffset(months=1)
schedule = [start + pd.offsets.MonthEnd(i) for i in range(3)]
assert str(mar_drift.date()) == '2026-03-28'
assert [str(x.date()) for x in schedule] == [
'2026-01-31', '2026-02-28', '2026-03-31']
print(mar_drift.date())
print([str(x.date()) for x in schedule])Календарный сдвиг от февральского результата дал 28 марта, а последовательность MonthEnd сохранила конец месяца. В високосном году февраль будет другим, но правило последнего дня останется тем же.
Сначала запишите правило расписания словами. Платёж каждое 15-е, каждые 30 суток и в последний день месяца — три разных договора. Для платежа в исходный день месяца лучше строить даты от первоначального якоря, а не от предыдущего результата: это позволяет избежать накопленного дрейфа после короткого месяца.
Что проверить на своих данных
Установите pandas командой python -m pip install pandas и запустите пример. Затем повторите с 31 января високосного года и с датой в середине месяца. У MonthEnd(0) есть важное поведение: середина месяца сдвигается к ближайшему концу текущего месяца, а уже последний день остаётся на месте.
Рабочий день и календарный конец месяца тоже не совпадают. Если списание переносится из выходного, храните плановую дату и фактическую дату переноса отдельно. Стандартный календарь будних дней не знает локальных государственных праздников, пока их явно не задали. Сначала постройте договорное расписание, затем примените правило переноса; так сверка сможет объяснить, почему февральский платёж оказался в марте.
Практика дальше
Календарное правило стоит закрепить вместе с остальной подготовкой таблиц. В тренажёре «NumPy и pandas» вы приводите даты к единому виду, считаете накопительные и скользящие показатели и собираете клиентский отчёт. Код проверяется автоматически в браузере.
Посмотреть программу и практику курса
Источник: Месяц после 31 января — официальная документация.
Другие задачи по теме: Календарь, пропуски и точность вычислений.
Продолжить на практике
- NumPy и pandas: практический тренажёр ↗
Бесплатный тренажёр NumPy и pandas для тех, кто знает основы Python. Научитесь очищать таблицы, объединять данные и собирать отчёты: 31 урок и 124 задачи с кодом и автоматической проверкой.
