(RESOLVIDO) Data salva no banco corretamente, mas na listagem vem com um dia a menos

Pessoal, bom dia, estou com um pequeno problema.

Tenho um programa que salva um cadastro na base, Nome, CPF e DataNascimento.
Ao Salvar, os registros vão corretos.
Confiro na base e está correto (ex: Rebeca, 12345678900 19/12/1989)

Mas, ao fazer a listagem dos dados (buscando na base)
Os registros possuem um dia a menos na dataNascimento.
(Rebeca 12345678900 18/12/1989)

O que pode ser?

Eu utilizo

private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");



public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Locale.setDefault(new Locale("pt", "BR"));
					MainFrame frame = new MainFrame();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}


--------------


public String[][] listagem() throws NegocioException {
		int numCols = 6;
		String[][] listaRetorno = null;
		try {
			PessoaDAO pessoaDAO = new PessoaDAO();
			List<PessoaDTO> lista = pessoaDAO.listarTodos();
			listaRetorno = new String[lista.size()][numCols];

			for (int i = 0; i < lista.size(); i++) {
				PessoaDTO pessoa = lista.get(i);
				listaRetorno[i][0] = pessoa.getIdPessoa().toString();
				listaRetorno[i][1] = pessoa.getNome();
				listaRetorno[i][2] = pessoa.getCpf().toString();
				listaRetorno[i][3] = pessoa.getEndereco();
				listaRetorno[i][4] = pessoa.getSexo() == 'M' ? "Masculino" : "Feminino";
				listaRetorno[i][5] = dateFormat.format(pessoa.getDtNasc());
			}

		} catch (Exception exception) {
			throw new NegocioException(exception.getMessage());
		}
		return listaRetorno;
	}
1 curtida

Coloque o código que adiciona o registro na lista

public class PessoaBO {

	private DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");

	public void cadastrar(PessoaDTO pessoaDTO) throws NegocioException {

		try {
			PessoaDAO pessoaDAO = new PessoaDAO();
			pessoaDAO.inserir(pessoaDTO);

		} catch (Exception exception) {
			throw new NegocioException(exception.getMessage());
		}

	}
JButton btnCadastrar = new JButton("Cadastrar");
		btnCadastrar.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				try {
					PessoaDTO pessoaDTO = new PessoaDTO();
					PessoaBO pessoaBO = new PessoaBO();

					String nome = txtNome.getText();
					String cpf = txtCpf.getText();
					String endereco = txtEndereco.getText();
					String nasc = txtDtNasc.getText();

					pessoaBO.validaNome(nome);
					pessoaBO.validaCpf(cpf);
					pessoaBO.validaEndereco(endereco);
					pessoaBO.validaDtNasc(nasc);

					pessoaDTO.setNome(nome);
					pessoaDTO.setCpf(Long.parseLong(cpf));
					pessoaDTO.setEndereco(endereco);

					try {
						pessoaDTO.setDtNasc(dateFormat.parse(nasc));
					} catch (ParseException e1) {
						e1.printStackTrace();
					}

					char sexo = rdbtnMasculino.isSelected() ? 'M' : 'F';
					pessoaDTO.setSexo(sexo);
					pessoaBO.cadastrar(pessoaDTO);

					MensagensUtil.addMsg(MainFrame.this, "Cadastro Efetuado com sucesso");
					MainFrame.this.dispose();
					main(null);

E o método inserir da classe PessoaDAO?

@Override
	public void inserir(PessoaDTO pessoaDTO) throws PersistenciaException {

		try {
			Connection connection = ConexaoUtil.getInstance().getConnection();
			String sql = "INSERT INTO TB_PESSOA(NOME, CPF, ENDERECO, SEXO, DT_NASC) " + "VALUES(?, ?, ?, ?, ?)";

			PreparedStatement statement = connection.prepareStatement(sql);
			statement.setString(1, pessoaDTO.getNome());
			statement.setLong(2, pessoaDTO.getCpf());
			statement.setString(3, pessoaDTO.getEndereco());
			statement.setObject(4, String.valueOf(pessoaDTO.getSexo()));
			statement.setDate(5, new java.sql.Date(pessoaDTO.getDtNasc().getTime()));

			statement.execute();
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new PersistenciaException(e.getMessage(), e);
		}
	}

Como você disse que os dados estao corretos no banco de dados, o problema nao deve ser no método de inserir.

Pode informar qual banco de dados está utilizando, o comando que utilizou para criar a tabela e postar o método listarTodos do seu DAO?

MySQL via Workbench

@Override
	public List<PessoaDTO> listarTodos() throws PersistenciaException {
		List<PessoaDTO> listaPessoas = new ArrayList<PessoaDTO>();
		try {
			Connection connection = ConexaoUtil.getInstance().getConnection();
			String sql = "SELECT * FROM TB_PESSOA";

			PreparedStatement statement = connection.prepareStatement(sql);
			ResultSet resultSet = statement.executeQuery();

			while (resultSet.next()) {
				PessoaDTO pessoaDTO = new PessoaDTO();
				pessoaDTO.setIdPessoa(resultSet.getInt("id_Pessoa"));
				pessoaDTO.setNome(resultSet.getString("Nome"));
				pessoaDTO.setCpf(resultSet.getLong("CPF"));
				pessoaDTO.setEndereco(resultSet.getString("Endereco"));
				pessoaDTO.setSexo(resultSet.getString("Sexo").charAt(0));
				pessoaDTO.setDtNasc(resultSet.getDate("DT_Nasc"));
				listaPessoas.add(pessoaDTO);
			}
			connection.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new PersistenciaException(e.getMessage(), e);
		}
		return listaPessoas;
	}

No banco de dados o tipo data de nascimento é varchar ? date? ou timestamp?

Você pode manipular data como String (no banco como varchar), fiz isso e nunca mais tiver dor de cabeça. Simplesmente quando fazer a busca no banco de dados, faça a validação com SimpleDateFormat

  1. Trabalhar com data no Java 8 link

  2. Problema semelhante link

  3. Opinião sobre trabalhar com tipos numéricos (valido também para datas) link

Oi @Rebeca_Nonato, faltou você postar o comando usar para criar a tabela (algo com “CREATE TABLE…”).

Aquele comando:

Locale.setDefault(new Locale("pt", "BR"));

Me faz suspeitar que possa ser problema de fuso horário entre aplicaçao e o servidor de banco de dados. A mesma coisa que aconteceu aqui:

@Eduardo_Maranata10,

Eu entendo que usar strings ao invés de dates possa parecer uma soluçao mais simples, mas acredito que a longo prazo isso traga mais dor de cabeça do que benefícios. Claro que no seu caso está funcionando, mas como conselho geral pode nao se adaptar em todos os casos.

Muitas pessoas confundem o que é um valor de um tipo de dados e o que é o formato aplicado aquele valor, quando se usa strings. Mantendo o tipo de dados correto, você só se preocupa com o valor. Mantendo como string, a pessoa tem que se preocupar com o valor e o formato sempre.

Esse artigo sobre tipos numéricos que mandou é justamente sobre nao usar o tipo incorreto para o problema. Sao dados que apesar de conterem números, nao sao dados numéricos (0 a esquerda é significante em CPF, formato é significante em telefone, etc).

Datas sao valores mais complexos e até por isso possuem um tipo específico para lidar com elas. Mantendo como tipo Date você tem uma garantia extra que as operaçoes efetuadas (comparar datas, números de dias entre duas datas, obter dia da semana, etc) podem ser efetuadas com sucesso sem precisar ficar dando parse a cada momento.

Como esse problema agora ?

Se a logica da manipulação dos datas estiver no banco de dados, faz sentido você trabalha com esses tipos(Datetime, Timestamp). No mais não vejo como solução trabalha com classes que possui vários métodos deprecated (java.util.Date e java.sql.Date).

No próprio artigo do Alexandre (Caelum) ele fala bem sobre diferença

Manipular datas no Java sempre foi algo trabalhoso. No Java 1.0 havia apenas a classe Date, que era complicada de usar e não funcionava bem com internacionalização. Com o lançamento do Java 1.1, surgiu a classe abstrata Calendar, com muito mais recursos, porém com mutabilidade e decisões de design questionáveis.

no banco o campo é DATE

Vou tentar fazer isso,
O problema é que estou seguindo um curso.
Então, estava seguindo os passos dele.

1 curtida

Esse comando, foi o instrutor que falou para fazer,
mas não resolveu o problema…

CREATE TABLE
não tenho esse comando no código Java.
Criei a tabela na base, antes de começar a fazer o código Java.

@Rebeca_Nonato,

O que pode estar acontecendo é que você tem um servidor num fuso horário diferente da máquina que está rodando sua aplicaçao.
Se teu Mysql estiver rodando em UTC, por exemplo, e sua máquina no horário de brasília, as datas ficaram 3 horas antes no seu fuso horário e portanto um dia a menos (já que a data tem horário zero)

Para confirmar se isto está acontecendo contigo, rode a seguinte query diretamente no mysql workbench:

SELECT NOW();

O horário mostrado nao deve ser igual ao da máquina que seu programa está rodando.

Um jeito de corrigir isso é passar um Calendar quando estiver obtendo a data do banco de dados:

ResultSet resultSet = statement.executeQuery();
Calendar calendar = Calendar.getInstance();
while (resultSet.next()) {
    // ...
    pessoaDTO.setDtNasc(resultSet.getDate("DT_Nasc", calendar));
    // ...
}

Outra maneira que vi pessoas sugerindo é passar o timezone da máquina diretamente na connection string:

DriverManager.getConnection("jdbc:mysql://127.0.0.1/teste?user=user&password=password&serverTimezone=" + TimeZone.getDefault().getID());

Num teste rápido parece funcionar tanto para inserir quanto para ler, mas o nome do parâmetro me parece confuso.

1 curtida

É justo, mas geralmente esse tipo de problema é uma configuraçao que você tem uma vez e depois de resolvido, nao acontece mais.

Mas como varchar também tem um “preço” a pagar, pois você força todo mundo que for manipular essa coluna a estar ciente do formato que a data está gravada. Pode nao ser um problema em muitos casos, mas é um conhecimento a mais que as pessoas terao.
Pode acontecer algo como tentar inserir a data atual com a funçao now() mas o formato de data da sessao é diferente do padrao e gravar dados no formato errado. Coisas do gênero.

Mas isso é do lado do java, também nao defendo.
Mesmo antes do java 8, tinha a Joda time que ajudava muito a manter a sanidade.
O que eu nao recomendaria é que ao invés de usar java.util.Date a pessoa usasse String formatada para representar datas.

AEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE \o/

Funcionouuuuuuuuuuuuuuuuu

Obrigada… Nossa, Obrigada mesmo.

Acho que entendi.

Mas, olha só:

Fiz o

SELECT NOW();

E a data e hora retornaram corretamente ( a mesma que está no meu pc).

Fiz o Calendar e agora retornou exatamente na listagem, os valores de data que eu tinha inserido, e que estavam no banco de dados.

vi que para toda busca na base, terei que utilizar esse comando.

mas,…

minha conexão está assim:

DriverManager.getConnection("jdbc:mysql://localhost:3306/teste_programa?useSSL=false&useTimezone=true&serverTimezone=UTC)

alterei ela:

DriverManager.getConnection("jdbc:mysql://localhost:3306/teste_devmedia?useSSL=false&useTimezone=true&serverTimezone=" + TimeZone.getDefault().getID(),

Alterei então ela, para o que vc passou e também deu certo, mesmo sem o calendar.

Obrigadaaaaaaaa, novamente…

2 curtidas

Salvou meu dia.
Muitíssimo obrigado!