tl; dr
Instant
e LocalDateTime
sã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.
LocalDateTime
representa 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
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
A turma da OffsetDateTime
turma 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 ZoneOffset
classe.
Se o número de horas-minutos-segundos for zero, um OffsetDateTime
representa um momento no UTC igual a um Instant
.
ZoneOffset
A ZoneOffset
classe 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
Um fuso horário é representado pela ZoneId
classe.
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 EST
ou IST
como 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
Pense ZonedDateTime
conceitualmente como um Instant
com 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 ZonedDateTime
classe 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
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 Instant
e ZonedDateTime
classificam 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 LocalDateTime
a ZoneId
, mantidos separadamente. Mais tarde, ao gerar uma programação, determine rapidamente um momento chamando LocalDateTime::atZone( ZoneId )
para gerar um ZonedDateTime
objeto.
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 Instant
do 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 LocalDateTime
em 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
& LocalDateTime
em um contexto maior.
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… .
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 .