Qual é a melhor maneira de converter um java.util.Date
objeto no novo JDK 8 / JSR-310 java.time.LocalDate
?
Date input = new Date();
LocalDate date = ???
Resposta curta
Date input = new Date();
LocalDate date = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Explicação
Apesar do nome, java.util.Date
representa um instante na linha do tempo, não uma "data". Os dados reais armazenados no objeto são uma long
contagem de milissegundos desde 01-01-2009 - 00: 00Z (meia-noite no início de 1970 GMT / UTC).
A classe equivalente a java.util.Date
no JSR-310 é Instant
, portanto, existe um método conveniente toInstant()
para fornecer a conversão:
Date input = new Date();
Instant instant = input.toInstant();
Uma java.util.Date
instância não tem conceito de fuso horário. Isso pode parecer estranho se você chamar toString()
um java.util.Date
, porque toString
é relativo a um fuso horário. No entanto, esse método realmente usa o fuso horário padrão de Java rapidamente para fornecer a string. O fuso horário não faz parte do estado real de java.util.Date
.
Um Instant
também não contém nenhuma informação sobre o fuso horário. Assim, para converter de uma Instant
data para uma local, é necessário especificar um fuso horário. Esse pode ser o fuso horário padrão - ZoneId.systemDefault()
- ou pode ser um fuso horário que seu aplicativo controla, como um fuso horário nas preferências do usuário. Use o atZone()
método para aplicar o fuso horário:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
A ZonedDateTime
contém o estado que consiste na data e hora locais, no fuso horário e no deslocamento de GMT / UTC. Como tal, a data - LocalDate
- pode ser facilmente extraída usando toLocalDate()
:
Date input = new Date();
Instant instant = input.toInstant();
ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
LocalDate date = zdt.toLocalDate();
Resposta Java 9
No Java SE 9, foi adicionado um novo método que simplifica levemente esta tarefa:
Date input = new Date();
LocalDate date = LocalDate.ofInstant(input.toInstant(), ZoneId.systemDefault());
Essa nova alternativa é mais direta, criando menos lixo e, portanto, deve ter um desempenho melhor.
LocalDate.from(Instant.ofEpochMilli(date.getTime()))
acho que é equivalente ao seu, mas mais direto.Date
não tem conceito de fuso horário,Instant
também não contém informações sobre fuso horário. ALocalDate
API diz "Uma data sem fuso horário". Então, por que converter deDate
paraInstant
emLocalDate
necessidadesatZone(ZoneId.systemDefault())
?LocalDate
eLocalDateTime
não "armazena ou representa uma hora ou um fuso horário" (ref: javadocs). Enquanto eles não o armazenam - as classes representam umaLocal
data e / ou hora, portanto, a conversão para data / hora local implica um fuso horário.Melhor maneira é:
Vantagens desta versão:
funciona independentemente da entrada ser uma instância
java.util.Date
ou subclasse dejava.sql.Date
(diferente da maneira de @ JodaStephen). Isso é comum com dados originados por JDBC.java.sql.Date.toInstant()
sempre lança uma exceção.é o mesmo para o JDK8 e o JDK7 com backport JSR-310
Eu pessoalmente uso uma classe de utilitário (mas não é compatível com backport):
O
asLocalDate()
método aqui é seguro para nulos, usatoLocalDate()
, se a entrada forjava.sql.Date
(pode ser substituída pelo driver JDBC para evitar problemas de fuso horário ou cálculos desnecessários), caso contrário, usa o método mencionado acima.fonte
DateConvertUtils
.Date.toInstant()
.fonte
SimpleDateFormat
instância está confinada ao encadeamento atual. É usado de maneira segura para threads. Agora,SimpleDateFormat
tem a fama de ser 'caro para instanciar' (por conta de todas as estruturas de dados internas de que necessita), mas você não pode compartilhar um como um 'solteirão' (sem sincronizar o acesso a ele), porque ele na verdade não é thread- seguro. (UmaThreadLocal
solução pode funcionar se o código 'poluente')Thread
for responsável pelo ciclo de vida do encadeamento ... mas isso raramente acontece). Desajeitado. EvitarSimpleDateFormat
é o motivo do usojavax.time
.SimpleDateFormat
(que é jogada fora), a cadeia intermediária (que é jogada fora) e o custo da análise. É uma solução, mas não é recomendado.Se você estiver usando o Java 8, a resposta do @ JodaStephen é obviamente a melhor. No entanto, se você estiver trabalhando com o backport JSR-310 , infelizmente precisará fazer algo assim:
fonte
fonte
Você pode converter em uma linha:
fonte
primeiro, é fácil converter uma data em um instante
Em seguida, você pode converter a API do Instant para qualquer data no jdk 8 usando o método ofInstant ():
fonte
import java.sql.Date
em seu arquivo: otoInstant()
método dejava.sql.Date
sempre lança.A
Date
instância contém tempo também, juntamente com a data, enquantoLocalDate
não. Portanto, você pode convertê-lo primeiro emLocalDateTime
usar seu métodoofInstant()
e, se desejar, sem tempo, em seguida, converter a instância emLocalDate
.fonte
esse formato é de
Date#tostring
fonte
Eu tive problemas com a implementação do @ JodaStephen no JBoss EAP 6. Portanto, reescrevi a conversão seguindo o Tutorial Java do Oracle em http://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html .
fonte
O que há de errado com esta 1 linha simples?
fonte
Resolvi esta questão com a solução abaixo
Nesse caso, localDate imprima sua data neste formato "aaaa-MM-dd"
fonte
java.time
classes no JDK8, não no Joda Time.