Qual é um caso de uso válido para usar o TIMESTAMP SEM Fuso Horário?

40

Há uma resposta longa e bastante esclarecedora sobre as diferenças entre

  • TIMESTAMP WITH TIME ZONE -vs-
  • TIMESTAMP WITHOUT TIME ZONE

disponível nesta postagem do SO . O que eu gostaria de saber é: existe algum caso de uso válido para realmente usar TIMESTAMP WITHOUT TIME ZONEou deve ser considerado um antipadrão.

Marcus Junius Brutus
fonte
Esta questão corre o risco de ser encerrada, sendo "principalmente baseada em opiniões". Tentei dar algumas visões objetivas na minha resposta abaixo.
Colin 'Hart
2
Esse problema é bastante real, cada tipo de dado tendo um significado muito diferente. Portanto, eu certamente não consideraria esta questão como primariamente baseada em opiniões.
Basil Bourque

Respostas:

29

Isso é afirmado em muitos lugares, mas acho que vale a pena mencionar sempre quando comparamos os tipos timestamp with time zonecom timestamp without time zone: o timestamp WITH time zonenão armazena as informações de fuso horário junto com o registro de data e hora . O que ele faz é armazenar todos os dados no fuso horário UTC, conforme declarado nos documentos :

Para registro de data e hora com fuso horário, o valor armazenado internamente é sempre em UTC (Universal Coordinated Time, tradicionalmente conhecido como Greenwich Mean Time, GMT). Um valor de entrada que possui um fuso horário explícito especificado é convertido para UTC usando o deslocamento apropriado para esse fuso horário. Se nenhum fuso horário for indicado na sequência de entrada, ele será assumido no fuso horário indicado pelo parâmetro TimeZone do sistema e será convertido em UTC usando o deslocamento para o fuso horário.

É considerado válido para alguns usarem timestamp WITHOUT time zoneem situações em que (1) tudo está no mesmo fuso horário ou (2) a camada de aplicativo lida com o fuso horário e apenas armazena tudo em um determinado fuso horário (geralmente UTC). Mas também é considerado um antipadrão, simples porque a solução correta para (1) é definir a configuração do Fuso Horário para o fuso horário especificado para o sistema e (2) já está resolvido, pois o PostgreSQL já armazena tudo no mesmo fuso horário. (UTC).

Agora, com os dois para baixo, posso veio com apenas uma boa razão para usar timestamp WITHOUT time zone. É quando você deseja armazenar eventos no futuro e que algum tipo de alerta deve ser acionado quando chegamos a esse momento. Isso pode ser bom para timestamp WITH time zonese, e somente se, as regras definidas pelas leis da região sobre fuso horário nunca mudarem. A regra mais comum que muda é sobre a adoção ou não do horário de verão (DST).

Por exemplo, imagine que você está, digamos, 2013-06-15(ainda não no horário de verão), programa algum evento para acontecer 2013-01-15 10:00(que já estaria no horário de verão) e na 2013-06-15sua região foi designado para adotar o horário de verão; mas, algum tempo depois disso, o governo mudou a regra e disse que sua região não usará mais o horário de verão e, de repente, o horário agendado se tornará 2013-01-15 11:00(em vez de 10:00), se você usar timestamp WITH time zone, e manter suas configurações de TZ atualizadas. É claro que você também pode perceber que é possível tratar esses casos também com fuso horário, se acompanhar as alterações das regras nas regiões / fusos horários de seu interesse e atualizar os registros afetados.

Vale ressaltar que algumas regiões frequentemente alteram essas regras (como no Brasil, alguns estados - e não todo o país - frequentemente mudam), mas na maioria dos casos elas são alteradas muito antes, para que seus usuários sejam afetados apenas por eventos agendados muito longe a hora atual.

Com tudo isso dito, só tenho mais uma sugestão. Se você possui usuários, logs ou qualquer coisa em fusos horários diferentes, armazene o fuso horário de onde eles vêm e escolha e use timestamp with time zone. Dessa forma, você pode (1) cruzar eventos que estão mais próximos entre si para diferentes fontes (independentemente de seus fusos horários) e (2) mostrar a hora original (a hora do relógio) em que o evento ocorreu.

MatheusOl
fonte
Você está dizendo: "Posso apenas ter um bom motivo para usar o carimbo de data / hora com o fuso horário". Se isso não é um erro de digitação, você está realmente sugerindo que "o carimbo de data / hora sem fuso horário" é realmente mais apropriado / menos propenso a produzir mal-entendidos do que "o carimbo de data / hora com fuso horário"? Isso parece contra-intuitivo para mim.
Marcus Junius Brutus
@ MarcusJuniusBrutus, desculpe por isso, foi realmente um erro de digitação e pensei o contrário ... Veja a resposta editada.
MatheusOl
codeblog.jonskeet.uk/2019/03/27/… discute em profundidade exatamente esse cenário de regras de eventos futuros - pode mudar (com a mesma conclusão)
Beni Cherniavsky-Paskin
17

Sim. Existem casos de uso para TIMESTAMP WITHOUT TIME ZONE.

  • Em aplicativos comerciais comuns, esse tipo seria usado apenas para:
    • Marcando compromissos futuros
    • Representando a mesma hora do dia em vários fusos horários, como o meio-dia do dia 23 em Tóquio e em Paris (dois momentos diferentes, separados por horas, a mesma hora do dia)
  • Para rastrear momentos, pontos específicos na linha do tempo, sempre use TIMESTAMP WITH TIME ZONE, não WITHOUT.

TIMESTAMP WITHOUT TIME ZONEvalores não são um ponto na linha do tempo, nem momentos reais. Eles representam uma idéia aproximada de momentos em potencial , possíveis pontos na linha do tempo ao longo de um período de 26 a 27 horas (o intervalo de fusos horários em todo o mundo). Eles não têm significado real até você aplicar um fuso horário ou um desvio do UTC .

Ex: Natal

Por exemplo, suponha que você precise registrar o início dos feriados / dias santos.

Table: holiday_

Column: year_         Type: SMALLINT
Column: description_  Type: VARCHAR
Column: start_        Type: TIMESTAMP WITHOUT TIME ZONE

Para registrar o fato de que o Natal começa depois da meia-noite de 25 de dezembro deste ano, precisamos dizer 2016-12-25 00:00:00sem fuso horário. No início do dia do Papai Noel, ele visita Auckland na Nova Zelândia logo após a meia-noite, pois é uma das primeiras noites do mundo. Então ele segue seu caminho para o oeste, como acontece a próxima meia-noite, logo chegando às Filipinas. Em seguida, as renas seguem em direção oeste, chegando à Índia à meia-noite, o que ocorre várias horas depois da meia-noite de Auckland. Muito mais tarde ainda é meia-noite em Paris FR, e ainda mais tarde em Montreal CA. Todas essas visitas do Papai Noel acontecem em momentos diferentes , mas ainda assim logo após a meia-noite, por meia-noite de cada localidade.

Portanto, gravar 2016-12-25 00:00:00sem fuso horário no início do Natal é informativo e legítimo, mas apenas vagamente. Até você dizer "Natal em Auckland" ou "Natal em Montreal", não temos um momento específico. Se você estiver gravando o momento real toda vez que o trenó tocar, você deve usar TIMESTAMP WITH TIME ZONEo WITHOUTtipo.

Semelhante ao Natal é a véspera de Ano Novo. Quando o Times Square Ball cai em Nova York , as pessoas em Seattle ainda estão tomando champanhe e preparando os chifres da festa . No entanto, gravaríamos a ideia do momento do ano novo como 2017-01-01 00:00:00em a TIMESTAMP WITHOUT TIME ZONE. Por outro lado, se queremos gravar quando a bola caiu em Nova York ou quando as pessoas em Seattle tocaram a buzina, em vez disso, usaríamos TIMESTAMP WITH TIME ZONE(não WITHOUT) para registrar esses momentos reais, cada três horas separados um do outro.

Ex: turnos de fábrica

Outro exemplo pode ser o registro de uma política que envolve o horário do relógio de parede em vários locais. Digamos que temos fábricas em Detroit, Düsseldorf e Delhi. Se dissermos que, nas três fábricas, o primeiro turno começa às 6 da manhã, com um intervalo para o almoço às 11:30, que pode ser registrado como a TIMESTAMP WITHOUT TIME ZONE. Novamente, essas informações são úteis de maneira vaga, mas não indicam um momento específico no tempo até aplicarmos um fuso horário. Um novo dia amanhece mais cedo no leste. Assim, a fábrica de Délhi será a primeira a abrir às seis da manhã. Horas depois, a fábrica de Düsseldorf começa a trabalhar às seis da manhã. Mas a fábrica de Detroit não abrirá até outras seis horas depois, quando as seis da manhã acontecerem.

Compare essa idéia (de quando o turno da fábrica geralmente começa) ao fato histórico de quando cada operário entrou em ação para iniciar seu turno em um determinado dia. A entrada do relógio é um momento real, um ponto real na linha do tempo. Então, gravaríamos isso em uma coluna do tipo TIMESTAMP WITH TIME ZONEe não do WITHOUTtipo.

Portanto, sim, existem casos de uso legítimos para TIMESTAMP WITHOUT TIME ZONE. Mas, na minha experiência com aplicativos de negócios, eles são relativamente raros. Nos negócios, tendemos a nos preocupar com momentos reais: quando a fatura realmente chegou, quando exatamente esse contrato entra em vigor, em que momento a transação bancária foi executada. Então, em situações tão comuns, queremos o TIMESTAMP WITH TIME ZONEtipo.

Para obter mais discussões, consulte minha resposta à pergunta semelhante. Devo armazenar registros de data e hora UTC ou hora local para turnos

Postgres

Observe que o Postgres especificamente nunca salva as informações de fuso horário especificadas ao inserir um carimbo de data / hora.

  • TIMESTAMP WITH TIME ZONE
    • Qualquer fuso horário ou deslocamento especificado incluído nos dados de entrada é usado para ajustar o valor para UTC e armazenado. A informação da zona / deslocamento passada é então descartada. Pense TIMESTAMP WITH TIME ZONEcomo TIMESTAMP WITH RESPECT FOR TIME ZONE.
    • Uma entrada do meio-dia de 7 de março deste ano na Índia terá sua hora do dia ajustada para UTC, subtraindo cinco horas e meia: 6h30.
  • TIMESTAMP WITHOUT TIME ZONE
    • Qualquer fuso horário ou deslocamento especificado incluído nos dados de entrada é totalmente ignorado.
    • Uma entrada de 12:00 no dia 7 de março deste ano na Índia é registrada como 12:00 no dia 7 de março deste ano sem nenhum ajuste.

O padrão SQL mal toca em questões de tipos e comportamento de dados de data e hora. Portanto, o banco de dados varia amplamente na manipulação da data e hora.

Basil Bourque
fonte
além dos turnos de fábrica (ou hospital), qualquer pessoa que trabalhe no turno da noite nos dias de mudança de horário de verão terá suas horas gravadas incorretamente, sem o fuso horário.
Jasen
Acho que há um erro de digitação no último exemplo: 'Uma entrada do meio-dia de 12:00 em 7 de março .. deve ser' registrada como 12 : 00 '(não 21:00)
TmTron
11

Gostaria de acrescentar outra visão a isso, que contraria muito do que foi escrito nas outras respostas. Na minha opinião, timestamp with time zonetem muito pouco casos de uso válidos e timestamp without time zone, em geral , deve ser preferido.

Primeiro, você deve entender o padrão "UTC em todos os lugares", geralmente recomendado para todos os aplicativos que não possuem requisitos muito especiais. Simplesmente significa que seu aplicativo deve representar todos os carimbos de data e hora no UTC, em qualquer lugar e em qualquer lugar. Obviamente, você mostrará a data / hora local para os usuários, mas a ideia é convertê-los na extremidade do seu programa, ao renderizar a exibição. Este é o lugar certo para combinar o carimbo de data / hora UTC (que você pode ter carregado de um banco de dados) e o fuso horário do usuário (que pode ter vindo do navegador) em um carimbo de data / hora local.

Se você está seguindo esse padrão, timestamp with time zoneé um anti-padrão. Tudo isso faz com que o PostgreSQL realize conversões de fuso horário ao ler e escrever carimbos de data / hora, com base na sua TimeZonevariável de sessão do PostgreSQL . Em vez de lidar com fusos horários nas extremidades do seu aplicativo, você os introduziu no coração, na própria comunicação com o banco de dados. Você deve sempre ter o PostgreSQL sempre TimeZoneconfigurado corretamente, adicionando outro ponto desnecessário de falha e confusão.

E para quê? Se você estiver seguindo o padrão UTC em todos os lugares, seu aplicativo só terá carimbos de data e hora UTC; então por que pedir ao seu banco de dados para fazer conversões de fuso horário neles? Você pode simplesmente armazená-los em uma timestamp without time zonecoluna e tratá-los como se fossem sempre UTC. Sem conversões, sem fusos horários, sem complicações.

Shay Rojansky
fonte
2
Penso que os proponentes do timestamptz também apóiam o padrão "UTC em todos os lugares". É apenas uma regra que é aplicada no nível do banco de dados, em vez de depender apenas de desenvolvedores de aplicativos / API para aplicá-lo? Se você é capaz de impor essa prática, por que não? Além disso, você pode garantir que todas as conexões do postgres definam seu fuso horário como UTC. Mesmo se não o fizerem, o formato ISO conterá o deslocamento de tz. Portanto, não é a mesma coisa que o UTC em todos os lugares, exceto o imposto?
Iamnat 22/08
3
Primeiro, se o seu PostgreSQL TimeZone estiver definido como qualquer coisa, exceto o UTC, e você estiver usando timestamptz, seu programa estará lendo registros de data e hora não UTC. Este simplesmente não é o padrão "UTC em todos os lugares" e, dependendo do idioma do seu cliente, pode ou não criar muitas complicações. Ou você é UTC em todos os lugares, ou você está usando timestamps locais ....
Shay Rojansky
Segundo, mais uma vez, se você é UTC em qualquer lugar do seu aplicativo, simplesmente não há deslocamento de tz para enviar no formato ISO para seus carimbos de data e hora. As especificidades variam entre idiomas, mas você deve, idealmente, usar um tipo de cliente que não é capaz de representar nada além de um carimbo de data / hora UTC (por exemplo, um Instanceno NodaTime / JodaTime). Você está descrevendo basicamente uma situação onde "UTC em todos os lugares" é quase seguidos, ou meio que seguiu ...
Shay Rojansky
Mais uma vez, é muito fácil imaginar uma nova instância do PostgreSQL sendo configurada em algum servidor, mantendo acidentalmente o fuso horário da máquina local que é configurado por padrão. Os aplicativos lêem neste servidor e obtêm carimbos de data e hora locais em um fuso horário totalmente arbitrário (no qual o servidor está). Por que queremos essa complicação adicional?
Shay Rojansky
11
Poderia, mas então faria ainda menos sentido usar timestamptz. O objetivo deste tipo é realizar conversões de fuso horário como valores lidos e gravados no PostgreSQL (internamente no banco de dados, o registro de data e hora é sempre salvo como UTC). Sempre definir o fuso horário da sessão como UTC desativa efetivamente essas conversões. Por que usar timestamptz? Dito de outra forma, se os valores no banco de dados são UTC e os valores que entram e saem do banco de dados são sempre UTC, por que o reconhecimento de fuso horário está presente no banco de dados?
Shay Rojansky em 21/01
2

O dateregistro de data e hora também não inclui informações de fuso horário, mas muitas pessoas as usam.

Claro, isso por si só não é uma resposta.

É válido usar timestampe datepara quaisquer carimbos de data e hora que estejam sempre no mesmo fuso horário ou que estejam sendo armazenados em relação a algum fuso horário conhecido.

Se o fuso horário for sempre o mesmo ou implícito, é mais antipadrão armazená-lo do que não armazená-lo (informações redundantes).

Os carimbos de data / hora também podem ser usados ​​para armazenar informações técnicas, como usadas nos logs do aplicativo ou para medições de desempenho. Nesse caso, o fuso horário também pode não ter importância.


Por outro lado, se você estiver projetando ou trabalhando em um sistema distribuído ou em qualquer sistema em que partes do sistema sejam distribuídas por fusos horários diferentes, pode ser considerado um antipadrão a não ser utilizado timestamp with timezone, embora alguns sistemas possam ser projetados para execução em um fuso horário, por exemplo, UTC. Nesse caso, a lógica do fuso horário pode estar sendo empurrada para a camada de aplicativo - mas eu consideraria isso um antipadrão, sim.

Colin 't Hart
fonte
Entendo que em certos casos não dói de usar timestamp without timezone, mas alguma vez me compra alguma coisa? Caso contrário, por que devo me preocupar se o timestamp with timezone datatipo é sempre igualmente ou mais apropriado?
Marcus Junius Brutus
Não armazenar informações redundantes seria o meu principal argumento. Presumo data aritmética em timestamp without timezoneseria mais rápido, também, mas que é provavelmente apenas importante se você estiver processando bilhões de linhas ...
Colin 't Hart
11
@ Colin'tHart timestampe timestamptzambos são armazenados da mesma maneira. Não há informações de fuso horário sendo armazenadas em a timestamptz, mas elas são convertidas em UTC para armazenamento. Eu diria, sempre use timestamptzquando os timestamps em questão denotarem tempo absoluto . Isso é tudo o que timestamptzsignifica. Eu escrevi sobre isso aqui .
Fphilipe
2

Pode parecer tentador armazenar e processar datas / horas no horário local se seu aplicativo estiver limitado a um único fuso horário, mas acredito que isso seja um erro.

Ao voltar do horário de verão para o horário padrão, uma hora no horário local é repetida (supondo que a diferença seja de uma hora). Onde eu moro, isso normalmente acontece por volta das 2h da manhã. O horário local é 01:58, 01:59, 01:00 e avança para 02:00 no final da hora repetida.

Se você tentar ordenar eventos por horário usando a hora local, isso significa que os eventos de duas horas separadas são misturados e não aparecem na ordem em que eles realmente ocorreram.

Em comparação, o UTC não tem esse problema e faz pedidos de forma limpa. Portanto, mesmo ao trabalhar com apenas um fuso horário, você deseja que o banco de dados armazene e processe horários no UTC e converta para / da hora local para entrada / exibição. Esse é o comportamento do TIMESTAMP WITH TIME ZONE.

Steve Fosdick
fonte