strptime: строка превращается в дату
Лог, форма и таблица присылают даты строками — для вычислений нужен объект. Учим strptime читать строку по шаблону и отличать настоящий формат от почти настоящего.
Редакция Питоники
strftime переводил объект в строку — а в реальном коде чаще нужно наоборот: лог прислал «2026-10-21 09:15», форма — «21.10.2026», отчёт — «21 октября 2026». Пока дата — строка, из неё нельзя вычесть неделю или сравнить с сегодняшним днём. Обратный перевод делает метод strptime — «string parse time»: строка разбирается в объект.
Разбор по шаблону
У strptime два аргумента: строка и шаблон. Важно: метод принадлежит классу datetime, а не объекту, — вызывается через datetime.strptime(...). Коды шаблона у strptime те же, что у strftime, — меняется только направление: из полей объекта в строку или из строки в объект. Если в строке нет времени, часы, минуты и секунды станут нулями.
from datetime import datetime
day = datetime.strptime('21.10.2026', '%d.%m.%Y')
print(day)
stamp = datetime.strptime('2026-10-21 14:30', '%Y-%m-%d %H:%M')
print(stamp)
2026-10-21 00:00:00 2026-10-21 14:30:00
Оба результата — полноценные datetime: у них работают year, month, hour, поверх них — вся арифметика и сравнения из следующих уроков. Шаблон при этом должен совпадать со строкой символ в символ: коды — под числа, разделители — под разделители. Перепутанный порядок ловится по-разному: шаблон %m.%d.%Y для строки «21.10.2026» упадёт сразу — месяца 21 не бывает, а вот для «04.10.2026» пройдёт молча и даст 10 апреля вместо 4 октября. Python читает ровно по шаблону и никогда не угадывает; на этой ловушке стоит питфолл-блок ниже.
from datetime import datetime
start = datetime.strptime('2026-10-21 09:15', '%Y-%m-%d %H:%M')
end = datetime.strptime('2026-10-21 18:40', '%Y-%m-%d %H:%M')
print(start.date())
print(end - start)
2026-10-21 9:25:00
Две строки из лога превратились в объекты — и из них уже получилась длительность рабочего дня: 9:25:00. Разница дат — это timedelta, отдельный объект со своей арифметикой; урок 6 целиком про него. Пока важно другое: разбор строки — это дверь, через которую внешние данные попадают в мир вычислений с датами.
Когда формат не совпал: ValueError
from datetime import datetime
try:
datetime.strptime('21/10/2026', '%d.%m.%Y')
except ValueError as err:
print('Ошибка:', err)
try:
datetime.strptime('21.10.2026 лишнее', '%d.%m.%Y')
except ValueError as err:
print('Ошибка:', err)
Ошибка: time data '21/10/2026' does not match format '%d.%m.%Y' Ошибка: unconverted data remains: лишнее
Два типовых сообщения. Первое, «time data ... does not match format ...», — строка не подходит под шаблон: в логе дефисы, в шаблоне точки, или порядок чисел другой. Второе, «unconverted data remains ...», — шаблон разобрал начало строки, а на хвосте остались символы, которых шаблон не описывает: после двоеточия в сообщении стоит лишний кусок с пробелом. Обе ошибки — ValueError, и обе лечатся одинаково: шаблон приводится в точное соответствие строке.
Пара strftime и strptime закрывает обе дороги между объектами и строками: наружу — для людей, внутрь — для вычислений. Дальше по курсу: урок 6 — timedelta и разница между моментами, тот самый 9:25:00 из лога; урок 10 — isoformat: стандартный формат, который парсится одной строкой и без шаблона вовсе.
Разбор пачки строк: лог, в котором одна строка битая
В одиночном разборе всё выглядит просто: дал строку — получил объект. Жизнь начинается, когда строк много и среди них попадаются неправильные. Лог приходит из чужой системы, и в нём встречается всё: обрезанная строка, другой разделитель, пустая строка в середине файла. Если разбирать каждую строку без try/except, первый же битый элемент уронит весь разбор — а вместе с ним весь отчёт, ради которого вы всё это затевали.
from datetime import datetime
lines = ['2026-10-21 09:00', '2026-10-22 11:30', 'битая строка']
for line in lines:
try:
moment = datetime.strptime(line, '%Y-%m-%d %H:%M')
except ValueError:
print(line, '->', 'не разобралась')
else:
print(line, '->', moment)
2026-10-21 09:00 -> 2026-10-21 09:00:00 2026-10-22 11:30 -> 2026-10-22 11:30:00 битая строка -> не разобралась
Ветка else существует не для красоты. Она отделяет успешный разбор от неуспешного и даёт вам выбор: залогировать битую строку и посчитать их количество, или молча пропустить. В рабочих проектах мы всегда считаем: если из десяти тысяч строк не разобрались три, это повод разбираться, а не повод молчать. Молчаливый пропуск превращает пропуск данных в неверный отчёт, который заметят уже наверху.
Пробелы, которые никто не видит
Отдельная боль — невидимые символы. CSV-экспорт часто оставляет в начале строки пробел или неразрывный пробел, лог добавляет отступы при выравнивании. Для глаза строка выглядит нормальной, а strptime честно падает с ValueError: разбор идёт посимвольно, и лишний пробел не совпал с ожидаемым. Лечится это либо strip() перед разбором, либо пробелом в шаблоне — %Y-%m-%d %H:%M с конкретным пробелом в ожидаемом месте.
from datetime import datetime
raw = ' 2026-10-21'
try:
print(datetime.strptime(raw, '%Y-%m-%d'))
except ValueError:
print('лишний пробел')
print(datetime.strptime(raw.strip(), '%Y-%m-%d'))
лишний пробел 2026-10-21 00:00:00
Strip перед разбором — привычка, которая стоит завести один раз и забыть. Мы вызываем его на каждой строке из внешнего источника, потому что цена одного вызова — микросекунды, а цена пропущенной строки — неверный отчёт. Исключение одно: если в данных гарантированно нет мусора и формат жёсткий, strip() можно опустить — мы так делаем в hot-loop на миллионе строк, где лишний проход по строке уже заметен.
from datetime import datetime
october = datetime.strptime('05.10.2026', '%d.%m.%Y')
print(october)
print(october.month)
print(october.day)
2026-10-05 00:00:00 10 5
Кстати, тот же приём сработает и наоборот: если вы знаете, что в логе приходит именно «05.10.2026», а разбор даёт пятое мая — дело в шаблоне, а не в данных. Отладка здесь занимает минуту: напечатайте месяц и день отдельно, и перепутать их невозможно.
Разбор даты, которая не в том формате: как понять, что именно сломалось
Самый частый сценарий: текст пришёл из внешнего источника, формат в нём другой, и strptime бросает ValueError. Сообщение об ошибке всегда содержит обе стороны — и строку, и шаблон: «time data '21/10/2026' does not match format '%d.%m.%Y'». Это уже половина разбора: сразу видно, что в строке слэши, а в шаблоне точки, и остаётся только решить, какую сторону менять.
Дальше полезно сузить область поиска. Чаще всего разбор спотыкается об один символ: лишний пробел в начале строки, неразрывный пробел вместо обычного, дефис вместо точки, или число, записанное с буквой. Печатать исходную строку с невидимыми символами — плохая идея, они не покажутся; вместо этого удобно напечатать repr(line), и невидимые символы станут видны как \u00a0 или \t. Ещё один приём — сравнить длины строки и результата разбора: если результат короче, потерялось что-то в конце, и это уже второй случай, unconverted data remains.
И третий приём, когда формат заранее неизвестен: собрать кандидатов и попробовать каждый, а не гадать. Список шаблонов в порядке убывания вероятности, обход по нему с try/except даёт работающий парсер там, где угадывание не работает никогда. Порядок в списке важен: более строгий шаблон должен стоять раньше, иначе строка разберётся не тем шаблоном и потеряет часть данных.
from datetime import datetime
FORMATS = ('%d.%m.%Y %H:%M', '%Y-%m-%d', '%d.%m.%Y')
def parse_any(text):
for fmt in FORMATS:
try:
return datetime.strptime(text, fmt)
except ValueError:
continue
return None
for line in ['21.10.2026 14:30', '2026-10-21', '21.10.2026', 'не дата']:
print(line, '->', parse_any(line))
21.10.2026 14:30 -> 2026-10-21 14:30:00 2026-10-21 -> 2026-10-21 00:00:00 21.10.2026 -> 2026-10-21 00:00:00 не дата -> None
Функция возвращает None на неудачу, и это осознанный выбор: вызывающий код сам решает, что делать со строкой, которую разобрать не вышло, — посчитать их, залогировать или пропустить. Бросать исключение из такой функции — значит заставлять каждого вызывающего писать свой try/except, а забытый обработчик уронит разбор целиком, как мы разбирали выше.
Сначала предскажи ответ в голове — это главный навык программиста.
from datetime import datetime
d = datetime.strptime('15.01.2027', '%d.%m.%Y')
print(d.year, d.month)
from datetime import datetime
stamp = datetime.strptime('2026-10-21 14:30', '%Y-%m-%d %H:%M')
print(stamp)
from datetime import datetime
start = datetime.strptime('2026-10-21 09:00', '%Y-%m-%d %H:%M')
end = datetime.strptime('2026-10-21 11:30', '%Y-%m-%d %H:%M')
print(end - start)
from datetime import datetime
lines = ['2026-10-21 09:00', 'битая строка']
for line in lines:
try:
moment = datetime.strptime(line, '%Y-%m-%d %H:%M')
except ValueError:
print(line, '->', 'не разобралась')
else:
print(line, '->', moment)
1. Что вернёт datetime.strptime('21.10.2026', '%d.%m.%Y')?
2. Чем шаблон strptime отличается от шаблона strftime?
3. Какая ошибка будет при datetime.strptime('21/10/2026', '%d.%m.%Y')?
4. Строка '04.10.2026' разобрана шаблоном '%m.%d.%Y'. Какая это дата?
5. Что означает сообщение «unconverted data remains: лишнее»?
6. Что произойдёт при datetime.strptime(' 2026-10-21', '%Y-%m-%d')?
7. Зачем при разборе списка строк оборачивать strptime в try/except?
8. Что даст разбор строки '05.10.2026' шаблоном '%m.%d.%Y'?
Разбери две строки из журнала: '15.01.2027 08:00' (начало) и '15.01.2027 16:30' (конец). Выведи оба объекта datetime, а затем дату начала отдельно методом .date().
Как преобразовать строку в дату в Python?
Методом datetime.strptime(строка, шаблон): datetime.strptime('21.10.2026', '%d.%m.%Y') вернёт объект datetime. Шаблон собирается из кодов %d, %m, %Y и других и должен совпадать со строкой символ в символ.
Урок 5: strptimeПочему strptime выдаёт ValueError?
Самая частая причина — строка не совпадает с шаблоном: другие разделители, другой порядок чисел или лишний хвост. Сообщения различаются: «time data ... does not match format ...» — полное несовпадение, «unconverted data remains ...» — шаблон разобрал начало, а конец строки остался неописанным.
Чем strptime отличается от strftime?
Направлением: strftime переводит объект datetime в строку по шаблону, strptime — строку в объект datetime. Коды форматирования одни и те же, пара закрывает обе стороны работы с датами.
Урок 4: strftimeКак разобрать дату из лог-файла?
Вырезать из строки часть с датой и прогнать через strptime с шаблоном, повторяющим формат лога: для «2026-10-21 09:15» это '%Y-%m-%d %H:%M'. Из двух разобранных штампов уже можно получить длительность события вычитанием.
Урок 19: даты в логахПочему strptime падает на строке с пробелом в начале?
Разбор идёт посимвольно: пробел не совпадает ни с одним кодом шаблона, и strptime честно сообщает об этом через ValueError. Перед разбором вызывайте strip() — тогда лишние пробелы и неразрывные пробелы не попадут в результат.
Как разобрать список дат, в котором часть строк может быть битой?
Оберните strptime в try/except ValueError прямо в цикле: успешные строки собирайте в список, неудачные считайте и логируйте. Так разбор не прервётся на первой проблеме, а вы увидите масштаб проблемы. Подробный разбор логов — в уроке 19.
Урок 19: даты в логахПонравился урок? Сошлитесь на него
«Коды шаблона у strptime те же, что у strftime, — меняется только направление: из полей объекта в строку или из строки в объект.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Datetime · Урок 4
strftime: дата превращается в строку
Объект даты хорош для вычислений, а человеку нужна строка «21.10.2026». Один метод strftime и горстка кодов — и дата принимает любой вид.
Datetime · Урок 6
timedelta: разница между моментами
«Срок подписки истекает через 7 дней», «событие было 3 часа назад» — за этим стоит timedelta. Вычитаем моменты, читаем дни и секунды, прибавляем разницу к датам.
Datetime · Урок 10
isoformat и fromisoformat: ISO-даты
Один вызов — и datetime превращается в строку 2026-10-21T14:30:45. ISO-формат сортируется как текст, а fromisoformat читает его обратно без единого кода %.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
openpyxl · Урок 9
Даты в Excel через openpyxl: запись, формат и арифметика
Пишем в ячейку настоящий datetime, показываем его по-русски маской DD.MM.YYYY и считаем дни между датами — а заодно узнаём, почему дату из файла нельзя сравнивать со строкой.
openpyxl датыopenpyxl datetime
Строки · Урок 9
split: разобрать строку
Одна строка данных редко живёт одна: CSV-запись, строка лога, поля формы. Метод split режет строку по разделителю и возвращает список частей — разбираем все варианты, от запятой до splitlines.
python разбить строкуpython разделить строку по запятой
Datetime · Урок 19
Даты в логах: разбор реального формата
Журнал из строк вида «2026-10-21 09:15:03 ERROR …»: разбираем момент через strptime, сортируем события по времени и вырезаем записи за интервал.
парсинг дат логов pythonpython разобрать дату из лога