03/04 — март или апрель: явный формат дат в pandas

Дата 03/04/2026 допустима, но может означать 3 апреля или 4 марта. Ошибка не вызывает исключения и перемещает продажи в другой месяц. Угадывание формата особенно опасно в регулярной выгрузке.

Договориться о представлении

Если источник использует день/месяц/год, задайте format="%d/%m/%Y". Тогда 13/04 и 03/04 читаются по одному правилу. Если форматы различаются, файл или строка должны сообщать, какой использован. Из неоднозначного текста нельзя восстановить намерение отправителя.

Явная спецификация лучше выражает строгий договор, чем надежда на эвристику dayfirst. Последовательный перебор форматов до первого успеха тоже не решает проблему: 03/04 успешно разберётся несколькими способами.

Сохранить причины NaT

31/04 является невозможной календарной датой. errors="coerce" позволяет собрать её в очередь, сохранив id и сырой текст. Пустое поле тоже станет NaT, но по другой причине. Различаем их до преобразования.

Месяц извлекаем уже из распознанной даты. Разрезать исходную строку и считать второй фрагмент месяцем означает закрепить неизвестный формат без календарной проверки.

import pandas as pd
x = pd.DataFrame({"id": [1, 2, 3, 4],
                  "date_raw": ["03/04/2026", "13/04/2026", "31/04/2026", ""]})
s = x["date_raw"].astype("string").str.strip()
missing = s.isna() | s.eq("")
x["date"] = pd.to_datetime(s.mask(missing), format="%d/%m/%Y", errors="coerce")
invalid = ~missing & x["date"].isna()
print(x.to_string(index=False))
assert x.loc[0, "date"] == pd.Timestamp("2026-04-03")
assert x.loc[1, "date"].month == 4
assert x.loc[invalid, "id"].tolist() == [3] and missing.sum() == 1

Первые две строки относятся к апрелю. Третья требует исправления даты, четвёртая — решения об обязательности поля. Если удалить их молча, объём отчёта изменится, а причина исчезнет.

От формата к диапазону поставки

Правильный формат ещё не гарантирует правильный период. Дата 03/04/2096 календарно допустима, но неожиданна для поставки 2026 года. После парсинга сравните диапазон и число строк по месяцу с ожидаемыми данными. Неожиданные даты сохраняйте для разбора.

Формат и часовой пояс — разные вопросы. Здесь используются даты без времени. Если приходит timestamp, после чтения отдельно определите пояс источника и бизнес-отчёта. Успех парсинга не гарантирует правильный календарный день региона.

При нескольких поставщиках сохраняйте поле источника и применяйте его известный формат. Перевод в общее представление выполняйте после чтения, чтобы последующие расчёты уже работали с датами, а не с вариантами записи.

В контрольном наборе держите неоднозначный день до двенадцати, однозначный день выше двенадцати, невозможную дату и пустоту. Такой набор проверяет смысл договора лучше, чем единственная аккуратная строка первого января. Сохраните его при изменении парсера: дата не должна менять месяц только из-за обновления логики загрузки.

Закрепить на практике

В бесплатном уроке временных столбцов вы отработаете парсинг, .dt и фильтрацию. Затем проверьте собственный формат на неоднозначных и невозможных датах из статьи. Откройте бесплатный урок и задачи. Полная последовательность тем — в бесплатном курсе.

Продолжить на практике

  • NumPy и pandas: практический тренажёр ↗

    Бесплатный тренажёр NumPy и pandas для тех, кто знает основы Python. Научитесь очищать таблицы, объединять данные и собирать отчёты: 31 урок и 124 задачи с кодом и автоматической проверкой.