PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Qual é a maneira mais recomendada de armazenar tempo no PostgreSQL usando Java?


Qualquer estratégia para armazenar dados de data e hora no PostgreSQL deve, IMO, contar com estes dois pontos:
  • Sua solução deve nunca dependem da configuração de fuso horário do servidor ou cliente.
  • Atualmente, o PostgreSQL (como a maioria dos bancos de dados) não possui um tipo de dados para armazenar um arquivo completo data e hora com fuso horário. Então, você precisa decidir entre um Instant ou um LocalDateTime tipo de dados.

Minha receita segue.

Se você quiser gravar o instantâneo físico quando um determinado evento ocorreu, (um verdadeiro "timestamp " , normalmente algum evento de criação/modificação/exclusão), então use:
  • Java:Instant (Java 8 ou Jodatime).
  • JDBC:java.sql.Timestamp
  • PostgreSQL:TIMESTAMP WITH TIMEZONE (TIMESTAMPTZ )

(Não deixe que tipos de dados peculiares do PostgreSQL WITH TIMEZONE /WITHOUT TIMEZONE confundir você:nenhum deles realmente armazena um fuso horário)

Algum código clichê:o seguinte assume que ps é uma PreparedStatement , rs um ResultSet e tzUTC é um Calendar estático objeto correspondente a UTC fuso horário.
public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));  

Escreva Instant para o banco de dados TIMESTAMPTZ :
Instant instant = ...;
Timestamp ts = instant != null ? Timestamp.from(instant) : null;
ps.setTimestamp(col, ts, tzUTC);   // column is TIMESTAMPTZ!

Leia Instant do banco de dados TIMESTAMPTZ :
Timestamp ts = rs.getTimestamp(col,tzUTC); // column is TIMESTAMPTZ
Instant inst = ts !=null ? ts.toInstant() : null;

Isso funciona com segurança se seu tipo de PG for TIMESTAMPTZ (Nesse caso, o calendarUTC não tem efeito nesse código; mas é sempre aconselhável não depender de fusos horários padrão). "Com segurança" significa que o resultado não dependerá do fuso horário do servidor ou do banco de dados , ou informações de fusos horários:a operação é totalmente reversível e, aconteça o que acontecer com as configurações de fusos horários, você sempre obterá o mesmo "instante de tempo" que tinha originalmente no lado do Java.

Se, em vez de um carimbo de data/hora (um instante na linha do tempo física), você estiver lidando com uma data e hora local "civil" (ou seja, o conjunto de campos {year-month-day hour:min:sec(:msecs)} ), você usaria:
  • Java:LocalDateTime (Java 8 ou Jodatime).
  • JDBC:java.sql.Timestamp
  • PostgreSQL:TIMESTAMP WITHOUT TIMEZONE (TIMESTAMP )

Leia LocalDateTime do banco de dados TIMESTAMP :
Timestamp ts = rs.getTimestamp(col, tzUTC); //
LocalDateTime localDt = null;
if( ts != null ) 
    localDt =  LocalDateTime.ofInstant(Instant.ofEpochMilli(ts.getTime()), ZoneOffset.UTC);

Escreva LocalDateTime para o banco de dados TIMESTAMP :
  Timestamp ts = null;
  if( localDt != null)    
      ts = new Timestamp(localDt.toInstant(ZoneOffset.UTC).toEpochMilli()), tzUTC);
  ps.setTimestamp(colNum,ts, tzUTC); 

Novamente, essa estratégia é segura e você pode dormir tranquilamente:se você armazenou 2011-10-30 23:59:30 , você recuperará esses campos precisos (hora =23, minuto =59 ... etc) sempre, não importa o que aconteça - mesmo que amanhã o fuso horário do seu servidor Postgresql (ou cliente) mude, ou sua JVM ou fuso horário do seu sistema operacional, ou se o seu país modificar suas regras de horário de verão, etc.

Adicionado:Se você quiser (parece um requisito natural) armazenar a especificação completa de data e hora (um ZonedDatetime :o carimbo de data e hora junto com o fuso horário, que implicitamente também inclui as informações completas de data e hora civil - mais o fuso horário) ... . Você deve criar seu próprio armazenamento, talvez em um par de campos:podem ser os dois tipos acima (altamente redundantes, embora eficientes para recuperação e cálculo), ou um deles mais o deslocamento de tempo (você perde as informações de fuso horário, alguns cálculos se tornam difícil, e alguns impossíveis), ou um deles mais o fuso horário (como string; alguns cálculos podem ser extremamente caros).