Работа с datetime в PostgreSQL: учет часовых поясов

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Точное вычитание дат-времени возможно только при соблюдении одного условия: оба объекта datetime должны быть в одинаковом статусе по отношению к часовому поясу – оба либо с информацией о часовом поясе (осведомлённые), либо без него (наивные).

Преобразовать осведомлённый объект datetime в наивный, исключив часовой пояс, можно с помощью .replace(tzinfo=None). Реверсивная операция – присвоение часового пояса наивному объекту datetime – будет потребовать использования timezone или библиотеки pytz в старых версиях Python.

Преобразование осведомленного объекта datetime в наивный:

Python
Скопировать код
naive_datetime = aware_datetime.replace(tzinfo=None)  # отбрасываем информацию о часовом поясе

Добавление UTC к наивному объекту datetime:

Python
Скопировать код
from datetime import datetime, timezone

aware_datetime = naive_datetime.replace(tzinfo=timezone.utc)  # добавляем UTC-часовой пояс

Прежде чем производить вычитание, удостоверьтесь, что статус часового пояса совпадает у обоих объектов datetime.

Кинга Идем в IT: пошаговый план для смены профессии

Часовые поясы и их преобразование – это проще, чем кажется

Ключ к успешной работе с datetime – корректное использование часовых поясов. Чтобы привести дату-время к часовому поясу UTC (или другому), используйте метод .astimezone().

Приведение времени к UTC:

Python
Скопировать код
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:

Python
Скопировать код
import pytz

utc = pytz.utc
aware_datetime = naive_datetime.replace(tzinfo=utc)  # Осведомлённая дата в старых версиях Python

Визуализация

Представим, если отнимать время из двух разных часовых поясов:

Markdown
Скопировать код
Космонавты в Московском времени (🚀): 12:00 PM (Наивное время)
Марсианские часы (👽): 12:00 PM UTC+0 (Осведомленное время)

Попытка вычитания приведёт к ошибке:

Python
Скопировать код
🚀 – 👽 # TypeError: недопустимая операция!

Причина ошибки Космонавты (🚀) и марсианские часы (👽) живут в разных временных рамках. Вы не можете провести вычитание, так как эти временные диапазоны не совместимы:

Markdown
Скопировать код
Ошибка: 🌎🔄🔴 # Наличие пространственно-временного портала обязательно!

Решение: Для корректного вычитания обе даты-времени следует привести к "галактическому" статусу осведомленности, то есть установить для них общий часовой пояс.

Также рекомендуем обратить внимание: Мелкие, но важные особенности

Python и часовые пояса: взаимно уважающие отношения

Использование datetime.utcnow() для получения осведомлённых меток времени не достаточно точно. Правильнее использовать datetime.now(timezone.utc) или datetime.utcnow().replace(tzinfo=timezone.utc).

Математика с датами и временами – дело скользкое

Если перед вычитанием не привести оба объекта datetime к стандартному виду, то можно получить ошибку, которую будет сложно осознать.

Откуда берется информация о часовых поясах?

Источником информации о часовых поясах стоит выбрать базу данных IANA, ее данные всегда проверенны и актуальны.

Время не стоит на месте, поэтому нужно следовать за ним

Правила часовых поясов периодически меняются, поэтому следите за новой информацией о библиотеках работы с ними (например, pytz).

Проверяйте актуальность информации!

Не используйте устаревшие правила перехода на летне-зимнее время. Опирайтесь только на текущие данные.

Летнее время – тест для всех

С летним и зимним временем отчётливо возникают сложности при работе с локальными часовыми поясами. Учтите это, чтобы избежать потери важных данных.

Полезные материалы

  1. datetime — Основные типы даты и времени — Документация Python 3.12.1 — подробная информация о приемах работы с модулем datetime в Python.
  2. python – Нельзя вычитать даты-время с часовым поясом и без него – Stack Overflow — эффективные советы для успешной работы с datetime.
  3. dateutil – мощное расширение для работы с datetime — документация dateutil 2.8.2 — дополнительный функционал стандартного модуля datetime через библиотеку dateutil.
  4. База данных часовых поясов IANA — всеобъемлющее руководство по стандартам по всему миру.
  5. ISO 8601 – Wikipedia — стандарты представления даты и времени, к которым следует приводить.
  6. Отказ от использования функций utcnow и utcfromtimestamp — последнее слово в дискуссии о выборе между двумя методами работы с UTC в Python.
  7. Arrow: Лучшие даты и времена для Python — Документация Arrow 🏹 1.3.0 — удобная для использования альтернатива модулю datetime в Python.