В postgres, timestamp with time zone
может быть сокращено как timestamptz
, и timestamp without time zone
как timestamp
. Я буду использовать более короткие имена типов для простоты.
Получение метки времени Unix от А Postgres , timestamptz
как now()
это просто, как вы говорите, просто:
select extract(epoch from now());
Это действительно все, что вам нужно знать о получении абсолютного времени от чего-либо типа timestamptz
, в том числе now()
.
Все становится сложнее, когда у вас есть timestamp
поле.
Когда вы помещаете timestamptz
данные как now()
в это поле, они сначала преобразуются в определенный часовой пояс (либо явно, at time zone
либо путем преобразования в часовой пояс сеанса), а информация о часовом поясе отбрасывается . Это больше не относится к абсолютному времени. Вот почему вы обычно не хотите хранить временные метки так, как timestamp
это обычно используется timestamptz
- возможно, фильм выходит в 18:00 в определенную дату в каждом часовом поясе , это тот случай использования.
Если вы когда-либо работаете только в одном часовом поясе, вы можете сойти с рук (неправильно) с помощью timestamp
. Обратное преобразование в timestamptz
достаточно умное, чтобы справиться с летним временем, и временные метки, как предполагается, для целей преобразования находятся в текущем часовом поясе. Вот пример для GMT / BST:
select '2011-03-27 00:59:00.0+00'::timestamptz::timestamp::timestamptz
, '2011-03-27 01:00:00.0+00'::timestamptz::timestamp::timestamptz;
/*
|timestamptz |timestamptz |
|:---------------------|:---------------------|
|2011-03-27 00:59:00+00|2011-03-27 02:00:00+01|
*/
DBFiddle
Но обратите внимание на следующее запутанное поведение:
set timezone to 0;
values(1, '1970-01-01 00:00:00+00'::timestamp::timestamptz)
, (2, '1970-01-01 00:00:00+02'::timestamp::timestamptz);
/*
|column1|column2 |
|------:|:---------------------|
| 1|1970-01-01 00:00:00+00|
| 2|1970-01-01 00:00:00+00|
*/
DBFiddle
Это потому что :
PostgreSQL никогда не проверяет содержимое буквенной строки до определения ее типа и поэтому будет обрабатывать обе метки […] как отметку времени без часового пояса. Чтобы литерал обрабатывался как метка времени с часовым поясом, присвойте ему правильный явный тип… В литерале, который был определен как метка времени без часового пояса, PostgreSQL будет молча игнорировать любой указатель часового пояса
SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
не возвращает правильную метку времени, потому что преобразование часового пояса postgres отбрасывает информацию о часовом поясе из результата
после этого извлечение смотрит на метку времени без часового пояса и считает, что это местное время (хотя на самом деле это уже utc).
Правильный путь будет:
В последней строке первая
at time zone
выполняет преобразование, вторая назначает новый часовой пояс для результата.источник