Используйте node-postgres, чтобы получить метку времени Postgres без часового пояса в utc

У меня есть временные метки, хранящиеся как тип Postgres timestamp without time zone.

В качестве примера я буду использовать метку времени 2013-12-20 20:45:27. Я предполагаю, что это будет метка времени в формате UTC.

В psql, если я запустил запрос SELECT start_time FROM table_name WHERE id = 1, я верну эту строку отметки времени, как и ожидалось: 2013-12-20 20:45:27.

Однако, если в моем приложении Node я использую библиотеку node-postgres для выполнения того же запроса, я получаю метку времени в местном часовом поясе: Fri Dec 20 2013 20:45:27 GMT-0600 (CST). Это объект даты Javascript, но он уже сохранен как часовой пояс. Что мне действительно нужно, так это объект даты (или даже просто строка), представляющий 2013-12-20 20:45:27 GMT+0000. Я уже знаю, что сейчас UTC.

Я попытался установить параметр часового пояса в моем файле postgresql.conf на: timezone = 'UTC', без разницы в результатах.

Что я делаю неправильно?

ИЗМЕНИТЬ

Кажется, проблема в этом файле: https://github.com/brianc/node-postgres/blob/master/lib/types/textParsers.js

Если в строке даты, возвращаемой Postgres, не указан часовой пояс (например, Z или +06:30, тогда он просто создает объект даты JavaScript, который, как я полагаю, будет просто включать местный часовой пояс. Мне либо нужно изменить мое приложение для сохранения часовых поясов в базе данных или отмены этого преобразователя.


person Isaac Dontje Lindell    schedule 20.12.2013    source источник


Ответы (4)


Не для того, чтобы возродить старый вопрос, а для того, чтобы увидеть, как у меня была точно такая же проблема здесь, существует альтернативное решение, которое работает путем переопределения синтаксического анализатора типов для использования для timestamp without time zone:

var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, function(stringValue) {
return stringValue;
});

Это не позволит node-pg преобразовать значение в объект Date и вместо этого предоставит вам необработанную строку временной метки.

Источник: Получено из проблем с узлами и postgres.

person BadIdeaException    schedule 06.04.2014
comment
Я не знаю, считается ли это работающим, но он меняет поведение парсера, чтобы он возвращал строку вместо объекта даты (по крайней мере, в текущей итерации pg-prom, которая использует node-postgres под крышками) . Это сломало весь мой код, который ожидал возврата даты, поэтому это решение не помогло мне. Единственное, что сработало для меня, - это изменение stringValue перед передачей его конструктору даты: return new Date(stringValue + '+0000'). Хотелось бы увидеть лучший способ создать объект даты UTC из строки ISO 8601, которая не указывает часовой пояс. - person stone; 13.07.2016
comment
Верно, но OP сказал, что строки достаточно. В любом случае, переопределив синтаксический анализатор, легко вернуть практически все, что вам нужно, включая новый объект даты. - person BadIdeaException; 13.07.2016
comment
У меня тоже работает, так как я все равно использую другие библиотеки времени, такие как moment или luxon, после загрузки. Не совсем фанат тех Date (), когда они все переводят в местное время ... - person Pencilcheck; 30.11.2017
comment
Все обходные пути перечислены здесь 60devs.com/. В итоге я использовал решение moment (). - person justd; 21.03.2019

Вы можете изменить парсер, как предлагает @BadIdeaException. Ниже приведены более подробные сведения о том, почему это не работает должным образом, и два возможных решения.

Для столбцов с типом timestamp without time zone синтаксический анализатор получает строку в формате ISO 8601 без указания часового пояса: 2016-07-12 22:47:34

Каждый раз, когда вы создаете объект Date в Javascript, если вы не указываете часовой пояс, предполагается, что дата находится в текущем часовом поясе. Для дат в формате UTC, которые по определению находятся в часовом поясе GMT, это даст вам дату с неправильным абсолютным значением (date.value), если только ваш Javascript не работает в часовом поясе GMT. .

Следовательно, эту строку ISO 8601 нельзя напрямую преобразовать в дату в формате UTC конструктором Date. Возможны следующие варианты: Измените строку так, чтобы она интерпретировалась как UTC:

var pg = require('pg');
var types = pg.types;
types.setTypeParser(1114, function(stringValue) {
    return new Date(stringValue + "+0000");
});

или пусть ваша дата будет создана с неправильным (текущим) часовым поясом, а затем извлеките для нее значения (все еще в вашем текущем часовом поясе), а затем используйте эти значения для создания даты в часовом поясе UTC. Обратите внимание, что Date.UTC () возвращает значение даты, а не объект, который затем можно передать конструктору Date.

types.setTypeParser(1114, function(stringValue) {

    var temp = new Date(stringValue);
    return new Date(Date.UTC(
        temp.getFullYear(), temp.getMonth(), temp.getDate(), temp.getHours(), temp.getMinutes(), temp.getSeconds(), temp.getMilliseconds())
    );
}
person stone    schedule 12.07.2016
comment
Ты сэкономил мне время, приятель. Спасибо - person Hemadri Dasari; 01.11.2018
comment
В моем случае я вообще избегал использования Date до тех пор, пока я полностью не ЗНАЮ часовой пояс, вместо этого использовал простой объект с этой схемой: {year, month, day, hour, minutes, seconds}, а затем построил из него строки ISO только однажды я знал часовой пояс, с которым хотел бы построить его. - person Dennis L; 10.11.2020

Это не лучшее решение, но я просто перешел на использование типа Postgres timestamp with time zone и убедился, что все даты, которые я сохраняю в БД, находятся в UTC.

person Isaac Dontje Lindell    schedule 20.12.2013
comment
В моем случае это решение в любом случае безопаснее из-за проблем с переходом на летнее время. - person Cody Stott; 23.01.2017

Мне было интересно, откуда @BadIdeaException взял число 1114. В машинописном тексте можно увидеть значения из интерфейса.

import { types } from 'pg';
types.setTypeParser(types.TypeId.TIME, (timeStr) => timeStr);
types.setTypeParser(types.TypeId.TIMESTAMP, (timeStr) => timeStr);
types.setTypeParser(types.TypeId.TIMESTAMPTZ, (timeStr) => timeStr);

Это переопределит все парсеры полей меток времени и предотвратит неправильный синтаксический анализ полей в объект Date.

person sziraqui    schedule 11.11.2020