Knex молча конвертирует метки времени Postgres с часовым поясом и возвращает неверное - PullRequest
0 голосов
/ 28 июня 2018

В моей базе данных psql есть таблица со столбцом «trigger_time» типа «TIMESTAMP WITH TIME ZONE DEFAULT now ()»

Я данные в строке это 2018-06-27 15:45:00-03.

При запуске из консоли PSQL

SELECT trigger_time AT TIME ZONE 'UTC' 
FROM tasks 
WHERE task_id = 1;

этот запрос возвращает "2018-06-27 18:45:00".

Точно так же, когда я бегу

SELECT trigger_time AT TIME ZONE 'America/Glace_Bay' 
FROM tasks 
WHERE task_id = 1;

Я получаю 2018-06-27 15:45:00

Используя knex.raw("SELECT trigger_time AT TIME ZONE 'America/Glace_Bay' FROM tasks WHERE task_id = 1") Я получаю 2018-06-27T18:45:00.000Z, а при запуске knex.raw("SELECT trigger_time AT TIME ZONE 'UTC' FROM tasks WHERE task_id = 1") Я получаю 2018-06-27T21:45:00.000Z

Оба эти результата от knex неверны, как мне заставить knex перестать молча изменять мои данные?

1 Ответ

0 голосов
/ 28 июня 2018

Вероятно, что-то не получается, потому что, когда вы запрашиваете дату / время из базы данных в определенном часовом поясе и эффективно конвертируете тип метки времени в метку времени без часового пояса. В этом случае база данных не будет отправлять информацию в knex о том, в каком часовом поясе было возвращено время.

Таким образом, knex (или, точнее, драйвер pg, который использует knex) интерпретирует вашу временную метку как местное время, которое зависит от настройки часового пояса сервера приложений, на котором работает knex.

Вы можете извлекать время точно так же, как в формате UTC, и выполнять преобразование часового пояса на стороне JavaScript с помощью библиотеки моментов или luxon (IMO лучше для обработки часового пояса).

Другим решением было бы сообщить pg driver, что отметка времени и отметка времени с типами часовых поясов не должны преобразовываться в JavaScript Date объекты.

Это можно сделать так (https://github.com/brianc/node-pg-types):

const types = require('pg').types;
const TIMESTAMPTZ_OID = 1184;
const TIMESTAMP_OID = 1114;
types.setTypeParser(TIMESTAMPTZ_OID, val => val);
types.setTypeParser(TIMESTAMP_OID, val => val);

Этот код, который делает все метки времени возвращаемыми в виде строк, может быть добавлен, например, в начале knexfile.js. Эти возвращенные строки будут точно в том же формате, в котором они были возвращены самим сервером базы данных.

РЕДАКТИРОВАТЬ:

В коде исходного сообщения, когда метка времени преобразуется в часовой пояс UTC Сервер баз данных преобразует тип timestamp with time zone в обычный timestamp without time zone, поэтому возвращаемое значение не имеет информации о часовом поясе. Чтобы добавить информацию о часовом поясе, вы можете, например, добавить +02 к концу возвращенной отметки времени, например:

select ('2010-01-01T00:00:00.000Z'::timestamptz AT TIME ZONE 'UTC')::text || '+00';

Возвращает 2010-01-01 00:00:00+00 драйверу, который также может быть правильно прочитан драйвером pg.

Это будет фактически делать то же самое, что просто установить SET TIME ZONE 'UTC'; на сервере базы данных при создании соединения и просто вернуть столбец timestamptz напрямую:

SET TIME ZONE 'UTC';
select '2010-01-01T00:00:00.000+02:00'::timestamptz;

Который вернет 2009-12-31 22:00:00+00.

...