java.util.Date
vs java.sql.Date
: quando usar qual e por quê?
Parabéns, você acertou minha irritação favorita com JDBC: Data class handling.
Basicamente, os bancos de dados geralmente suportam pelo menos três formas de campos de data e hora que são data, hora e carimbo de data e hora. Cada um deles tem uma classe correspondente no JDBC e cada um deles se estendejava.util.Date
. A semântica rápida de cada um desses três é a seguinte:
java.sql.Date
corresponde ao SQL DATE, o que significa que armazena anos, meses e dias, enquanto hora, minuto, segundo e milissegundo são ignorados. Além disso, sql.Date
não está vinculado a fusos horários.java.sql.Time
corresponde ao SQL TIME e, como deve ser óbvio, contém apenas informações sobre hora, minutos, segundos e milissegundos .java.sql.Timestamp
corresponde ao SQL TIMESTAMP, que é a data exata do nanossegundo ( observe que util.Date
apenas suporta milissegundos! ) com precisão personalizável.Um dos erros mais comuns ao usar drivers JDBC em relação a esses três tipos é que os tipos são manipulados incorretamente. Isso significa que sql.Date
é específico do fuso horário, sql.Time
contém o ano, o mês e o dia atuais etc.
Depende do tipo SQL do campo, realmente. PreparedStatement
possui setters para todos os três valores, #setDate()
sendo esse para sql.Date
, #setTime()
para sql.Time
e #setTimestamp()
para sql.Timestamp
.
Observe que, se você usar, ps.setObject(fieldIndex, utilDateObject);
poderá realmente fornecer um normal util.Date
à maioria dos drivers JDBC, que o devorarão como se fossem do tipo correto, mas, quando você solicitar os dados posteriormente, poderá perceber que realmente está faltando alguma coisa.
O que estou dizendo é que salva os milissegundos / nanossegundos em longos simples e os converte em qualquer objeto que você estiver usando ( plug obrigatório de tempo de joda ). Uma maneira hacky que pode ser feita é armazenar o componente de data como um componente de tempo e tempo como outro, por exemplo, agora seria 20100221 e 154536123. Esses números mágicos podem ser usados em consultas SQL e serão portáteis do banco de dados para outro e permitirá que você evite completamente essa parte da API JDBC / Java Date API: s.
EDIT LATE: Começando com Java 8 você deve usar nem
java.util.Date
nemjava.sql.Date
se você puder evitar isso, e em vez disso preferem usar ojava.time
pacote (com base em Joda) em vez de qualquer outra coisa. Se você não está no Java 8, aqui está a resposta original:java.sql.Date
- quando você chama métodos / construtores de bibliotecas que o utilizam (como JDBC). Não de outra forma. Você não deseja introduzir dependências nas bibliotecas de banco de dados para aplicativos / módulos que não lidam explicitamente com o JDBC.java.util.Date
- ao usar bibliotecas que o utilizam. Caso contrário, o mínimo possível, por vários motivos:É mutável, o que significa que você precisa fazer uma cópia defensiva toda vez que passa ou devolve um método.
Ele não lida com datas muito bem, o que, de trás para frente, pessoas como a sua, acham que as aulas de manipulação de datas deveriam.
Agora, como o juD não faz seu trabalho muito bem, as horríveis
Calendar
classes foram introduzidas. Eles também são mutáveis e difíceis de trabalhar, e devem ser evitados se você não tiver escolha.Existem alternativas melhores, como a API Joda Time (
que pode até entrar no Java 7 e se tornar a nova API oficial de manipulação de datas- uma pesquisa rápida diz que não).Se você acha que é exagero introduzir uma nova dependência como Joda,
long
não é tão ruim usar os campos de registro de data e hora nos objetos, embora eu mesmo os envolva em juD quando os repassamos, para segurança de tipo e como documentação.fonte
java.sql.Date
comPreparedStatement
etc! Mas quando você está distribuindo, use umLocalDate
que você converta usandojava.sql.Date.valueOf
ejava.sql.Date.valueOf
ao configurá-lo, e converta-o o mais cedo possível usandojava.sql.Date.toLocalDate
- novamente, porque você deseja envolver o java.sql o mínimo possível e porque é mutável.O único momento para usar
java.sql.Date
é emPreparedStatement.setDate
. Caso contrário, usejava.util.Date
. Está dizendo queResultSet.getDate
retorna a,java.sql.Date
mas pode ser atribuído diretamente ajava.util.Date
.fonte
java.sql.Date
pode ser atribuído a ajava.util.Date
quando o primeiro estende o último? Qual é o ponto que você está tentando enfatizar?Eu tive o mesmo problema, a maneira mais fácil de inserir a data atual em uma declaração preparada é esta:
fonte
tl; dr
Não use nenhum.
java.time.Instant
substituijava.util.Date
java.time.LocalDate
substituijava.sql.Date
Nem
Ambas as classes são terríveis, com falhas no design e na implementação. Evite como o coronavírus da
peste.Em vez disso, use as classes java.time , definidas no JSR 310. Essas classes são uma estrutura líder do setor para trabalhar com manipulação de data e hora. Estes suplantar inteiramente os sangrentos aulas terrível legado, como
Date
,Calendar
,SimpleDateFormat
, e tal.java.util.Date
O primeiro,
java.util.Date
pretende representar um momento no UTC, significando um deslocamento do UTC de zero horas-minutos-segundos.java.time.Instant
Agora substituído por
java.time.Instant
.java.time.OffsetDateTime
Instant
é a classe básica de blocos de construção do java.time . Para obter mais flexibilidade, useOffsetDateTime
setZoneOffset.UTC
para o mesmo objetivo: representar um momento no UTC.Você pode enviar esse objeto para um banco de dados usando
PreparedStatement::setObject
com JDBC 4.2 ou posterior.Recuperar.
java.sql.Date
A
java.sql.Date
turma também é terrível e obsoleta.Esta classe deve representar apenas uma data, sem uma hora do dia e sem um fuso horário. Infelizmente, em um terrível hack de um design, essa classe é herdada da
java.util.Date
qual representa um momento (uma data com a hora do dia no UTC). Portanto, essa classe está apenas fingindo ser apenas de data, enquanto na verdade carrega um deslocamento de hora do dia e implícito do UTC. Isso causa muita confusão. Nunca use esta classe.java.time.LocalDate
Em vez disso, use
java.time.LocalDate
para rastrear apenas uma data (ano, mês, dia do mês) sem nenhuma hora do dia nem fuso horário ou deslocamento.Enviar para o banco de dados.
Recuperar.
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
, eSimpleDateFormat
.Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .
O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .
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?
fonte
A classe java.util.Date em Java representa um momento específico (por exemplo, 25 de novembro de 2013 às 16:30:45 até milissegundos), mas o tipo de dados DATE no banco de dados representa apenas uma data (por exemplo, 2013 25 de novembro). Para impedir que você forneça um objeto java.util.Date ao banco de dados por engano, Java não permite que você defina um parâmetro SQL como java.util.Date diretamente:
Mas ainda permite que você faça isso por força / intenção (horas e minutos serão ignorados pelo driver do DB). Isso é feito com a classe java.sql.Date:
Um objeto java.sql.Date pode armazenar um momento no tempo (para que seja fácil construir a partir de um java.util.Date), mas lançará uma exceção se você tentar perguntar por horas (para reforçar seu conceito de ser um somente data). O driver DB deve reconhecer essa classe e usar apenas 0 para as horas. Tente o seguinte:
fonte
java.util.Date
representa um instante específico no tempo com precisão de milissegundos. Representa informações de data e hora sem fuso horário. A classe java.util.Date implementa a interface Serializable, Cloneable e Comparable. É herdado porjava.sql.Date
,java.sql.Time
ejava.sql.Timestamp
interfaces.java.sql.Date
estende a classe java.util.Date, que representa informações de data sem hora, e deve ser usada apenas ao lidar com bancos de dados. Para estar em conformidade com a definição de SQL DATE, os valores de milissegundos agrupados por umajava.sql.Date
instância 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.Ele herda todos os métodos públicos de
java.util.Date
tais comogetHours()
,getMinutes()
,getSeconds()
,setHours()
,setMinutes()
,setSeconds()
. Comojava.sql.Date
não armazena as informações de horário, elas substituem todas as operações de horáriojava.util.Date
e todos esses métodos são lançadosjava.lang.IllegalArgumentException
se invocados como evidentes nos detalhes de implementação.fonte