Запрос диапазона дат PostgreSQL работает локально, но не в рабочей среде - PullRequest
2 голосов
/ 01 октября 2019

Я работаю над приложением, которое, помимо прочего, имеет некоторые функции управления заказами, и я обнаружил проблему, которая, по моему мнению, связана с часовыми поясами.

Справочная информация

Бэкэнд написан на Python, и мы используем Flask и SQLAlchemy. База данных PostgreSQL. Мы (и пользователи, и разработчики) находимся в одном часовом поясе (CET / CEST). Рассматриваемое приложение размещено на AWS с серверами в Ирландии, как мне кажется.

Общее описание проблемы

Когда я получаю заказы и пытаюсь отфильтровать их по определенному диапазону дат, заказы с первого часа следующего дня (вне диапазона дат) включается в результат.

Пошаговая инструкция

  1. Интерфейс отправляет запрос в бэкэнд Python с диапазоном дат в строке запроса.
  2. Проект Flask получает запрос, извлекает параметры в строке запроса и вызывает функцию get_orders в OrderService.
  3. get_order создает объект SQLAlchemy Query и фильтрует по заданным параметрам.
# Very simplified version of actual code
def get_orders(self, site_id, params):
    created_after = params.get('created_after')
    created_before = params.get('created_before')

    query = self.sess.query(Order) \
        .filter(Order.site_id == site_id)

    if created_after:
        dt = datetime.strptime(created_after, '%Y%m%d-%H%M%S-%f')
        query = query.filter(Order.created_at > self._nor_to_utc_tz(dt))

    if created_before:
        dt = datetime.strptime(created_before, '%Y%m%d-%H%M%S-%f')
        query = query.filter(Order.created_at < self._nor_to_utz_tz(dt))

    ...
    return result


def _nor_to_utc_tz(dt):
    # Incoming datetime is always the same timezone
    dt = dt.replace(tzinfo=tz.gettz('Europe/Oslo'))

    # All datetimes is stored as UTC on server
    dt = dt.astimezone(tz.gettz('UTC'))
    return dt

Результат запроса преобразуется в диктовку и возвращается в чертеж Flask. Проект возвращает диктант в виде JSON на внешний интерфейс.

Шаблон модели SQLAlchemy

class Order(Base, ModelTemplate):
    __tablename__ = 'orders'
    ...
    created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
    ...

Результаты

При локальном тестировании все работает нормально. Я сделал тестовые заказы на все часы дня, и они отфильтрованы по правильному диапазону дат.

Проблема возникает в производственной среде. Заказы, созданные сразу после полуночи по местному времени, включаются в результат для запросов, которые должны были быть ограничены заказами, созданными накануне.

Пример

  • Кто-то покупаетчто-то 2 октября в 00:55 (UTC + 2).
  • Заказ создается и сохраняется с отметкой времени 2019-10-01 22:55 (UTC + 0).
  • Позже кто-то хочет просмотреть все заказы 2 октября и отправляет запрос навсе заказы, созданные после 2019-10-02 00:00:00 и до 2019-10-02 23:59:59.
  • Бэкэнд преобразует это время в UTC + 0, так что должны быть возвращены все заказы, созданные между 2019-10-01 22:00:00 и 2019-10-02 21:59:59, но вышеупомянутый заказне является.

Теория

Моя теория, основанная только на том, что я не могу думать ни о чем другом, что соответствует шаблону, заключается в том, что postgres конвертируетдиапазон дат по местному времени серверов перед фильтрацией результата. Я СЧИТАЮ (или размышляю), что местное время сервера - UTC + 1 (начиная с Ирландии), что соответствует полученному результату.

То, что я пробовал

  • Удаление информации о часовом поясе из даты и времени после преобразования из норвежского в UTC часового пояса, в случае, если обманул postgres, полагая, что dt должно бытьпереведено в местное время
  • Добавление timezone = True к объекту DateTime в модели SQLAlchemy, чтобы сделать его временной меткой с часовым поясом в postgres, а затем добавить норвежский часовой пояс к datetime, используемому для фильтрации запроса (и не преобразовывать его в UTC+0, надеясь, что Postgres сделает это).
  • Разочарован.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...