isoformat и fromisoformat: ISO-даты
Один вызов — и datetime превращается в строку 2026-10-21T14:30:45. ISO-формат сортируется как текст, а fromisoformat читает его обратно без единого кода %.
Редакция Питоники
После шпаргалки кодов кажется, что любую дату в строку превращают шаблонами. Для хранения и передачи данных есть путь короче — международный стандарт ISO 8601 и метод isoformat, которому не нужен ни один код с процентом. Шпаргалка кодов пригодится, когда формат диктует человек, — в письме, в отчёте, в интерфейсе; в остальных случаях стандартный формат и надёжнее, и короче. Разница между ISO-строкой и привычной датой видна в первом же сравнении — об этом урок 7.
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30, 45)
print(d.isoformat())
print(d.date().isoformat())
print(d.isoformat(sep=' '))
2026-10-21T14:30:45 2026-10-21 2026-10-21 14:30:45
Буква T между датой и временем — разделитель по стандарту ISO 8601. isoformat всегда дополняет поля нулями: у datetime(2026, 10, 21, 9, 5) строка будет 2026-10-21T09:05:00 — с нулём перед девяткой и с секундами. Вызов d.date().isoformat() оставляет только календарный день без времени, а именованный аргумент sep заменяет T на любой символ: со строкой-пробелом вывод выглядит точно так же, как print(d).
Почему ISO-строки удобно сортировать
В ISO-формате поля идут от старшего к младшему: год, месяц, день, часы, минуты. Поэтому обычная строковая сортировка расставляет такие строки хронологически — не нужно парсить даты, чтобы упорядочить журнал событий или имена файлов с датами в названии. С форматом 21.10.2026 этот номер не прошёл бы: строковая сортировка поставила бы 21.09.2026 раньше 05.10.2026, потому что сравнение идёт слева направо и день важнее месяца. ISO-формат придуман так, чтобы текст и время совпадали.
stamps = ['2026-10-21', '2026-01-05', '2026-12-31', '2026-03-08']
print(sorted(stamps))
['2026-01-05', '2026-03-08', '2026-10-21', '2026-12-31']
fromisoformat: строка обратно в datetime
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30, 45)
stamp = d.isoformat()
print(stamp)
restored = datetime.fromisoformat(stamp)
print(restored)
print(restored == d)
2026-10-21T14:30:45 2026-10-21 14:30:45 True
Круговая поездка честная: isoformat собрал строку, fromisoformat разобрал её обратно, и restored равен исходному d. Никакой пары «шаблон плюс данные», как в strftime, — метод узнаёт собственный формат сам, поэтому datetime.fromisoformat(d.isoformat()) можно писать не задумываясь.
from datetime import datetime
d = datetime.fromisoformat('2026-10-21')
print(d)
print(repr(d))
2026-10-21 00:00:00 datetime.datetime(2026, 10, 21, 0, 0)
isoformat закрывает хранение и передачу дат. Следующая остановка — сборка datetime из частей: combine склеивает date и time, а replace точечно меняет поля готового объекта.
Где ISO-формат работает лучше всего
Главное достоинство ISO-строки видно не в теории, а в API. Объект datetime в JSON не положишь — json.dumps на нём падает с TypeError: Object of type datetime is not JSON serializable. Два выхода: превращать дату в строку заранее или научить json.dumps её обрабатывать. Первый путь честнее: вы решаете, в каком виде дата уйдёт наружу, и не зависите от того, как сериализатор решил её представить.
import json
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30)
payload = {'deal': 'поставка', 'at': d.isoformat()}
print(payload['at'])
print(json.dumps(payload, ensure_ascii=False))
2026-10-21T14:30:00
{"deal": "поставка", "at": "2026-10-21T14:30:00"}Второе место, где ISO незаменим, — базы данных. Колонка TIMESTAMP в PostgreSQL и MySQL принимает ровно этот формат, а не «21.10.2026 14:30». Когда мы перестаём писать даты в базу через strftime с русским шаблоном, уходят целые классы ошибок: разделители, разная точность, несовпадение с тем, что потом читает другой сервис. Кто-то наверняка скажет, что база сама умеет принимать даты в куче форматов, — да, но зачем полагаться на это, если есть один формат, который понимают все?
Часовой пояс внутри ISO-строки
У осознанного момента, у которого задан часовой пояс, ISO-строка заканчивается смещением: +03:00 вместо голого времени. Это важное отличие: строка 2026-10-21T14:30:00 говорит «полдень по чьим-то часам», а 2026-10-21T14:30:00+03:00 говорит «полдень по московскому времени» — и это уже можно сравнивать с другой такой же строкой из другого пояса. Подробнее про зоны и про naive-объекты — в уроке 14.
from datetime import datetime, timedelta, timezone
msk = timezone(timedelta(hours=3))
moment = datetime(2026, 10, 21, 14, 30, tzinfo=msk)
print(moment.isoformat())
2026-10-21T14:30:00+03:00
Важно: смещение здесь фиксированное и не зависит от машины, на которой запущен код: мы явно сказали «плюс три часа». Никакой локальной зоны, никакой зависимости от настроек сервера. Если бы мы пользовались now() без явной зоны, строка получилась бы без смещения, и её нельзя было бы сравнить с датой из другого источника.
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30)
try:
print(d < '2026-10-21')
except TypeError:
print('объект и строка несравнимы')
объект и строка несравнимы
Круговая поездка и её границы
Строку, полученную через isoformat, можно разобрать обратно — и это уже настоящая проверка: если строка не читается, значит, формат потерял информацию. Но у fromisoformat есть границы, о которых стоит знать заранее. Он понимает ISO-варианты: дату без времени, с временем, с секундами и микросекундами, со смещением. А вот «21.10.2026 14:30» — это не ISO, и такой строке он не помощник.
from datetime import datetime
restored = datetime.fromisoformat('2026-10-21T14:30:00')
print(restored)
print(restored.hour)
print(restored.minute)
2026-10-21 14:30:00 14 30
Ещё одна деталь, на которой стоит остановиться: datetime.fromisoformat в Python 3.11 и новее научился понимать большинство вариантов ISO 8601, включая букву Z на конце и смещение в форме +0300. Раньше метод принимал только узкий набор. Если ваш код должен работать на старых версиях, полагайтесь на тот формат, который пишет сам isoformat, — он распознаётся везде.
ISO-формат — это не про удобство чтения, а про то, чтобы вашу дату без споров поняла любая другая система: база, API на другом языке, скрипт в терминале.
isoformat и обратное чтение: формат, который понимают все
isoformat() существует не из-за красоты, а из-за совместимости. Строка вида «2026-10-30T18:45:00» одинаково читается в Python, JavaScript, базах данных и JSON — потому что это ISO 8601, стандарт, о котором договорились разработчики разных языков.
Обратная операция — fromisoformat() — в Python 3.11 и новее разбирает большинство вариантов ISO, включая суффикс Z и смещения часовых поясов. В 3.12 и 3.13 поведение одинаковое, но набор принимаемых вариантов различается от 3.10 и старше. Практический вывод: если код должен работать на старых версиях, полагайтесь ровно на тот формат, который пишет сам isoformat, — он распознаётся везде.
Рекомендация простая: в базе и в API храните дату в ISO, а показывайте пользователю человекочитаемую. Это убирает целый класс проблем — от «после обновления у всех отметок времени стали локальными» до невозможности сравнить даты, полученные из разных источников.
И ещё одно достоинство ISO-формата: он сортируется как текст, поэтому такие строки можно сравнивать напрямую, без разбора дат вообще.
Часы и микросекунды: сколько оставлять
У isoformat есть аргумент timespec, и он закрывает вопрос, который обычно решают вручную. По умолчанию метод пишет всё, что есть в объекте, до микросекунд. Для строки в базе это лишние шесть цифр, для метки в логе — тем более. timespec='minutes' оставляет часы и минуты, timespec='hours' — только дату и час, timespec='seconds' убирает микросекунды, но оставляет секунды.
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30, 45, 123456)
print(d.isoformat())
print(d.isoformat(timespec='seconds'))
print(d.isoformat(timespec='minutes'))
print(d.isoformat(timespec='hours'))
2026-10-21T14:30:45.123456 2026-10-21T14:30:45 2026-10-21T14:30 2026-10-21T14
Выбор уровня — это договорённость с тем, кто будет читать строку. Секунды нужны там, где идут платежи и смены: там две записи с разницей в полсекунды означают разные события. Минуты достаточны для меток в логах и в расписании. А в ключе сортировки в базе часов хватает с большим запасом — суточная статистика всё равно считается запросом, а не просмотром одного значения.
Микросекунды при этом не теряются напрасно: если они в объекте есть, isoformat их запишет, и fromisoformat их прочитает обратно без потерь. Проверка на то, что ничего не потерялось, — та же круговая поездка из блока выше, только с микросекундами внутри. Мы в проектах микросекунды в строках не храним: поле microsecond в базе почти всегда бесполезно, а вот порядок событий внутри секунды по нему различать — полезно, и для этого достаточно момента в памяти, без записи в базу.
Сначала предскажи ответ в голове — это главный навык программиста.
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30)
print(d.isoformat())
from datetime import datetime
d = datetime.fromisoformat('2026-03-08T09:05')
print(d.month)
stamps = ['2026-02-01', '2026-01-31']
print(sorted(stamps))
from datetime import datetime
d = datetime(2026, 10, 21, 14, 30)
print(d.isoformat())
print(d.isoformat(sep=' '))
1. Что вернёт datetime(2026, 10, 21, 14, 30).isoformat()?
2. Почему ISO-строки можно сортировать как обычный текст?
3. Что делает datetime.fromisoformat('2026-10-21')?
4. Что делает аргумент sep=' ' в isoformat?
5. Чему равно datetime.fromisoformat(d.isoformat()) == d?
6. Что произойдёт при попытке положить объект datetime в JSON?
7. Как выглядит isoformat у момента с часовым поясом UTC+3?
8. Что вернёт datetime.fromisoformat('21.10.2026 14:30')?
Возьмите datetime(2026, 7, 19, 21, 45). Сохраните его isoformat-строку в переменную stamp и выведите её. Разберите строку обратно через fromisoformat, выведите год восстановленного объекта и результат сравнения restored == d.
Что делает isoformat в Python?
Метод isoformat переводит объект даты или времени в строку по стандарту ISO 8601: datetime(2026, 10, 21, 14, 30, 45).isoformat() вернёт 2026-10-21T14:30:45. Аргумент sep позволяет заменить разделитель T на другой символ.
Как перевести строку в datetime?
Если строка в ISO-формате — datetime.fromisoformat('2026-10-21T14:30:45'), одна строка кода без шаблонов. Для самодельных форматов вроде 21.10.2026 нужен strptime с кодами из шпаргалки: обычный fromisoformat на них выбросит ValueError.
Урок 8: коды форматированияПочему ISO 8601 удобнее формата ДД.ММ.ГГГГ?
Поля идут от старшего к младшему, поэтому ISO-строки сортируются как обычный текст — хронология сохраняется без парсинга дат. Плюс формат однозначен: в 21.10.2026 непонятно, что здесь день, а что месяц, а в 2026-10-21 путаницы не бывает.
Чем isoformat лучше strftime?
Скоростью и надёжностью записи: не нужен шаблон и знание кодов, вывод фиксирован стандартом и понимается другими системами. strftime нужен, когда формат диктует человек — письмо, отчёт, интерфейс; для хранения и передачи данных выбирайте isoformat.
Как положить дату в JSON?
Преобразовать её в строку заранее: payload = {'at': d.isoformat()}. Объект datetime модуль json не сериализует — json.dumps выбросит TypeError. Альтернатива — default=str в dumps, но тогда формат выберет сериализатор, а не вы.
Что означает смещение +03:00 в конце ISO-строки?
Что момент задан в зоне UTC+3. Строка 2026-10-21T14:30:00+03:00 однозначна: это 11:30 UTC. Без смещения та же строка означает «полдень по чьим-то часам» и не сравнивается с датой из другого источника.
Урок 14: часовые поясаРазберёт ли fromisoformat строку «21.10.2026 14:30»?
Нет, получится ValueError: метод понимает только ISO-варианты. Для произвольных форматов нужен strptime с шаблоном — '%d.%m.%Y %H:%M' для этой строки.
Урок 5: strptimeПонравился урок? Сошлитесь на него
«В ISO-формате поля идут от старшего к младшему: год, месяц, день, часы, минуты.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Datetime · Урок 9
Русские месяцы: названия дат словами
%B упрямо выводит October: названия месяцев strftime берёт из локали среды. Делаем словарь RU_MONTHS и печатаем «21 октября 2026» без единой локали.
Datetime · Урок 11
combine и replace: datetime из частей
date знает день, time знает часы — combine склеивает их в datetime, а replace меняет отдельные поля и возвращает новый объект: datetime неизменяем.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
openpyxl · Урок 9
Даты в Excel через openpyxl: запись, формат и арифметика
Пишем в ячейку настоящий datetime, показываем его по-русски маской DD.MM.YYYY и считаем дни между датами — а заодно узнаём, почему дату из файла нельзя сравнивать со строкой.
openpyxl датыopenpyxl дата в ячейке
Строки · Урок 3
f-строки: вставить значение в текст
f-строка вставляет значение прямо в текст: f'Привет, {name}!' — без плюсов, скобок и str(). Внутри фигурных скобок работает любое выражение Python. Учимся читать и писать их свободно.
f строка pythonf строки python
Datetime · Урок 5
strptime: строка превращается в дату
Лог, форма и таблица присылают даты строками — для вычислений нужен объект. Учим strptime читать строку по шаблону и отличать настоящий формат от почти настоящего.
datetime.strptime pythonстроку в дату python