Qual é a diferença entre Instant e LocalDateTime?

256

Eu sei disso:

  • O Instant é uma representação "técnica" de carimbo de data / hora (nanossegundos) para a computação.
  • LocalDateTime é uma representação de data / relógio, incluindo fusos horários para humanos.

Ainda no final, o IMO pode ser considerado como um tipo para a maioria dos casos de uso de aplicativos. Como exemplo: no momento, estou executando um trabalho em lotes no qual preciso calcular uma próxima execução com base nas datas e lutando para encontrar prós / contras entre esses dois tipos (além da vantagem de precisão em nanossegundos do Instant e da parte do fuso horário LocalDateTime).

Você pode citar alguns exemplos de aplicativos, onde apenas Instant ou LocalDateTime devem ser usados?

Edit: Cuidado com as documentações mal interpretadas do LocalDateTime sobre precisão e fuso horário

manuel aldana
fonte
O instante é mais elementar, envolvendo o padrão por muito tempo para o UTC. Para um cron como lote não é uma escolha tão lógica.
Joop Eggen
37
Definição incorreta . LocalDateTimese não tiver um fuso horário!
Basil Bourque

Respostas:

832

Tabela de todos os tipos de data e hora em Java, modernos e herdados

tl; dr

Instante LocalDateTimesão dois animais completamente diferentes: um representa um momento, o outro não.

  • Instant representa um momento, um ponto específico na linha do tempo.
  • LocalDateTimerepresenta uma data e uma hora do dia. Mas, sem um fuso horário ou deslocamento do UTC, essa classe não pode representar um momento . Representa momentos em potencial ao longo de um intervalo de cerca de 26 a 27 horas, o intervalo de todos os fusos horários do mundo.

Presunção incorreta

LocalDateTime é uma representação de data / relógio, incluindo fusos horários para humanos.

Sua declaração está incorreta: A nãoLocalDateTime possui fuso horário . Não ter fuso horário é o ponto principal dessa classe.

Para citar o documento dessa classe:

Esta classe não armazena ou representa um fuso horário. Em vez disso, é uma descrição da data, usada para aniversários, combinada com a hora local, como vista em um relógio de parede. Não pode representar um instante na linha do tempo sem informações adicionais, como um deslocamento ou fuso horário.

Então Local…significa "não zoneado, sem deslocamento".

Instant

insira a descrição da imagem aqui

An Instanté um momento na linha do tempo no UTC , uma contagem de nanossegundos desde a época do primeiro momento de 1970 no UTC (basicamente, consulte a classe doc para obter detalhes minuciosos). Como a maior parte da lógica de negócios, armazenamento de dados e troca de dados deve estar no UTC, essa é uma classe útil a ser usada com frequência.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

OffsetDateTime

insira a descrição da imagem aqui

A turma da OffsetDateTimeturma representa um momento como data e hora com um contexto de um número de horas-minutos-segundos antes ou atrás do UTC. A quantidade de deslocamento, o número de horas-minutos-segundos, é representada pela ZoneOffsetclasse.

Se o número de horas-minutos-segundos for zero, um OffsetDateTimerepresenta um momento no UTC igual a um Instant.

ZoneOffset

insira a descrição da imagem aqui

A ZoneOffsetclasse representa um deslocamento do UTC , um número de horas-minutos-segundos antes do UTC ou atrás do UTC.

A ZoneOffseté apenas um número de horas-minutos-segundos, nada mais. Uma zona é muito mais, com um nome e um histórico de alterações a serem compensadas. Portanto, sempre é preferível usar uma zona do que usar um mero deslocamento.

ZoneId

insira a descrição da imagem aqui

Um fuso horário é representado pela ZoneIdclasse.

Um novo dia amanhece mais cedo em Paris do que em Montreal , por exemplo. Portanto, precisamos mover os ponteiros do relógio para refletir melhor o meio-dia (quando o Sol está diretamente no alto) para uma determinada região. Quanto mais distante o leste / oeste da linha UTC no oeste da Europa / África, maior o deslocamento.

Um fuso horário é um conjunto de regras para lidar com ajustes e anomalias, conforme praticado por uma comunidade ou região local. A anomalia mais comum é a loucura popular, conhecida como Horário de Verão (DST) .

Um fuso horário tem o histórico de regras passadas, regras presentes e regras confirmadas em um futuro próximo.

Essas regras mudam com mais frequência do que você poderia esperar. Certifique-se de manter as regras da sua biblioteca de data e hora, geralmente uma cópia do banco de dados 'tz' , atualizada. Manter-se atualizado é mais fácil do que nunca agora no Java 8, com o Oracle lançando uma Ferramenta de Atualização do Fuso Horário .

Especifique um nome próprio fuso horário no formato Continent/Region, como America/Montreal, Africa/Casablanca, ou Pacific/Auckland. Nunca use o 2-4 letras, como ESTou ISTcomo eles são não zonas verdadeiros tempo, não padronizados, e nem mesmo única (!).

Fuso Horário = Deslocamento + Regras de Ajustes

ZoneId z = ZoneId.of( Africa/Tunis ) ; 

ZonedDateTime

insira a descrição da imagem aqui

Pense ZonedDateTimeconceitualmente como um Instantcom um atribuído ZoneId.

ZonedDateTime = (Instantâneo + ZoneId)

Para capturar o momento atual como visto no relógio de parede usado pelas pessoas de uma região específica (um fuso horário):

ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`. 

Quase todo o seu back-end, banco de dados, lógica de negócios, persistência de dados e troca de dados devem estar no UTC. Mas para a apresentação aos usuários, você precisa ajustar o fuso horário esperado pelo usuário. Esse é o objetivo da ZonedDateTimeclasse e das classes do formatador usadas para gerar representações de String desses valores de data e hora.

ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ;                 // Standard ISO 8601 format.

Você pode gerar texto no formato localizado usando DateTimeFormatter.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ; 
String outputFormatted = zdt.format( f ) ;

terça-feira 30 de abril 2019, às 23 h 22 min 55 s heure de l'Inde

LocalDate, LocalTime,LocalDateTime

Diagrama mostrando apenas um calendário para um <code> LocalDate </code>.

Diagrama mostrando apenas um relógio para um <code> LocalTime </code>.

Diagrama mostrando um calendário mais um relógio para um <code> LocalDateTime </code>.

As classes de data e hora "locais", LocalDateTime, LocalDate, LocalTime, são um tipo diferente de criatura. O não está vinculado a nenhuma localidade ou fuso horário. Eles não estão vinculados à linha do tempo. Eles não têm significado real até que você os aplique a uma localidade para encontrar um ponto na linha do tempo.

A palavra "Local" nesses nomes de classe pode ser contra-intuitiva para os não iniciados. A palavra significa qualquer localidade, ou toda localidade, mas não uma localidade específica.

Portanto, para aplicativos de negócios, os tipos "Local" geralmente não são usados, pois representam apenas a idéia geral de uma possível data ou hora, não um momento específico na linha do tempo. Os aplicativos de negócios tendem a se importar com o momento exato em que uma fatura chegou, um produto enviado para transporte, um funcionário foi contratado ou o táxi saiu da garagem. Portanto, os desenvolvedores de aplicativos de negócios usam Instante ZonedDateTimeclassificam com mais frequência.

Então, quando usaríamos LocalDateTime? Em três situações: onde queremos aplicar uma determinada data e hora do dia em vários locais, onde estamos agendando compromissos ou onde temos um fuso horário ainda indeterminado. Observe que nenhum desses três casos é um único ponto específico na linha do tempo; nenhum deles é um momento.

Uma hora do dia, vários momentos

Às vezes, queremos representar uma determinada hora do dia em uma determinada data, mas queremos aplicá-la em várias localidades em fusos horários.

Por exemplo, "O Natal começa à meia-noite de 25 de dezembro de 2015" é a LocalDateTime. A meia-noite ocorre em diferentes momentos em Paris do que em Montreal, e novamente diferente em Seattle e Auckland .

LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ;   // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ;  // Xmas morning anywhere. 

Outro exemplo, "A Acme Company tem uma política de que a hora do almoço começa às 12h30 em cada uma de suas fábricas em todo o mundo" é a LocalTime. Para ter um significado real, é necessário aplicá-lo à linha do tempo para calcular o momento das 12:30 na fábrica de Stuttgart ou 12:30 na fábrica de Rabat ou 12:30 na fábrica de Sydney .

Marcação de marcações

Outra situação a ser usada LocalDateTimeé para reservar eventos futuros (por exemplo: consultas com dentistas). Essas nomeações podem estar suficientemente longe no futuro, para que você arrisque os políticos a redefinir o fuso horário. Os políticos costumam dar pouco aviso prévio, ou mesmo nenhum aviso. Se você quer dizer "15:00 no próximo dia 23 de janeiro", independentemente de como os políticos possam jogar com o relógio, não é possível gravar um momento - isso faria as 15:00 se transformarem em 14:00 ou 16:00 se a região adotasse ou diminuísse o horário de verão, por exemplo.

Para compromissos, armazene ae LocalDateTimea ZoneId, mantidos separadamente. Mais tarde, ao gerar uma programação, determine rapidamente um momento chamando LocalDateTime::atZone( ZoneId )para gerar um ZonedDateTimeobjeto.

ZonedDateTime zdt = ldt.atZone( z ) ;  // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.

Se necessário, você pode ajustar para UTC. Extraia um Instantdo ZonedDateTime.

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

Zona desconhecida

Algumas pessoas podem usar LocalDateTimeem uma situação em que o fuso horário ou deslocamento é desconhecido.

Considero este caso inadequado e imprudente. Se uma zona ou deslocamento for planejado, mas indeterminado, você terá dados incorretos. Seria como armazenar o preço de um produto sem saber a moeda pretendida. Não é uma boa ideia.

Todos os tipos de data e hora

Para garantir a integridade, aqui está uma tabela de todos os tipos possíveis de data e hora, modernos e herdados em Java, além daqueles definidos pelo padrão SQL. Isso pode ajudar a colocar as classes Instant& LocalDateTimeem um contexto maior.

Tabela de todos os tipos de data e hora em Java (moderno e herdado), bem como no padrão SQL.

Observe as escolhas ímpares feitas pela equipe Java no design do JDBC 4.2. Eles escolheram dar suporte a todos os tempos java.time … exceto pelas duas classes mais usadas: Instant& ZonedDateTime.

Mas não se preocupe. Podemos facilmente converter para frente e para trás.

Convertendo Instant.

// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;

Convertendo ZonedDateTime.

// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject(  , odt ) ;

// Retrieving
OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ; 

Sobre java.time

A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date, Calendar, e SimpleDateFormat.

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .

Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Você pode trocar objetos java.time diretamente com seu banco de dados. Use um driver JDBC compatível com JDBC 4.2 ou posterior. Não há necessidade de strings, não há necessidade de java.sql.*classes.

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 , Java SE 10 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação em pacote configurável.
    • O Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações de pacote configurável do Android das classes java.time.
    • Para anteriormente Android (<26), o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

Tabela de qual biblioteca java.time a ser usada com qual versão do Java ou Android

O projeto ThreeTen-Extra estende o java.time com classes adicionais. Este projeto é um campo de prova para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .

Basil Bourque
fonte
40
Ótima resposta. Eu acho que alguma confusão (pelo menos a minha) vem do Localnome. Minha intuição por Localmeios em relação a onde estou E quando estou (?!), O que me leva a acreditar que seria realmente o que ZonedDateTimeé.
Mkobit # 8/15
4
Sim, é confuso. É por isso que java.time habilmente adicionou a palavra 'Zoned' ao DateTimenome da classe usado por seu antecessor Joda-Time (produtor ZonedDateTime), para enfatizar a diferença das classes "Local". Pense no nome "Local" como abreviação de "precisando ser aplicado a alguma localidade específica".
Basil Bourque
2
Prefixar a palavra Localtambém pode ter sido uma maneira de diferenciar o pacote java.util, embora, de alguma forma, eu ache que poderia haver uma melhor escolha de palavra.
vphilipnyc
2
@simonh Pelo contrário ... Quando esse novo funcionário assinar seus documentos de contratação definindo seus benefícios, incluindo o seguro de vida, e depois os novos funcionários sairem para um café para serem atingidos e mortos por um caminhão, haverá muitas pessoas como como gerentes de recursos humanos, agentes de seguros e advogados que desejam saber o momento exato em que esse novo emprego entrou em vigor.
Basil Bourque
2
@simonh Sim, há casos em que a data e hora "local" é apropriada. Além dos mencionados em minha resposta, outro caso comum nos negócios é que as nomeações serão feitas dentro de alguns meses no futuro, longe o suficiente para que os políticos possam mudar as regras do fuso horário, geralmente com pouco aviso. Os políticos costumam fazer essas alterações, como alterar as datas ao ativar / desativar o horário de verão (DST) ou permanecer / desativar permanentemente o horário de verão.
Basil Bourque
20

Uma diferença principal é a Localparte de LocalDateTime. Se você mora na Alemanha e cria uma LocalDateTimeinstância e alguém mora nos EUA e cria outra instância no mesmo momento (desde que os relógios estejam configurados corretamente) - o valor desses objetos seria realmente diferente. Isso não se aplica a Instant, calculado independentemente do fuso horário.

LocalDateTimearmazena data e hora sem fuso horário, mas seu valor inicial depende do fuso horário. Instantnão é.

Além disso, LocalDateTimefornece métodos para manipular componentes de data, como dias, horas, meses. Um Instantnão.

além da vantagem de precisão em nanossegundos do Instant e a parte de fuso horário do LocalDateTime

Ambas as classes têm a mesma precisão. LocalDateTimenão armazena fuso horário. Leia os javadocs completamente, pois você pode cometer um grande erro com essas suposições inválidas: Instant e LocalDateTime .

Dariusz
fonte
desculpe pela leitura incorreta da peça na zona + precisão. Desculpe por repetir a partir da postagem acima: Considerando um único aplicativo de fuso horário, em quais casos de uso você preferiria LocalDateTime ou vice-versa?
manuel aldana
1
Eu usaria LocalDateTime sempre que eu precisar de datas e / ou horários. Em horas, minutos ou mais. Eu usaria o Instant para medir os tempos de execução, por exemplo, ou armazenar um campo interno de sth acontecendo naquele momento. Calculando as próximas execuções, como no seu caso? LocalDateTime parece apropriado, mas é uma opinião. Como você afirmou, ambos podem ser usados.
Dariusz
Você pode elaborar mais sobre LocalDateTime stores date and time without timezone, but it's initial value is timezone dependent? qual é o valor inicial e como é dependente do fuso horário? Obrigado.
Max
12

Você está errado LocalDateTime: ele não armazena nenhuma informação de fuso horário e possui precisão de nanossegundos. Citando o Javadoc (ênfase minha):

Uma data e hora sem fuso horário no sistema de calendário ISO-8601 , como 2007-12-03T10: 15: 30.

LocalDateTime é um objeto de data e hora imutável que representa uma data e hora, geralmente exibido como ano-mês-dia-hora-hora-minuto-segundo. Outros campos de data e hora, como dia do ano, dia da semana e semana do ano, também podem ser acessados. O tempo é representado com precisão de nanossegundos . Por exemplo, o valor "2 de outubro de 2007 às 13: 45.30.123456789" pode ser armazenado em um LocalDateTime.

A diferença entre os dois é que Instantrepresenta um deslocamento da época (01-01-1970) e, como tal, representa um instante específico na linha do tempo. Dois Instantobjetos criados no mesmo momento em dois lugares diferentes da Terra terão exatamente o mesmo valor.

Tunaki
fonte
Considerando um aplicativo de fuso horário único, em quais casos de uso você preferiria LocalDateTime ou vice-versa?
manuel aldana
3
@manuelaldana É mais uma questão de gosto. Prefiro LocalDateTime para qualquer coisa relacionada ao usuário (aniversário ...) e Instant para qualquer coisa relacionada à máquina (tempo de execução ...).
Tunaki
2
@manuelaldana Um aplicativo de fuso horário único é raro, se não inexistente. Você pode ignorar os fusos horários de um pequeno aplicativo que você criou para o seu clube de música barroca local. Porém, assim que você precisar postar um evento para as pessoas que viajam (e cruzam fusos horários), eles desejam esses dados vinculados a um fuso horário, para que seu aplicativo de calendário possa se ajustar conforme necessário. Sugiro que você aprenda a trabalhar com fusos horários adequadamente em todos os seus aplicativos.
Basil Bourque
@Tunaki O uso da palavra 'deslocamento' no último parágrafo é perturbador. Essa palavra tem um certo significado no trabalho de data e hora; portanto, seu uso aqui neste contexto pode ser inútil.
Basil Bourque
0

Instant corresponde ao tempo no meridiano de Greenwich (Greenwich).

Considerando que, em LocalDateTimerelação às configurações de fuso horário do SO, e

não pode representar um instante sem informações adicionais, como deslocamento ou fuso horário.

user2418306
fonte
2
O Instant baseia-se no UTC, não no GMT.
Torsten Ojaperv 16/08/19