Работа с datetime в PostgreSQL: учет часовых поясов
Быстрый ответ
Точное вычитание дат-времени возможно только при соблюдении одного условия: оба объекта datetime
должны быть в одинаковом статусе по отношению к часовому поясу – оба либо с информацией о часовом поясе (осведомлённые), либо без него (наивные).
Преобразовать осведомлённый объект datetime
в наивный, исключив часовой пояс, можно с помощью .replace(tzinfo=None)
. Реверсивная операция – присвоение часового пояса наивному объекту datetime
– будет потребовать использования timezone
или библиотеки pytz
в старых версиях Python.
Преобразование осведомленного объекта datetime в наивный:
naive_datetime = aware_datetime.replace(tzinfo=None) # отбрасываем информацию о часовом поясе
Добавление UTC к наивному объекту datetime:
from datetime import datetime, timezone
aware_datetime = naive_datetime.replace(tzinfo=timezone.utc) # добавляем UTC-часовой пояс
Прежде чем производить вычитание, удостоверьтесь, что статус часового пояса совпадает у обоих объектов datetime
.
Часовые поясы и их преобразование – это проще, чем кажется
Ключ к успешной работе с datetime
– корректное использование часовых поясов. Чтобы привести дату-время к часовому поясу UTC (или другому), используйте метод .astimezone()
.
Приведение времени к UTC:
from datetime import datetime, timezone
aware_datetime_utc = aware_datetime.astimezone(timezone.utc) # Теперь время в формате UTC!
Это особенно актуально для приложений, деплоящихся на серверах в разных часовых поясах.
Базы данных и ORM: союз преимущественно благотворный
При работе с PostgreSQL рекомендуется хранить даты-время в формате UTC, используя функцию NOW() AT TIME ZONE 'UTC'
.
При использовании Django ORM предпочтительнее функцию timezone.now()
, создающую осведомлённую временную метку. В этом случае параметр USE_TZ
должен быть включен. Установление подключения к базе данных по умолчанию на работу в UTC избавит вас от проблем с часовыми поясами.
Руководство по старым версиям Python
Для версий Python без datetime.timezone
можно создать объект tzinfo UTC вручную:
Создание tzinfo UTC:
import pytz
utc = pytz.utc
aware_datetime = naive_datetime.replace(tzinfo=utc) # Осведомлённая дата в старых версиях Python
Визуализация
Представим, если отнимать время из двух разных часовых поясов:
Космонавты в Московском времени (🚀): 12:00 PM (Наивное время)
Марсианские часы (👽): 12:00 PM UTC+0 (Осведомленное время)
Попытка вычитания приведёт к ошибке:
🚀 – 👽 # TypeError: недопустимая операция!
Причина ошибки Космонавты (🚀) и марсианские часы (👽) живут в разных временных рамках. Вы не можете провести вычитание, так как эти временные диапазоны не совместимы:
Ошибка: 🌎🔄🔴 # Наличие пространственно-временного портала обязательно!
Решение: Для корректного вычитания обе даты-времени следует привести к "галактическому" статусу осведомленности, то есть установить для них общий часовой пояс.
Также рекомендуем обратить внимание: Мелкие, но важные особенности
Python и часовые пояса: взаимно уважающие отношения
Использование datetime.utcnow()
для получения осведомлённых меток времени не достаточно точно. Правильнее использовать datetime.now(timezone.utc)
или datetime.utcnow().replace(tzinfo=timezone.utc)
.
Математика с датами и временами – дело скользкое
Если перед вычитанием не привести оба объекта datetime
к стандартному виду, то можно получить ошибку, которую будет сложно осознать.
Откуда берется информация о часовых поясах?
Источником информации о часовых поясах стоит выбрать базу данных IANA, ее данные всегда проверенны и актуальны.
Время не стоит на месте, поэтому нужно следовать за ним
Правила часовых поясов периодически меняются, поэтому следите за новой информацией о библиотеках работы с ними (например, pytz
).
Проверяйте актуальность информации!
Не используйте устаревшие правила перехода на летне-зимнее время. Опирайтесь только на текущие данные.
Летнее время – тест для всех
С летним и зимним временем отчётливо возникают сложности при работе с локальными часовыми поясами. Учтите это, чтобы избежать потери важных данных.
Полезные материалы
- datetime — Основные типы даты и времени — Документация Python 3.12.1 — подробная информация о приемах работы с модулем
datetime
в Python. - python – Нельзя вычитать даты-время с часовым поясом и без него – Stack Overflow — эффективные советы для успешной работы с
datetime
. - dateutil – мощное расширение для работы с datetime — документация dateutil 2.8.2 — дополнительный функционал стандартного модуля
datetime
через библиотекуdateutil
. - База данных часовых поясов IANA — всеобъемлющее руководство по стандартам по всему миру.
- ISO 8601 – Wikipedia — стандарты представления даты и времени, к которым следует приводить.
- Отказ от использования функций utcnow и utcfromtimestamp — последнее слово в дискуссии о выборе между двумя методами работы с UTC в Python.
- Arrow: Лучшие даты и времена для Python — Документация Arrow 🏹 1.3.0 — удобная для использования альтернатива модулю
datetime
в Python.