Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 10 из 20 Начальный 15 мин 110 XP

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-формат придуман так, чтобы текст и время совпадали.

sorted без парсинга дат
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 её обрабатывать. Первый путь честнее: вы решаете, в каком виде дата уйдёт наружу, и не зависите от того, как сериализатор решил её представить.

json.py — дата в payload
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.

offset.py — смещение в строке
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() без явной зоны, строка получилась бы без смещения, и её нельзя было бы сравнить с датой из другого источника.

mixed_types.py — объект против строки
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, и такой строке он не помощник.

roundtrip.py — разбор обратно
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' убирает микросекунды, но оставляет секунды.

timespec.py — четыре уровня точности
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=' '))
Проверь себя
0 / 8

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')?

Карточки терминов
Запомнено: 0 / 9
Практика

Возьмите datetime(2026, 7, 19, 21, 45). Сохраните его isoformat-строку в переменную stamp и выведите её. Разберите строку обратно через fromisoformat, выведите год восстановленного объекта и результат сравнения restored == d.

practice.py
Вопросы и ответы по уроку

Что делает 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-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.