Diferença entre a class Date no pacote java.util & Package java.sql

Em java, o pacote java.util e o pacote java.sql contêm uma class Date . Então, qual é a diferença entre eles?

Se uma class Date estiver presente em Java, então qual é a necessidade de outra class Date ?

Do JavaDoc de java.sql.Date :

Um wrapper fino em torno de um valor de milissegundos que permite que o JDBC identifique isso como um valor SQL DATE. Um valor de milissegundos representa o número de milissegundos que se passaram desde 1º de janeiro de 1970 00: 00: 00.000 GMT.

Para estar em conformidade com a definição de SQL DATE, os valores em milissegundos envolvidos por uma instância java.sql.Date devem ser ‘normalizados’ definindo as horas, minutos, segundos e milissegundos para zero no fuso horário específico ao qual a instância está associada .

Explicação: Um java.util.Date representa a data e hora do dia, um java.sql.Date representa apenas uma data (o complemento de java.sql.Date é java.sql.Time , que representa apenas uma hora do dia, mas também estende java.util.Date ).

Essas respostas parecem estar parcialmente desatualizadas.

Acabei de ler um pequeno código de API (Java versão 1.8.0_91) e encontrei isso em java.sql.Date :

 /** * Creates a date which corresponds to the day determined by the supplied * milliseconds time value {@code theDate}. * * @param theDate * a time value in milliseconds since the epoch - January 1 1970 * 00:00:00 GMT. The time value (hours, minutes, seconds, * milliseconds) stored in the {@code Date} object is adjusted to * correspond to 00:00:00 GMT on the day determined by the supplied * time value. */ public Date(long theDate) { super(normalizeTime(theDate)); } /* * Private method which normalizes a Time value, removing all low * significance digits corresponding to milliseconds, seconds, minutes and * hours, so that the returned Time value corresponds to 00:00:00 GMT on a * particular day. */ private static long normalizeTime(long theTime) { return theTime; } 

O método para normalizar o tempo ainda está lá e até o comentário diz que o horário será normalizado para 00:00:00 GMT mas não faz nada. Por alguma razão, eles removeram a normalização, o que significa que um java.sql.Date contém exatamente como um java.util.Date apenas o número de milissegundos desde 1.1.1970. Portanto, há um componente de tempo, mas não é exibido externamente.

Por exemplo, o código

 java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(Calendar.getInstance().getTimeInMillis()) System.out.println(utilDate); System.out.println(sqlDate); 

produz a saída

 Thu Jun 02 13:17:35 CEST 2016 2016-06-02 

Portanto, tenha cuidado com datas sql e não as manipule como se elas apenas contivessem uma Data e nenhuma informação de hora. Por exemplo:

 java.sql.Date sqlDate1 = new java.sql.Date(Calendar.getInstance().getTimeInMillis()); java.sql.Date sqlDate2 = new java.sql.Date(Calendar.getInstance().getTimeInMillis()); System.out.println(sqlDate1); System.out.println(sqlDate2); System.out.println(sqlDate1.equals(sqlDate2)); System.out.println(sqlDate1.toString().equals(sqlDate2.toString())); 

impressões:

 2016-06-02 2016-06-02 false true 

Java.util.Date é o object genérico genérico para todos os fins. Ele armazena uma data (como um longo) e permite exibi-lo.

java.sql.Date estende java.util.Date. A principal diferença a notar é que java.sql.Date não possui um componente de tempo.

java.sql.Date aceita um inteiro longo que representa a quantidade de milissegundos desde 1º de janeiro de 1970. Se o número fornecido for negativo, ele referirá o tempo anterior a 1º de janeiro de 1970. Lembre-se, o valor encapsulado dentro do object representa apenas a data como 1 de janeiro de , 1970 e nenhuma informação de tempo é armazenada.

java.util.Date armazena informações de data e hora. É mais comumente usado que java.sql.Date.

O velho

java.util.Date

A class java.util.Date faz parte das antigas classs de data e hora que provaram ser mal projetadas, confusas e problemáticas. A intenção é representar um momento ( uma data e uma hora do dia ) na linha do tempo.

A class parece representar um momento no UTC, exceto que seu método toString aplica silenciosamente o fuso horário padrão atual da JVM enquanto gera a String, o que cria a ilusão de que um java.util.Date possui um fuso horário, mas na verdade não. Bem, na verdade, ele tem um fuso horário atribuído em seu código-fonte usado para algumas coisas internamente, mas não óbvio e não configurável nem disponível. Uma bagunça confusa.

java.sql.Date

O java.sql.Date piora a situação, representando um valor somente de data (como significa “DATE” no mundo do database SQL ), mas o fez como um hack, estendendo o java.util.Date . Mas você deve fingir que não é uma subclass, conforme indicado no documento de class. Além disso, tem hora do dia, mas finge não se ajustar ao primeiro momento do dia na UTC . Uma bagunça confusa.

E mais uma coisa … a class java.sql.Date adicionada em um segundo fracionário com uma resolução de nanossegundos . Isso vai além da resolução de milissegundos usada pelo java.util.Date. Muitos bancos de dados oferecem suporte a resoluções mais refinadas, como microssegundo ou nanossegundo.

Portanto, nessas classs antigas de data e hora, não há como representar verdadeiramente um valor somente de datas sem hora do dia nem fuso horário.

O novo

O framework java.time vem para o resgate. Inspirado pelo projeto altamente bem sucedido Joda-Time . Construído no Java 8 e posterior. Voltado para o Java 6 e 7 , e adaptado para o Android . Veja o Oracle Tutorial .

Instant

A class Instant representa um momento na linha do tempo no UTC com uma resolução de nanossegundos. Claro e simples.

 Instant instant = Instant.now(); 

instant.toString () → 2016-06-19T02: 34: 55.564Z

Se um java.util.Date for necessário para uso com código antigo, você poderá converter. Veja novos methods adicionados à class antiga: java.util.Date::toInstant () e java.util.Date.from (Instant) .

Zoneado

Para ajustar a hora do relógio de parede de alguma localidade, aplique um deslocamento de UTC ( ZoneOffset ) para obter um object OffsetDateTime . Melhor ainda, se você souber o nome correto do fuso horário, aplique um ZoneId para obter um ZonedDateTime .

Por exemplo, America/Montreal está quatro horas atrasada no horário de verão ( UTC) no horário de verão (DST) , portanto, vemos as dez horas (22:00) da data anterior no código abaixo, em vez de duas horas no exemplo acima. Voltando quatro horas cruzou mais de meia-noite para a data anterior. Mas tanto o object instant visto acima quanto o object zdt visto em seguida representam o mesmo momento simultâneo na linha do tempo. Mesmo momento na história, mas é “amanhã” em Paris, Calcutá e Auckland, enquanto “ontem” em Montreal, Cidade do México e Honolulu.

 ZoneId zoneId = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId ); 

zdt.toString () → 2016-06-18T22: 34: 55.564-04: 00 [América / Montreal]

LocalDate

Para um valor somente de data, use a class LocalDate . Nenhuma hora do dia nem fuso horário é retido.

 LocalDate localDate = zdt.toLocalDate(); 

Mas observe que um fuso horário é crucial na determinação de uma data , pois qualquer dado momento a data pode variar em todo o mundo por fuso horário. Assim, a discussão acima sobre a especificação de um fuso horário. Por exemplo, veja a seguir como chegamos no dia 18 de junho em vez do dia 19 .

localDate.toString () → 2016-06-18

Se essa distinção entre datas por fuso horário for significativa para sua empresa, você deverá usar um valor de data e hora armazenado em um tipo de coluna de database TIMESTAMP WITH TIME ZONE vez de DATE .

Pesquise o Stack Overflow para muito mais informações e muitos exemplos de java.time (tag: java-time ).

Base de dados

Portanto, salve em um database, use um driver JDBC compatível com a especificação JDBC 4.2 (consulte o Guia ). Chame setObject e getObject em PreparedStatement para usar diretamente os objects java.time.

Se o seu driver JDBC ainda não suportar esse uso direto dos tipos java.time, use os novos methods adicionados às classs antigas para facilitar a conversão. Mas minimize seu uso das classs antigas; Converta em java.time imediatamente e use apenas objects java.time em sua lógica de negócios.

 java.sql.Date mySqlDate = java.sql.Date.valueOf( localDate ); 

E a outra direção.

 LocalDate localDate = mySqlDate.toLocalDate();