Даты в Pandas: to_datetime
Столбец дат приезжает из выгрузки строками — pd.to_datetime делает его настоящими датами, после чего работают dt.year, dt.month, фильтры по периоду и сортировка по времени.
Редакция Питоники
Восемнадцать уроков курса работали с одной датой за раз. Реальные данные — это столбцы: тысяча заказов с датами из выгрузки, таблица визитов, журнал платежей. Для столбцов в курсе есть отдельный инструмент — pandas, и у его дат своё правило номер один: пока не сказано обратное, дата в таблице — это строка. Урок опирается на strptime и коды формата из уроков 4–5, но в pandas всё делается одним вызовом.
Если pandas ещё не знаком — не страшно: здесь нужны четыре приёма, и каждый запускается прямо на этой странице. Пишете import pandas as pd — библиотека ставится в песочницу автоматически при первом импорте.
import pandas as pd
df = pd.DataFrame({
'order': [104, 101, 107, 102],
'date': ['2026-10-12', '2026-09-28', '2026-10-05', '2026-10-01'],
'total': [3200, 4990, 12500, 8800],
})
print(df)
print(type(df['date'][0]).__name__)
order date total 0 104 2026-10-12 3200 1 101 2026-09-28 4990 2 107 2026-10-05 12500 3 102 2026-10-01 8800 str
Четыре заказа, даты не по порядку. В последней строке — проверка: type(df['date'][0]).__name__ печатает str, то есть первый элемент столбца — обычная Python-строка. В выгрузке из CSV было бы то же самое. Строки с датами отсортировались бы по алфавиту, из них нельзя вычесть неделю и не спросить у них месяц по-человечески. Чинится одним вызовом:
import pandas as pd
df = pd.DataFrame({
'order': [104, 101, 107, 102],
'date': ['2026-10-12', '2026-09-28', '2026-10-05', '2026-10-01'],
'total': [3200, 4990, 12500, 8800],
})
df['date'] = pd.to_datetime(df['date'])
print(df)
print(type(df['date'][0]).__name__)
order date total 0 104 2026-10-12 3200 1 101 2026-09-28 4990 2 107 2026-10-05 12500 3 102 2026-10-01 8800 Timestamp
Тот же print(df), но первый элемент столбца теперь Timestamp — класс pandas, прямой наследник знакомого datetime из первого урока. Столбец целиком перешёл на тип datetime64: печатаются даты в том же международном виде, зато внутри это настоящие моменты времени. Дома тип столбца видно через df.dtypes — там появится строка вида datetime64[ns] или datetime64[us]; буквы в скобках — единица хранения, разные у версий pandas, на приёмы этого урока они не влияют.
dt.year и dt.month: части дат из столбца
У одиночного datetime месяц доставляло поле .month из урока про классы дат. У столбца вместо поля — dt-аксессуар: df['date'].dt.month — сразу месяц каждой строки:
import pandas as pd
df = pd.DataFrame({
'order': [104, 101, 107, 102],
'date': ['2026-10-12', '2026-09-28', '2026-10-05', '2026-10-01'],
'total': [3200, 4990, 12500, 8800],
})
df['date'] = pd.to_datetime(df['date'])
df['month'] = df['date'].dt.month
print(df[['order', 'month']])
order month 0 104 10 1 101 9 2 107 10 3 102 10
dt работает и с .year, и с .day, и со всем набором полей datetime. Новый столбец month готов к группировке: выручка по месяцам — это df.groupby('month'), знакомое по курсу pandas.
Фильтр по периоду
Зачем всё это — самый частый ответ: выбрать заказы за период. Фильтр по дате в pandas выглядит как сравнение с текстом, но работает как сравнение с датой:
import pandas as pd
df = pd.DataFrame({
'order': [104, 101, 107, 102],
'date': ['2026-10-12', '2026-09-28', '2026-10-05', '2026-10-01'],
'total': [3200, 4990, 12500, 8800],
})
df['date'] = pd.to_datetime(df['date'])
recent = df[df['date'] > '2026-10-01']
print(recent)
order date total 0 104 2026-10-12 3200 2 107 2026-10-05 12500
Справа строка '2026-10-01', слева — столбец Timestamp, и pandas приводит строку к дате сам: из четырёх заказов остались два, строго после первого октября, а сам 1 октября в выборку не попал — сравнение строгое. Диапазон задаётся двумя условиями через &: df[(df['date'] >= '2026-10-01') & (df['date'] <= '2026-10-31')].
Сортировка по дате
Последний штрих — вернуть таблице хронологию. sort_values по столбцу дат упорядочивает строки по времени, а не по алфавиту:
import pandas as pd
df = pd.DataFrame({
'order': [104, 101, 107, 102],
'date': ['2026-10-12', '2026-09-28', '2026-10-05', '2026-10-01'],
'total': [3200, 4990, 12500, 8800],
})
df['date'] = pd.to_datetime(df['date'])
df = df.sort_values('date')
print(df)
order date total 1 101 2026-09-28 4990 3 102 2026-10-01 8800 2 107 2026-10-05 12500 0 104 2026-10-12 3200
Строки выстроились с 28 сентября по 12 октября. Обратите внимание на левый столбец: метки 1, 3, 2, 0 — это исходные индексы строк, они едут вместе со строками. Вернуть аккуратную нумерацию можно цепочкой .reset_index(drop=True) — так делают почти всегда, если индекс не несёт смысла.
Что дальше
Таблица — не единственный источник дат-строк. Второй по частоте — логи: каждая строка начинается с момента в формате «2026-10-21 09:15:03», и его предстоит разобрать, отсортировать и отфильтровать по интервалу. Это следующий урок — даты в логах, последний перед финальным проектом.
Фильтр по дате в pandas выглядит как сравнение с текстом, но работает как сравнение с датой.
Грязный столбец: что делать с битыми строками
Выгрузки редко бывают чистыми. Где-то в середине тысячи строк обязательно найдётся пустая ячейка, где-то — дата в чужом формате, а где-то — опечатка. Поведение pandas на такое по умолчанию неприятное: он не пропустит строку молча, а уронит всё вычисление. Для одиночной строки это честно, для столбца — дорого.
import pandas as pd
df = pd.DataFrame({'d': ['2026-10-21', 'битая', '2026-11-02']})
df['d'] = pd.to_datetime(df['d'], errors='coerce')
print(df['d'].isna().sum())
print(df['d'].notna().sum())
1 2
Аргумент errors='coerce' меняет стратегию: вместо исключения нераспознанная строка превращается в NaT — пустое значение даты. Обратите внимание на асимметрию: isna() отвечает про исходную строку и даёт 1, а notna() — про распознанные даты и даёт 2. Одна битая строка из трёх не исчезает бесследно: она превращается в NaT, который можно посчитать, отфильтровать и показать в отчёте.
import pandas as pd
df = pd.DataFrame({'d': ['2026-10-21', 'битая', '2026-11-02']})
df['d'] = pd.to_datetime(df['d'], errors='coerce')
print(df['d'].dt.month.tolist())
[10.0, nan, 11.0]
Вот тонкость, на которой спотыкаются почти все: dt-аксессор работает и по NaT, но вместо числа для пустой ячейки выдаёт nan. Тип столбца меняется на float, и целые месяцы превращаются в 10.0, а пропуск виден как nan. Это не поломка — это честное отражение того, что в столбце есть дырка. Сравнивать такие значения с обычными числами надо осторожно: nan не равно ничему, даже самому себе.
Формат, который pandas не угадает
ISO-строки pandas разбирает сам, и это спасает в девяти случаях из десяти. Но русская выгрузка с датами вида «21.10.2026» — это уже не ISO, и тут угадывать нечего: тот же набор цифр «04.10.2026» может значить и 4 октября, и 10 апреля. Модуль datetime в уроке 5 требует явный шаблон, и pandas ведёт себя так же.
import pandas as pd
df = pd.DataFrame({'d': ['21.10.2026', '01.11.2026']})
df['d'] = pd.to_datetime(df['d'], format='%d.%m.%Y')
print(df['d'].dt.strftime('%d.%m.%Y').tolist())
['21.10.2026', '01.11.2026']
С явным format='%d.%m.%Y' порядок дней и месяцев задаётся раз и навсегда, и две даты разбираются так, как их записал человек. Тот же столбец без format pandas читает по своим правилам — и на «04.10.2026» даст 10 апреля, потому что по умолчанию в нём американский порядок месяца и дня. Ни ошибки, ни предупреждения: просто другая дата.
import pandas as pd
s = pd.to_datetime(['04.10.2026'], dayfirst=True)
print(s[0].month, s[0].day)
10 4
Аргумент dayfirst=True переключает приоритет: первым читается день, вторым месяц. Это спасательный круг для европейских выгрузок, где формат не указан, но все даты написаны в одном стиле. Но мы его не используем: dayfirst — это предположение о данных, а format='%d.%m.%Y' — это утверждение. Первое может внезапно перестать работать, второе выскажет себя сразу на первой неоднозначной дате.
От unix-времени к датам
В API и базах даты часто приходят числами — тем самым unix-временем из урока 13. У pandas для этого есть аргумент unit: он говорит, в каких единицах лежат числа, и делает то же, что деление на 1000, но сразу и правильно.
import pandas as pd
df = pd.DataFrame({'ts': [1792593045, 1792582200]})
df['when'] = pd.to_datetime(df['ts'], unit='s')
print(df['when'].dt.strftime('%d.%m.%Y %H:%M:%S').tolist())
['21.10.2026 14:30:45', '21.10.2026 11:30:00']
Единицы бывают разные: unit='s' — секунды, unit='ms' — миллисекунды, unit='D' — дни. Ошибка в выборе единицы не выглядит как ошибка: миллисекунды, прочитанные как секунды, дают дату в 1970 году с номерами тысяч. Мы всегда сверяем результат с ожидаемым диапазоном: если столбец дат вдруг оказался в 1970-м, первое, что стоит проверить, — единицы измерения.
Группировка: месяцы вместо дней
Столбец дат — это готовый признак для группировки. Чтобы узнать выручку по месяцам, не нужно ни циклов, ни словарей: достаточно добавить столбец с номером месяца и позвать groupby.
import pandas as pd
df = pd.DataFrame({
'd': pd.to_datetime(['2026-09-28', '2026-10-12', '2026-10-20']),
'v': [10, 20, 30],
})
df['m'] = df['d'].dt.month
print(df.groupby('m')['v'].sum().to_dict())
{9: 10, 10: 50}Сентябрь дал 10, октябрь — 50: две продажи в октябре сложились вместе. Ключ группировки — номер месяца, целое число, поэтому результат приходит словарём и печатается без лишних танцев с индексами. Заметьте: если в данных есть даты из разных годов, группировка по одному месяцу их смешает — тогда нужен ключ из года и месяца, а это уже отдельная тема урока про временные ряды.
| Задача | Вызов | Что получится |
|---|---|---|
| Месяц каждой строки | df['d'].dt.month | 10, 9, 10 — целые числа |
| День недели (0 — пн) | df['d'].dt.weekday | 2, 5 — как в datetime |
| Имя дня недели | df['d'].dt.day_name() | Wednesday, Saturday — по-английски |
| Номер квартала | df['d'].dt.quarter | 4, 1 |
| Неделя года по ISO | df['d'].dt.isocalendar().week | 43, 1 |
| Первый день месяца | df['d'].dt.is_month_start | True, False |
| Дата без времени | df['d'].dt.normalize() | полночь той же даты |
| Сумма по месяцам | df.groupby(df['d'].dt.month)['v'].sum() | словарь {месяц: сумма} |
Восемь строк, которые закрывают почти весь бытовой анализ по датам. Заметим две особенности. Первая: day_name() даёт английские названия — Wednesday, Saturday, — потому что локаль pandas по умолчанию не переключается; русские дни недели придётся приклеивать словарём, как в уроке про русские даты. Вторая: isocalendar().week считает недели по стандарту ISO, где первая неделя года та, что содержит 4 января, — из-за этого номер недели в начале года меньше, чем кажется интуитивно.
import pandas as pd
df = pd.DataFrame({'d': pd.to_datetime(['2026-10-01', '2026-10-21', '2026-11-02'])})
m = df[df['d'].between('2026-10-01', '2026-10-31')]
print(len(m))
2
between() удобнее цепочки из двух сравнений с &: он же и короче, и понятнее. Границы включаются в диапазон с обеих сторон, а задавать их можно строками в ISO — pandas сам приведёт их к датам, ровно как в фильтре из начала урока. Единственное, что стоит запомнить: between() не принимает разные форматы в одной границе, поэтому «2026-10-01» и «31.10.2026» лучше не смешивать.
import pandas as pd
df = pd.DataFrame({'d': pd.to_datetime(['2026-10-12', '2026-09-28'])})
out = df.sort_values('d').reset_index(drop=True)
print(out['d'].dt.strftime('%d.%m.%Y').tolist())
['28.09.2026', '12.10.2026']
Две даты встали в хронологию, а метки снова 0 и 1. Мелочь, но без неё следующий кусок кода, который скажет df.loc[0, 'total'], возьмёт не ту строку — молча, без всякой ошибки. Мы добавляем reset_index(drop=True) после каждой сортировки, если индекс не несёт смысла.
Сначала предскажи ответ в голове — это главный навык программиста.
import pandas as pd
s = pd.to_datetime('2026-10-21')
print(s.year, s.month)
import pandas as pd
df = pd.DataFrame({'d': pd.to_datetime(['2026-01-15', '2026-03-02'])})
print(df['d'].dt.month.tolist())
import pandas as pd
df = pd.DataFrame({'d': pd.to_datetime(['2026-09-28', '2026-10-12'])})
print(len(df[df['d'] > '2026-10-01']))
import pandas as pd
df = pd.DataFrame({'d': ['2026-10-21', 'битая', '2026-11-02']})
df['d'] = pd.to_datetime(df['d'], errors='coerce')
print(df['d'].isna().sum())
import pandas as pd
df = pd.DataFrame({
'd': pd.to_datetime(['2026-09-28', '2026-10-12', '2026-10-20']),
'v': [10, 20, 30],
})
df['m'] = df['d'].dt.month
print(df.groupby('m')['v'].sum().to_dict())
1. Что делает pd.to_datetime(df['date'])?
2. Как получить месяц каждой строки столбца с датами?
3. Почему фильтр df[df['date'] > '2026-10-01'] корректен, если справа строка?
4. После df.sort_values('date') в левом столбце таблицы оказались метки 1, 3, 2, 0. Что это?
5. Что вернёт type(df['date'][0]).__name__ после вызова pd.to_datetime(df['date'])?
6. Что делает аргумент errors='coerce' при разборе дат?
7. Что произойдёт с pd.to_datetime(['04.10.2026']) без format и без dayfirst?
8. Зачем при разборе unix-времени в pandas указывать unit?
9. Что даст df['d'].dt.month для столбца, где одна строка не распозналась и стала NaT?
Таблица визитов трёх клиентов пришла со строками-датами. Приведите столбец visit к датам, добавьте столбец month с номером месяца, выведите фамилии клиентов в хронологии визитов списком, затем фамилии октябрьских визитов (строго после 1 октября) и список номеров месяцев. Три списка, каждый на своей строке.
Как превратить столбец строк в даты в pandas?
Одним вызовом: df['date'] = pd.to_datetime(df['date']). Для ISO-строк вида 2026-10-12 формат угадывается сам; для форматов вида 12.10.2026 передайте format='%d.%m.%Y', иначе день и месяц перепутаются. После приведения у столбца работает dt-аксессуар, а фильтры и сортировки считаются по календарю.
Урок 18: даты в PandasПочему df['date'].dt.month выдаёт ошибку AttributeError?
dt-аксессуар работает только над столбцами с типом дат (datetime64). Если столбец остался строковым — pandas не привёл его сам, вызовите сначала df['date'] = pd.to_datetime(df['date']). Ошибка так и говорит: Can only use .dt accessor with datetimelike values.
Как отфильтровать DataFrame по диапазону дат?
Двумя условиями через &: df[(df['date'] >= '2026-10-01') & (df['date'] <= '2026-10-31')]. Границы можно писать строками в ISO-формате «ГГГГ-ММ-ДД» — pandas приводит их к датам сам. Скобки вокруг каждого условия обязательны: у сравнений приоритет выше, чем у &.
Чем Timestamp отличается от datetime в Python?
Timestamp — класс pandas для отдельного значения даты-времени, построенный поверх datetime из стандартной библиотеки: у него те же поля year, month, day и методы strftime, плюс работа с индексами и столбцами. В коде pandas значения столбцов дат — это Timestamp, а тип всего столбца в df.dtypes пишется как datetime64.
Что делать, если в столбце дат есть битые строки?
Разбирать с errors='coerce': нераспознанные строки превращаются в NaT, а не роняют всё вычисление. Но потеря становится тихой, поэтому сразу после разбора считайте df['d'].isna().sum() и печатайте это число в лог — если из тысячи строк не распознались три, это повод разбираться.
Урок 18: даты в PandasКак разобрать в pandas даты в русском формате 21.10.2026?
Укажите шаблон явно: df['d'] = pd.to_datetime(df['d'], format='%d.%m.%Y'). Без format pandas читает «04.10.2026» по своему умолчанию — месяц первым — и даёт 10 апреля, не сообщив об этом ни ошибкой, ни предупреждением.
Как превратить столбец unix-времени в даты в pandas?
Аргументом unit: df['when'] = pd.to_datetime(df['ts'], unit='s') для секунд, unit='ms' для миллисекунд. Единицу надо называть явно: миллисекунды, прочитанные как секунды, дадут даты 1970 года, и ошибка не выглядит как ошибка.
Как посчитать сумму по месяцам в pandas?
Добавьте столбец с номером месяца и сгруппируйте: df['m'] = df['d'].dt.month, затем df.groupby('m')['v'].sum(). Номер месяца — целое число, поэтому результат приходит словарём вида {9: 10, 10: 50}. Если в данных есть разные годы, группируйте по паре год-месяц.
Понравился урок? Сошлитесь на него
«Фильтр по дате в pandas выглядит как сравнение с текстом, но работает как сравнение с датой.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Datetime · Урок 17
Рабочие дни: будни без выходных
Перебираем даты циклом с timedelta, отсекаем выходные условием weekday() < 5 и отвечаем на два вопроса планировщика: сколько будней между датами и на какое число выпадает срок через N рабочих дней.
Datetime · Урок 19
Даты в логах: разбор реального формата
Журнал из строк вида «2026-10-21 09:15:03 ERROR …»: разбираем момент через strptime, сортируем события по времени и вырезаем записи за интервал.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Pandas · Урок 9
Даты и временные ряды в Pandas: resample и rolling
Строки «01.07.2024» превращаются в настоящие даты, выручка агрегируется по неделям и месяцам через resample, а шум сглаживает rolling — строим тренд продаж магазина.
временные ряды pandasдаты и время в pandas to_datetime примеры
Seaborn · Урок 19
Seaborn и Pandas DataFrame: таблица как источник графиков
Seaborn ест DataFrame напрямую, но красивый график начинается до него: groupby, melt из широкого формата в длинный, настоящие даты и правильный порядок категорий.
seaborn pandas dataframeseaborn даты на оси
Datetime · Урок 10
isoformat и fromisoformat: ISO-даты
Один вызов — и datetime превращается в строку 2026-10-21T14:30:45. ISO-формат сортируется как текст, а fromisoformat читает его обратно без единого кода %.
python дата в строку isoпарсинг даты python