Em postgres, timestamp with time zone
pode ser abreviado como timestamptz
, e timestamp without time zone
como timestamp
. Usarei os nomes de tipo mais curtos para simplificar.
Obter o timestamp Unix de um postgres timestamptz
como now()
é simples, como você diz, apenas:
select extract(epoch from now());
É realmente tudo o que você precisa saber sobre como obter o tempo absoluto de qualquer coisa do tipo timestamptz
, inclusive now()
.
As coisas só ficam complicadas quando você tem um timestamp
campo.
Quando você coloca timestamptz
dados como now()
esse campo, eles primeiro são convertidos em um fuso horário específico (explicitamente com at time zone
ou pela conversão no fuso horário da sessão) e as informações do fuso horário são descartadas . Já não se refere a um tempo absoluto. É por isso que você normalmente não deseja armazenar carimbos de data timestamp
e hora como normalmente usaria timestamptz
- talvez um filme seja lançado às 18h em uma data específica em cada fuso horário , esse é o tipo de caso de uso.
Se você trabalhar apenas em um único fuso horário, poderá se safar (mis) de usar timestamp
. A conversão de volta para timestamptz
é inteligente o suficiente para lidar com o horário de verão, e os registros de data e hora são assumidos, para fins de conversão, no fuso horário atual. Aqui está um exemplo para 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
Mas, observe o seguinte comportamento confuso:
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
Isso ocorre porque :
O PostgreSQL nunca examina o conteúdo de uma string literal antes de determinar seu tipo e, portanto, tratará ambos […] como carimbo de data / hora sem fuso horário. Para garantir que um literal seja tratado como registro de data e hora com fuso horário, forneça o tipo explícito correto ... Em um literal que foi determinado como registro de data e hora sem fuso horário, o PostgreSQL ignorará silenciosamente qualquer indicação de fuso horário
SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
não retorna o carimbo de data e hora correto porque a conversão do fuso horário do postgres joga fora as informações do fuso horário do resultado:
depois, extrair examina o carimbo de data / hora sem fuso horário e o considera um horário local (embora já seja utc de fato).
A maneira correta seria:
Na última linha, a primeira
at time zone
realiza a conversão, a segunda atribui um novo fuso horário ao resultado.fonte