ResultSet.getDate () возвращает неправильную дату

0

У меня возникла проблема с использованием метода 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", "2017-12-20"

Здесь данные, которые были возвращены (StackTrace):

Id: 1 Nome: Lucas CPF: 1111111111 RG: 12222222 Данные de Nascimento: 2017-12-21

Id: 2 Nome: Lucas CPF: 1111111111 RG: 12222222 Данные de Nascimento: 2017-12-21

Id: 3 Nome: Lucas CPF: 1111111111 RG: 12222222 Данные de Nascimento: 2017-12-21

Id: 4 Nome: Leandro CPF: 2321 RG: 21232 Данные de Nascimento: 2017-12-21

Как я уже сказал, у одной из строк есть дата два дня назад, но она также показывает сегодняшнюю дату, поэтому я думаю, что это не часовая ошибка.

PS: Имя переменных и методов на португальском языке, потому что приложение также находится на португальском языке.

Теги:
date
jodatime

2 ответа

2
Лучший ответ

Проблема здесь

LocalDate dt = new LocalDate();
dt.fromDateFields(rs.getDate("data_nasc"));

Первое утверждение создает новый набор LocalDate для сегодняшнего дня. Второй оператор - это вызов static метода fromDateFields, который должен быть помечен как предупреждение вашей IDE/компилятором. Этот метод возвращает новый объект LocalDate, который вы отбрасывали, и не LocalDate dt. Вышеизложенное должно быть:

LocalDate dt = LocalDate.fromDateFields(rs.getDate("data_nasc"));
2

Ответ Джима Гаррисона правильный. Более простой и интуитивно понятный код, описанный ниже, предотвратил бы эту конкретную ошибку.

Кроме того, вы:

  • Игнорирование ключевой проблемы часового пояса при определении даты.
  • Использование старой библиотеки из проекта, который рекомендует переходить на их современные классы замены.

ТЛ; др

Использование классов java.time, которые заменили Joda-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 теперь находится в режиме обслуживания. Его команда советует перейти на java.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 который является значением только для даты.

Но похоже, что вы сохранили момент, возможно, тип TIMESTAMP MySQL, который, как представляется, отслеживает стандартный SQL TIMESTAMP WITH TIME ZONE. Любая предоставленная информация о смещении или часовом поясе используется для настройки значения в формате UTC при отправке в базу данных в MySQL с разрешением в микросекундах.

Таким образом, эквивалентный тип в 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() ;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню