Respostas:
As diferenças são abordadas na documentação do PostgreSQL para tipos de data / hora . Sim, o tratamento TIME
ou TIMESTAMP
difere entre um WITH TIME ZONE
ou WITHOUT TIME ZONE
. Não afeta como os valores são armazenados; afeta como eles são interpretados.
Os efeitos dos fusos horários nesses tipos de dados são abordados especificamente nos documentos. A diferença surge do que o sistema pode razoavelmente saber sobre o valor:
Com um fuso horário como parte do valor, o valor pode ser renderizado como um horário local no cliente.
Sem um fuso horário como parte do valor, o fuso horário padrão óbvio é UTC e, portanto, é renderizado para esse fuso horário.
O comportamento difere dependendo de pelo menos três fatores:
WITH TIME ZONE
ou seja, WITHOUT TIME ZONE
) do valor.Aqui estão exemplos que cobrem as combinações desses fatores:
foo=> SET TIMEZONE TO 'Japan';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 00:00:00+09
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 06:00:00+09
(1 row)
foo=> SET TIMEZONE TO 'Australia/Melbourne';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 00:00:00+11
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 08:00:00+11
(1 row)
timestamp with time zone
e timestamp without time zone
, no Postgres *, na verdade não armazenam informações de fuso horário. Você pode confirmar isso com uma olhada na página de documentos do tipo de dados: os dois tipos ocupam o mesmo número de octetos e têm o intervalo de valores salvo, portanto, não há espaço para armazenar informações de fuso horário. O texto da página confirma isso. Algo equívoco: "sem tz" significa "ignorar deslocamento ao inserir dados" e "com tz" significa "usar deslocamento para ajustar ao UTC".
Tento explicá-lo de maneira mais compreensível do que a documentação do PostgreSQL.
Nenhuma das TIMESTAMP
variantes armazena um fuso horário (ou um deslocamento), apesar do que os nomes sugerem. A diferença está na interpretação dos dados armazenados (e no aplicativo pretendido), não no próprio formato de armazenamento:
TIMESTAMP WITHOUT TIME ZONE
armazena a data e hora local (também conhecida como data do calendário da parede e hora do relógio da parede). Seu fuso horário não é especificado até onde o PostgreSQL pode dizer (embora seu aplicativo possa saber o que é). Portanto, o PostgreSQL não realiza nenhuma conversão relacionada ao fuso horário na entrada ou na saída. Se o valor foi inserido no banco de dados como '2011-07-01 06:30:30'
, então não importa em que fuso horário você o exibirá mais tarde, ainda será o ano de 2011, mês 07, dia 01, 06 horas, 30 minutos e 30 segundos (em algum formato). Além disso, qualquer deslocamento ou fuso horário que você especificar na entrada é ignorado pelo PostgreSQL, então '2011-07-01 06:30:30+00'
e '2011-07-01 06:30:30+05'
são os mesmos apenas '2011-07-01 06:30:30'
. Para desenvolvedores Java: é análogo a java.time.LocalDateTime
.
TIMESTAMP WITH TIME ZONE
armazena um ponto na linha do tempo UTC. Sua aparência (quantas horas, minutos etc.) depende do seu fuso horário, mas sempre se refere ao mesmo instante "físico" (como o momento de um evento físico real). A entrada é convertida internamente em UTC, e é assim que é armazenada. Para isso, o deslocamento da entrada deve ser conhecido; portanto, quando a entrada não contém deslocamento explícito ou fuso horário (como '2011-07-01 06:30:30'
), presume-se que esteja no fuso horário atual da sessão do PostgreSQL, caso contrário, o deslocamento ou fuso horário especificado explicitamente será usado (como em '2011-07-01 06:30:30+05'
). A saída é exibida convertida no fuso horário atual da sessão do PostgreSQL. Para desenvolvedores Java: É análogo a java.time.Instant
(com menor resolução), mas com JDBC e JPA 2.2 você deve mapeá-lo para java.time.OffsetDateTime
(ou para java.util.Date
oujava.sql.Timestamp
claro).
Alguns dizem que ambas as TIMESTAMP
variações armazenam a data e hora UTC. Mais ou menos, mas é confuso colocar dessa maneira na minha opinião. TIMESTAMP WITHOUT TIME ZONE
é armazenado como a TIMESTAMP WITH TIME ZONE
, que é renderizado com o fuso horário UTC e fornece o mesmo ano, mês, dia, horas, minutos, segundos e microssegundos que estão na data e hora local. Mas não é para representar o ponto na linha do tempo que a interpretação UTC diz, é apenas o modo como os campos locais de data e hora são codificados. (Há alguns aglomerados de pontos na linha do tempo, pois o fuso horário real não é UTC; não sabemos o que é.)
TIMESTAMP WITH TIME ZONE
como a Instant
. Ambos representam um ponto na linha do tempo no UTC. Instant
é preferível, na minha opinião, ao OffsetDateTime
invés de ser mais auto-documentado: A TIMESTAMP WITH TIME ZONE
sempre é recuperado do banco de dados como UTC, e Instant
sempre está no UTC para uma correspondência natural, enquanto um OffsetDateTime
pode levar outras compensações.
OffsetDateTime
o tipo Java mapeado. Não sei se Instance
ainda há suporte não oficial em algum lugar.
'2011-07-01 06:30:30+00'
e '2011-07-01 06:30:30+05'
é ignorado, mas eu sou capaz de fazer insert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
e ele o converterá em utc corretamente. em que data é data e hora sem fuso horário. Estou tentando entender qual é o principal valor do carimbo de data / hora com o fuso horário e está tendo problemas.
::timestamptz
. Com isso, você converte a string para TIMESTAMP WITH TIME ZONE
, e quando isso será convertido para WITHOUT TIME ZONE
, que armazenará o dia do "calendário de parede" e a hora do relógio de parede daquele instante, conforme visto no fuso horário da sessão (que talvez seja UTC). Ainda será apenas um registro de data e hora local com deslocamento não especificado (sem zona).
Aqui está um exemplo que deve ajudar. Se você tiver um carimbo de data / hora com um fuso horário, poderá convertê-lo em qualquer outro fuso horário. Se você não tiver um fuso horário base, ele não será convertido corretamente.
SELECT now(),
now()::timestamp,
now() AT TIME ZONE 'CST',
now()::timestamp AT TIME ZONE 'CST'
Resultado:
-[ RECORD 1 ]---------------------------
now | 2018-09-15 17:01:36.399357+03
now | 2018-09-15 17:01:36.399357
timezone | 2018-09-15 08:01:36.399357
timezone | 2018-09-16 02:01:36.399357+03
timestamp
e timestamptz
dizer. timestamptz
significa um ponto absoluto no tempo (UTC), enquanto timestamp
denota o que o relógio mostrou em um determinado fuso horário. Assim, ao converter timestamptz
para um fuso horário, você está perguntando o que o relógio mostrou em Nova York nesse ponto absoluto no tempo? enquanto que ao "converter" a timestamp
, você está perguntando qual era o ponto absoluto no tempo em que o relógio em Nova York mostrava x?
AT TIME ZONE
construção é um quebra-cabeças próprio, mesmo que você já entenda os tipos WITH
vs. WITHOUT TIME ZONE
Portanto, é uma escolha curiosa para explicá-los. (: ( AT TIME ZONE
Converte um WITH TIME ZONE
timestamp de um WITHOUT TIME ZONE
timestamp, e vice-versa ... não exatamente óbvio).
now()::timestamp AT TIME ZONE 'CST'
Não faz sentido, a menos que o que se em qualquer tempo um relógio para a zona 'CST' iria mostrar o tempo que seu relógio local está mostrando