Время в API: передавайте момент, а не загадку
UTC, смещение и явное преобразование вместо неявного локального времени.
Строка 2026-09-09T10:00:00 не сообщает, в каком часовом поясе произошло событие. Если сервер и клиент понимают её по-разному, сортировка и дедлайны начинают расходиться. Для конкретного момента времени передавайте смещение или UTC.
Создать aware datetime
from datetime import datetime, timezone
now = datetime.now(timezone.utc)
print(now.isoformat())Результат содержит смещение +00:00. Такой объект несёт информацию о часовом поясе, в отличие от naive datetime без tzinfo.
Преобразовать известное смещение
from datetime import datetime, timezone
event = datetime.fromisoformat(
"2026-09-09T13:00:00+03:00"
)
print(event.astimezone(timezone.utc).isoformat())
# 2026-09-09T10:00:00+00:00astimezone сохраняет момент и меняет его представление. Простая замена tzinfo не выполняет такого преобразования: она меняет интерпретацию исходных часов.
Оговорить контракт
Определите формат, допустимую точность и поведение для строк без смещения. Для поля occurred_at удобно требовать явный момент. Для даты рождения достаточно календарной даты: превращение её в полночь UTC обычно добавляет ненужную неоднозначность.
UTC не решает все задачи
Расписание «каждый день в девять по местному времени» описывает правило, а не единственный момент. Для него нужен региональный часовой пояс и отдельная обработка переходов времени. Фиксированное смещение не содержит этих правил.
Проверьте сериализацию и обратное чтение на значениях с разными смещениями. Отдельно проверьте границу суток: один и тот же момент может относиться к разным календарным датам у двух пользователей. В интерфейсе показывайте выбранный часовой пояс рядом со временем, когда от него зависит решение читателя.