Os valores de carimbo de data e hora são armazenados de maneira diferente no PostgreSQL quando o tipo de dados é WITH TIME ZONE
versus WITHOUT TIME ZONE
? As diferenças podem ser ilustradas com casos de teste simples?
postgresql
types
timestamp
timezone
Larsenal
fonte
fonte
Respostas:
As diferenças são abordadas na documentação do PostgreSQL para tipos de data / hora . Sim, o tratamento
TIME
ouTIMESTAMP
difere entre umWITH TIME ZONE
ouWITHOUT 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:
fonte
timestamp with time zone
etimestamp 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 ajava.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 ajava.time.Instant
(com menor resolução), mas com JDBC e JPA 2.2 você deve mapeá-lo parajava.time.OffsetDateTime
(ou parajava.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 aTIMESTAMP 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 é.)fonte
TIMESTAMP WITH TIME ZONE
como aInstant
. Ambos representam um ponto na linha do tempo no UTC.Instant
é preferível, na minha opinião, aoOffsetDateTime
invés de ser mais auto-documentado: ATIMESTAMP WITH TIME ZONE
sempre é recuperado do banco de dados como UTC, eInstant
sempre está no UTC para uma correspondência natural, enquanto umOffsetDateTime
pode levar outras compensações.OffsetDateTime
o tipo Java mapeado. Não sei seInstance
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 fazerinsert 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 paraTIMESTAMP WITH TIME ZONE
, e quando isso será convertido paraWITHOUT 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.
Resultado:
fonte
timestamp
etimestamptz
dizer.timestamptz
significa um ponto absoluto no tempo (UTC), enquantotimestamp
denota o que o relógio mostrou em um determinado fuso horário. Assim, ao convertertimestamptz
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" atimestamp
, 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 tiposWITH
vs.WITHOUT TIME ZONE
Portanto, é uma escolha curiosa para explicá-los. (: (AT TIME ZONE
Converte umWITH TIME ZONE
timestamp de umWITHOUT 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