Django извлекает из базы данных postgres неправильные объекты времени (переопределен часовой пояс)
У меня возникла проблема с Django, psycopg и PostgreSQL, связанная с обработкой временных интервалов с учетом временных зон. Ниже приведены детали моей установки и проблема, с которой я столкнулся:
Окружение
Library | Version |
---|---|
psycopg | 3.1.18 |
Django | 4.2.10 |
PostgreSQL | 16.1 |
Описание выпуска
У меня есть модель Django с DateTimeField
, которая создает колонку timestamp with timezone
в PostgreSQL. Когда я создаю новый экземпляр модели с временной шкалой и сохраняю его в базе данных, временная шкала сохраняется правильно, что подтверждается просмотром в таких средствах просмотра базы данных, как pgAdmin или DataGrip.
Однако при извлечении данных обратно в Django дататайм отображается с неправильным смещением. В частности, он, похоже, переопределяет исходное смещение часового пояса на 0 (UTC), в то время как время остается неизменным, что приводит к неправильным значениям datetime.
Пример
- Время, переданное в модель:
2024-02-18 01:46:29+01:00
- Время, хранящееся в базе данных (просматривается с помощью DataGrip):
2024-02-18 01:46:29.000000 +01:00
- Время, полученное в Django:
2024-02-18 01:46:29+00:00
Это расхождение говорит о том, что вместо того, чтобы просто преобразовать время в UTC, Django меняет часовой пояс на UTC, но сохраняет время из часового пояса UTC+1, что неверно.
Настройки Django
У меня следующие настройки в моем settings.py
:
USE_TZ = True
TIME_ZONE = 'UTC'
Я поэкспериментировал с параметром TIME_ZONE
в переменной DATABASES
, установив его в значение TIME_ZONE
: Europe/Zurich
, что позволило исправить часовой пояс на UTC+1
. Однако это решение, похоже, корректирует часовой пояс, в котором я получаю данные, а не основную проблему неправильной обработки часового пояса.
Дополнительные замечания При использовании psycopg напрямую (без Django) эта проблема не возникает, и данные возвращаются с правильным часовым поясом. Это позволяет предположить, что проблема может быть связана с обработкой часовых поясов в Django.
Вопросы Я неправильно понимаю работу Django с часовыми поясами? Может быть, я пропустил какой-то шаг настройки или такое поведение может быть ошибкой? Буду признателен за любые соображения или рекомендации по решению этой проблемы.
Я определил основную причину проблемы, с которой мы столкнулись. Проблема исходила от PostgreSQL. Однако из-за того, как Django обрабатывает ответы, связанные с датами, ошибка была заметна только на стороне Django.
Проблема в PostgreSQL:
Проблема заключалась в том, что PostgreSQL не устанавливал часовой пояс, как ожидалось. Хотя фактическое время было правильным, установка часового пояса в любое значение работала нормально, за исключением UTC. Когда указывался UTC, PostgreSQL возвращала время в системном часовом поясе, а не в UTC. Это поведение было подтверждено в ходе тестирования с использованием psql
:
slick26=# SET TIME ZONE 'Europe/London';
SET
slick26=# SHOW TIMEZONE;
TimeZone
---------------
Europe/London
(1 row)
slick26=# SELECT now();
now
-------------------------------
2024-03-03 12:27:16.057474+00
(1 row)
slick26=#
slick26=# SET TIME ZONE 'UTC';
SET
slick26=# SHOW TIMEZONE;
TimeZone
----------
UTC
(1 row)
slick26=# SELECT now();
now
-------------------------------
2024-03-03 13:28:54.533239+01
(1 row)
slick26=#
Основная проблема была связана с запуском PostgreSQL в контейнере. Чтобы правильно выровнять часовой пояс контейнера, я смонтировал следующие тома и установил соответствующие переменные окружения:
- Тома:
/etc/timezone:/etc/timezone:ro
/etc/localtime:/etc/localtime:ro
- Переменные окружения:
TZ: Europe/Zurich
PGTZ: Europe/Zurich
Однако попытка смонтировать localtime
не привела к ожидаемому результату; симлинк продолжал указывать на UTC.
Проблема в Django:
Django устанавливает часовой пояс соединения как UTC. Однако, когда база данных отвечает значением времени в UTC+1, возникает несоответствие. В то время как другие клиенты отображали бы возвращаемый результат как есть, Django переопределяет его с ожидаемым часовым поясом (в данном случае UTC), что приводит к отображению неправильных значений времени.