ResultSet.getDate()返回错误的日期

时间:2017-12-21 22:09:12

标签: java mysql date jodatime

我在使用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):

  • “1”, “卢卡斯”, “1111111111”, “12222222”, “2017年12月19日”
  • “2”, “卢卡斯”, “1111111111”, “12222222”, “2017年12月20日”
  • “3”, “卢卡斯”, “1111111111”, “12222222”, “2017年12月20日”
  • “4”, “Leandro的”, “2321”, “21232”, “二〇一七年十二月二十〇日”

这是返回的数据(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:变量和方法的名称是葡萄牙语,因为应用程序也是葡萄牙语。

2 个答案:

答案 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是正确的。下面看到的更简单,更直观的代码可以避免这种特殊的错误。

此外,你是:

  • 在确定日期时忽略时区的关键问题。
  • 使用项目中较旧的库,建议您转移到现代替换类。

TL;博士

使用替换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。

java.time

使用getObjectsetObject方法。

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() ;
相关问题