Java: Por que o construtor de data está obsoleto e o que eu uso em vez disso?

Eu venho do mundo C #, por isso não muito experiente com Java ainda. Foi informado pelo Eclipse que a Date foi descontinuada.

 Person p = new Person(); p.setDateOfBirth(new Date(1985, 1, 1)); 

Por quê? E o que (especialmente em casos como acima) deve ser usado em vez disso?

O construtor de data específico está obsoleto e um calendar deve ser usado em vez disso. O JavaDoc for Date descreve quais construtores foram reprovados e como substituí-los usando um Calendar.

A class java.util.Date não está de fato obsoleta, apenas esse construtor, juntamente com alguns outros construtores / methods, estão obsoletos. Foi descontinuado porque esse tipo de uso não funciona bem com a internacionalização. A class Calendar deve ser usada no lugar:

 Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, 1988); cal.set(Calendar.MONTH, Calendar.JANUARY); cal.set(Calendar.DAY_OF_MONTH, 1); Date dateRepresentation = cal.getTime(); 

Dê uma olhada na data Javadoc:

http://download.oracle.com/javase/6/docs/api/java/util/Date.html

tl; dr

 LocalDate.of( 1985 , 1 , 1 ) 

…ou…

 LocalDate.of( 1985 , Month.JANUARY , 1 ) 

Detalhes

As classs java.util.Date , java.util.Calendar e java.text.SimpleDateFormat foram aceleradas muito rapidamente quando o Java foi lançado e evoluiu pela primeira vez. As classs não foram bem projetadas ou implementadas. Melhorias foram tentadas, assim, as depreciações que você encontrou. Infelizmente, as tentativas de melhoria falharam em grande parte. Você deve evitar essas classs completamente. Eles são suplantados no Java 8 por novas classs.

Problemas no seu código

Um java.util.Date tem uma parte de data e hora. Você ignorou a parte do tempo em seu código. Portanto, a class Date terá o início do dia conforme definido pelo fuso horário padrão da sua JVM e aplicará essa hora ao object Date. Assim, os resultados do seu código irão variar dependendo de qual máquina é executada ou qual fuso horário está definido. Provavelmente não é o que você quer.

Se você quiser apenas a data, sem a parte do tempo, como para uma data de nascimento, talvez não queira usar um object Date . Você pode querer armazenar apenas uma string da data, no formato ISO 8601 de YYYY-MM-DD . Ou use um object LocalDate do Joda-Time (veja abaixo).

Joda-Time

A primeira coisa a aprender em Java: Evite as notoriamente problemáticas classs java.util.Date e java.util.Calendar empacotadas com Java.

Como observado corretamente na resposta de user3277382 , use o Joda-Time ou o novo pacote java.time. * No Java 8.

Exemplo de código no Joda-Time 2.3

 DateTimeZone timeZoneNorway = DateTimeZone.forID( "Europe/Oslo" ); DateTime birthDateTime_InNorway = new DateTime( 1985, 1, 1, 3, 2, 1, timeZoneNorway ); DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" ); DateTime birthDateTime_InNewYork = birthDateTime_InNorway.toDateTime( timeZoneNewYork ); DateTime birthDateTime_UtcGmt = birthDateTime_InNorway.toDateTime( DateTimeZone.UTC ); LocalDate birthDate = new LocalDate( 1985, 1, 1 ); 

Despeje para consolar…

 System.out.println( "birthDateTime_InNorway: " + birthDateTime_InNorway ); System.out.println( "birthDateTime_InNewYork: " + birthDateTime_InNewYork ); System.out.println( "birthDateTime_UtcGmt: " + birthDateTime_UtcGmt ); System.out.println( "birthDate: " + birthDate ); 

Quando correr …

 birthDateTime_InNorway: 1985-01-01T03:02:01.000+01:00 birthDateTime_InNewYork: 1984-12-31T21:02:01.000-05:00 birthDateTime_UtcGmt: 1985-01-01T02:02:01.000Z birthDate: 1985-01-01 

java.time

Neste caso, o código para java.time é quase idêntico ao de Joda-Time .

ZoneId um fuso horário ( ZoneId ) e construímos um object de data e hora atribuído a esse fuso horário ( ZonedDateTime ). Em seguida, usando o padrão de Objetos Imutáveis , criamos novos tempos de data com base no mesmo instante do antigo object (contagem de nanossegundos desde a época ), mas atribuídos a outro fuso horário. Por fim, recebemos uma LocalDate que não tem hora do dia nem fuso horário, embora o fuso horário se aplique ao determinar essa data (um novo dia amanhece mais cedo em Oslo do que em Nova York, por exemplo).

 ZoneId zoneId_Norway = ZoneId.of( "Europe/Oslo" ); ZonedDateTime zdt_Norway = ZonedDateTime.of( 1985 , 1 , 1 , 3 , 2 , 1 , 0 , zoneId_Norway ); ZoneId zoneId_NewYork = ZonedId.of( "America/New_York" ); ZonedDateTime zdt_NewYork = zdt_Norway.withZoneSameInstant( zoneId_NewYork ); ZonedDateTime zdt_Utc = zdt_Norway.withZoneSameInstant( ZoneOffset.UTC ); // Or, next line is similar. Instant instant = zdt_Norway.toInstant(); // Instant is always in UTC. LocalDate localDate_Norway = zdt_Norway.toLocalDate(); 

Sobre o java.time

O framework java.time está embutido no Java 8 e posterior. Essas classs substituem as antigas classs herdadas de data e hora legadas , como java.util.Date , Calendar e SimpleDateFormat .

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

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

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

Onde obter as classs 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 integrada.
    • O Java 9 adiciona alguns resources e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é transferida para o Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações do pacote Android das classs java.time.
    • Para Android anterior (<26), o projeto ThreeTenABP adapta o ThreeTen-Backport (mencionado acima). Veja Como usar o ThreeTenABP… .

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

Me deparei com essa pergunta como uma duplicata de uma pergunta mais recente que perguntou qual era a maneira não depreciada de obter uma Date em um ano, mês e dia específico.

As respostas aqui até agora dizem para usar a class Calendar , e isso era verdade até o Java 8 aparecer. Mas, a partir do Java 8, a maneira padrão de fazer isso é:

 LocalDate localDate = LocalDate.of(1985, 1, 1); 

E então, se você realmente precisa de um java.util.Date , pode usar as sugestões desta pergunta .

Para mais informações, confira a API ou os tutoriais do Java 8.

Um motivo pelo qual o construtor é obsoleto é que o significado do parâmetro ano não é o que você esperaria. O javadoc diz:

A partir do JDK versão 1.1, substituído por Calendar.set(year + 1900, month, date) .

Observe que o campo ano é o número de anos desde 1900 , portanto, seu código de amostra provavelmente não fará o que você espera que ele faça. E esse é o ponto.

Em geral, a API Date suporta apenas o calendar ocidental moderno, possui componentes especificados idiossincraticamente e se comporta de maneira inconsistente se você definir campos.

As APIs do Google Calendar e do GregorianCalendar são melhores do que a Date , e as APIs do Joda-time de terceiros geralmente são consideradas as melhores. No Java 8, eles introduziram os pacotes java.time e agora são a alternativa recomendada.

Observe que Calendar.getTime() é não determinístico no sentido de que a parte do horário do dia é padronizada para a hora atual.

Para reproduzir, tente executar o código a seguir um par de vezes:

 Calendar c = Calendar.getInstance(); c.set(2010, 2, 7); // NB: 2 means March, not February! System.err.println(c.getTime()); 

Saída por exemplo .:

 Sun Mar 07 10:46:21 CET 2010 

Executar exatamente o mesmo código alguns minutos depois produz:

 Sun Mar 07 10:57:51 CET 2010 

Assim, enquanto set() força os campos correspondentes a corrigir valores, ele vaza a hora do sistema para os outros campos. (Testado acima com Sun jdk6 e jdk7)

Date própria Date não é reprovada. É apenas um monte de seus methods são. Veja aqui para detalhes .

Use java.util.Calendar vez disso.

A maioria dos desenvolvedores Java atualmente usa o pacote de terceiros Joda-Time . É amplamente considerado como uma implementação muito melhor.

O Java 8, no entanto, terá um novo pacote java.time. * . Consulte este artigo, Apresentando a nova API de data e hora do JDK 8 .

Semelhante ao que o binnyb sugeriu, você pode considerar o uso do mais novo método Calendar> GregorianCalendar. Veja estes documentos mais recentes:

http://download.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html

Você pode criar um método como a new Date(year,month,date) no seu código usando a class Calendar .

 private Date getDate(int year,int month,int date){ Calendar cal = Calendar.getInstance(); cal.set(Calendar.YEAR, year); cal.set(Calendar.MONTH, month-1); cal.set(Calendar.DAY_OF_MONTH, day); return cal.getTime(); } 

Ele funcionará exatamente como o construtor obsoleto do Date