我在使用ResultSet.getDate()
方法时遇到问题。我在MySQL中有一个日期字段,当我尝试获取该值时,获得的日期是今天的日期而不是指定表中的日期。我不知道是什么导致了这个错误,我搜索了其他帖子,但getDate()
的其他错误不同,如解析或数据不匹配错误或其他类型的错误。由于时区可能是一个错误,因为日期的值是从昨天开始的,但是有一行的日期是两天前的,它也是今天的日期。
以下是代码:
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.joda.time.LocalDate;
import model.Paciente;
import teste.ConnectionFactory;
public class PacienteDao {
// a conexão com o banco de dados
private Connection connection;
public PacienteDao() {
this.connection = new ConnectionFactory().getConnection();
}
public void adiciona(Paciente paciente) {
String sql = "insert into paciente" +
" (nome_paciente,cpf_paciente,rg_paciente,data_nasc)" +
"values (?,?,?,?)";
try {
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, paciente.getNome_paciente());
stmt.setString(2, paciente.getCpf());
stmt.setString(3, paciente.getRg());
java.sql.Date data_nasc = new java.sql.Date(paciente.getData_nasc().toDate().getTime());
stmt.setDate(4, data_nasc);
stmt.execute();
stmt.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public List<Paciente> listaPacientes() {
List<Paciente> pacientes = new ArrayList<Paciente>();
try {
PreparedStatement stmt = this.connection.prepareStatement("select * from paciente");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
Paciente paciente = new Paciente();
paciente.setId_paciente(rs.getInt("id_paciente"));
paciente.setNome_paciente(rs.getString("nome_paciente"));
paciente.setCpf(rs.getString("cpf_paciente"));
paciente.setRg(rs.getString("rg_paciente"));
LocalDate dt = new LocalDate();
dt.fromDateFields(rs.getDate("data_nasc"));
paciente.setData_nasc(dt);
pacientes.add(paciente);
}
rs.close();
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
return pacientes;
}
以下是应返回的数据(CSV):
这是返回的数据(StackTrace):
Id:1 诺姆:卢卡斯 CPF:1111111111 RG:12222222 Data de Nascimento:2017-12-21
同上:2 诺姆:卢卡斯 CPF:1111111111 RG:12222222 Data de Nascimento:2017-12-21
Id:3 诺姆:卢卡斯 CPF:1111111111 RG:12222222 Data de Nascimento:2017-12-21
Id:4 诺姆:莱安德罗 CPF:2321 RG:21232 Data de Nascimento:2017-12-21
就像我说的其中一行有两天前的日期,但它也显示今天的日期,所以我认为不是时区错误。
PS:变量和方法的名称是葡萄牙语,因为应用程序也是葡萄牙语。
答案 0 :(得分:2)
问题出在这里
LocalDate dt = new LocalDate();
dt.fromDateFields(rs.getDate("data_nasc"));
第一个语句创建了一个新的LocalDate
设置为今天。第二个语句是对static
方法fromDateFields
的调用,它应该被IDE和/或编译器标记为警告。此方法返回您放弃的 新 LocalDate
对象,并且不会修改dt
。以上应该是:
LocalDate dt = LocalDate.fromDateFields(rs.getDate("data_nasc"));
答案 1 :(得分:2)
Answer by Jim Garrison是正确的。下面看到的更简单,更直观的代码可以避免这种特殊的错误。
此外,你是:
使用替换Joda-Time的java.time类。
myResultSet().getObject( … , Instant.class ) // Extract a moment on the timeline in UTC, an `Instant` object.
.atZone( ZoneId.of( "Asia/Kolkata" ) ) // Adjust into a time zone, to determine a date, rendering a `ZonedDateTime` object.
.toLocalDate() // Extract a date-only object, a `LocalDate` without time-of-day and without a time zone.
您不应该使用PreparedStatement::getDate()
。避免使用与最早版本的Java捆绑在一起的所有麻烦的旧日期时间类,例如Date,Calendar和相关的java.sql类型。这些完全取代了java.time类和JDBC 4.2驱动程序。
同样,Joda-Time项目现在处于维护模式。它的团队建议迁移到他们在JSR 310中启发,定义和实现的java.time。
使用getObject
和setObject
方法。
LocalDate ld = myResultSet().getObject( … , LocalDate.class ) ; // For retrieving a standard SQL `DATE` column.
和...
myPrepatedStatement.setObject( … , ld ) ;
上面的代码是针对标准SQL DATE
列的,这是一个仅限日期的值。
但听起来你有一个时刻存储,也许MySQL类型TIMESTAMP
似乎跟踪标准的SQL TIMESTAMP WITH TIME ZONE
类型。任何提供的偏移或时区信息用于在MySQL中提交到数据库时将值调整为UTC,分辨率为微秒。
因此,Java中的等效类型是Instant
,用于UTC中时间轴中的一个点,但具有更精细的纳秒级分辨率。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
和...
myPreparedStatement.setObject( … , instant ) ;
请记住,Instant
始终为UTC。但确定日期需要一个时区。对于任何给定时刻,日期因区域而异。
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
从那里提取似乎是你的目标的仅限日期的对象。
LocalDate ld = zdt.toLocalDate() ;