PDA

View Full Version : MySQL - Data sul DB diminuita di un giorno


Andreawave
07-03-2019, 00:13
Ciao a tutti.
Ho il seguente problema:
Sto facendo una java web application molto semplice in cui memorizzo nel database i dati relativi a una persona: nome, cognome e data di nascita.
L'applicazione sembra funzionare tranne per il fatto che, inserendo una data (ad esempio 07/03/2019) mi ritrovo sul db tale data diminuita di un giorno, ovvero 2019-03-06. Com'è possibile?
Potreste dirmi come fixare tale problema?
Di seguito il codice:

Il bean
package bean;

import java.io.Serializable;
import java.sql.Date;

public class Persona implements Serializable {

private int idPersona;
private String nome;
private String cognome;
private Date dataNascita;

public Persona() {
super();

}

public Persona(String nome, String cognome, Date dataNascita) {
super();
this.nome = nome;
this.cognome = cognome;
this.dataNascita = dataNascita;
}

public Persona(int idPersona, String nome, String cognome, Date dataNascita) {
super();
this.idPersona = idPersona;
this.nome = nome;
this.cognome = cognome;
this.dataNascita = dataNascita;
}

public int getIdPersona() {
return idPersona;
}

public void setIdPersona(int idPersona) {
this.idPersona = idPersona;
}

public String getNome() {
return nome;
}

public void setNome(String nome) {
this.nome = nome;
}

public String getCognome() {
return cognome;
}

public void setCognome(String cognome) {
this.cognome = cognome;
}

public Date getDataNascita() {
return dataNascita;
}

public void setDataNascita(Date dataNascita) {
this.dataNascita = dataNascita;
}







}


La servlet
package servlet;

import java.io.IOException;
import java.sql.Date;
import java.sql.SQLException;
import java.text.ParseException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import bean.Persona;
import dao.ProvaDao;
import utility.ManipolazioneDate;

/**
* Servlet implementation class Inserimento
*/
@WebServlet("/Inserimento")
public class Inserimento extends HttpServlet {
private static final long serialVersionUID = 1L;

/**
* Default constructor.
*/
public Inserimento() {


}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String nome = request.getParameter("nome");
String cognome = request.getParameter("cognome");
String dataNascita = request.getParameter("dataNascita");
Date dataN = null;
try {
dataN = (Date) ManipolazioneDate.convertiData(dataNascita);
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}

Persona p = new Persona(nome, cognome, dataN);
System.out.println(p.getNome());
System.out.println(p.getCognome());
System.out.println(p.getDataNascita());

try{
ProvaDao.registraPersona(p);
}catch(SQLException e){
e.printStackTrace();
}
}

}


La classe che mi permette di convertire la data dal formato stringa al formato java.sql.Date

package utility;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ManipolazioneDate {

public static Date convertiData(String data) throws ParseException{

SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");
Date parser = format.parse(data);
java.sql.Date dataSql = new java.sql.Date(parser.getTime());

return dataSql;

}

}


Jsp con il form per l'inserimento dei dati


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<div align="center">
<form action="/Prova/Inserimento" method="get">
<p>Nome</p>
<input type="text" value="" name="nome">
<br>
<p>Cognome</p>
<input type="text" value"" name="cognome">
<br>
<p>Data di nascita</p>
<input type="text" value="" name="dataNascita">
<br>
<input type="submit" value="Invia">

</form>
</div>
</body>
</html>


Il Dao
[HTML]
package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import bean.Persona;
import utility.Connessione;

public class ProvaDao {

public static void registraPersona(Persona persona) throws SQLException{

Connection conn = Connessione.getConnection();
PreparedStatement ps = null;


String ins = "insert into prova2.persona(nome, cognome, dataNascita) values(?,?,?)";

try{

ps = conn.prepareStatement(ins);

ps.setString(1, persona.getNome());
ps.setString(2, persona.getCognome());
ps.setDate(3, persona.getDataNascita());

ps.executeUpdate();
System.out.println("Persona inserita");

}catch(SQLException e){

System.out.println(e.getMessage());
System.out.println("Errore nell'inserimento");

}finally{

if(ps != null){
ps.close();
}

if(conn != null){
conn.close();
}
}
}

}

[HTML]

Kaya
07-03-2019, 08:42
La butto li ma non sono sicuro.
Non è che hai definito la colonna datanascita come datetime e timestamp?
In quel caso mi verrebbe da pensare che ci sia un problema derivato dalla timezone (ad esempio se fosse un datetime e metti il 6 marzo 2019, mysql lo rappresenta in 2019-03-06 00:00:00 UTC+1 e quando vai a convertirlo risulta 2019-03-05 23:00:00 ).
E' un ipotesi, dovresti debuggare a livello di inserimento in mysql

Andreawave
07-03-2019, 11:36
La butto li ma non sono sicuro.
Non è che hai definito la colonna datanascita come datetime e timestamp?
In quel caso mi verrebbe da pensare che ci sia un problema derivato dalla timezone (ad esempio se fosse un datetime e metti il 6 marzo 2019, mysql lo rappresenta in 2019-03-06 00:00:00 UTC+1 e quando vai a convertirlo risulta 2019-03-05 23:00:00 ).
E' un ipotesi, dovresti debuggare a livello di inserimento in mysql

No, veramente la colonna datanascita sul db l'ho definita come date semplice e non come datetime

Kaya
07-03-2019, 11:52
No, veramente la colonna datanascita sul db l'ho definita come date semplice e non come datetime
Dai comunque un occhio ai timezone.
Inoltre vai di debug e vedi i vari valori se variano da qualche parte.

Andreawave
07-03-2019, 15:37
Dai comunque un occhio ai timezone.
Inoltre vai di debug e vedi i vari valori se variano da qualche parte.

Ok, ho fatto un debug sia utilizzando la modalità di debug di eclipse che mettendo dei system.out per verificare la data in ingresso e in uscita dal metodo di conversione delle date.
In pratica la data che ho inserito rimane invariata. Cambia(diminuisce) solo verificando nel db.
Tu pensi quindi di utilizzare datetime e non date sul db?

Kaya
07-03-2019, 16:51
Ok, ho fatto un debug sia utilizzando la modalità di debug di eclipse che mettendo dei system.out per verificare la data in ingresso e in uscita dal metodo di conversione delle date.
In pratica la data che ho inserito rimane invariata. Cambia(diminuisce) solo verificando nel db.
Tu pensi quindi di utilizzare datetime e non date sul db?

Visto che se in ballo farei un test..
Ma hai verificato la configurazione cosa dice sul timezone?

Andreawave
07-03-2019, 17:55
Visto che se in ballo farei un test..
Ma hai verificato la configurazione cosa dice sul timezone?
Ok ora provo..

Andreawave
07-03-2019, 18:22
Ok, ho provato ma ottengo lo stesso identico risultato, con la differenza che, usando datetime ottengo pure l'orario in formato HH:MM:SS

Kaya
08-03-2019, 08:19
Ok, ho provato ma ottengo lo stesso identico risultato, con la differenza che, usando datetime ottengo pure l'orario in formato HH:MM:SS

Accedi al database mysql e fai:
select now();
e verifica se data e ora coincidono con la data e l'ora corrente.

Andreawave
08-03-2019, 11:46
Accedi al database mysql e fai:
select now();
e verifica se data e ora coincidono con la data e l'ora corrente.
Fatto. La data coincide(2019-03-08) ma l'ora non coincide proprio. Risultano essere le 04:44:48

Kaya
08-03-2019, 11:59
Fatto. La data coincide(2019-03-08) ma l'ora non coincide proprio. Risultano essere le 04:44:48

E' da ieri che ti dico di impostare la timezone corretta sul mysql. :)

Andreawave
08-03-2019, 12:04
E' da ieri che ti dico di impostare la timezone corretta sul mysql. :)
Come si fa per settarla?:help:

Kaya
08-03-2019, 12:30
Come si fa per settarla?:help:

nel my.cnf di mysql

Andreawave
08-03-2019, 12:54
nel my.cnf di mysql
Ok, però io il problema lo ho principalmente se inserisco date diverse dalla data corrente. Nello specifico inserisco date di nascita es 14/02/1988 su db la data viene visualizzata come 1988-02-13. Pensi che anche in questo caso il problema sia dovuto al timezone?

Ibanez89
10-03-2019, 12:28
E' un problema del timezione. La data del tuo sistema è quella italiana "UTC+1", mentre di default quella di mysql è UTC. Dovresti lavorare sulla conversione delle date nel timezione corretto.

Il problema è che hai è il seguente, da input tu leggi una data senza timezione e a mezzanotte, ad esempio 10/03/2019. Questa ti viene convertita in java.util.date oppure java.sql.date "hanno la stessa interfaccia, quindi sono equiparabili. Tecnicamente dovresti usare la più moderna java.time" nel seguente modo->

data input: 10/03/2019 00:00

dopo di che tu la passi al jdbc che la trasforma nel timezione di mysql in:

offsetcorrected data by jdbc: 09/03/2019 23:00

Quest'ultima viene salvata nel tuo campo data troncando le ore, e quindi in:

DATE di mysql: 09/03/2019

Dopo di che quando l'andrai a reperire non avendo alcuna info sull'ora verrà trasformata in:

offsetcorrected data by jdbc: 09/03/2019 01:00

E incapsulata nel tuo oggetto e montrata a video con l'ennesimo troncamento delle ore in:

output data: 09/03/2019

Forse la soluzione più barbara è cambiare l'offset del db, oppure un'altra roba non ideale può essere la seguente:

Imposta il data formatter del parser in questo modo:
static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd", Locale.getDefault())

Crea un oggetto data per il tuo model in questo modo:

java.util.Date.from(
LocalDate.parse(request.getParameter("data"), DispatcherServlet.formatter)
.atStartOfDay()
.atZone(ZoneId.of("UTC"))
.toInstant()
)

Così fatto dovresti aver parsato la data in un oggetto "Zonizzato", gli normalizzi l'orario e lo converti in UTC, dopo di che lo trasformi in tipo java.util.date "che come già accennato, per il Principio di sostituzione di Liskov è intercambiabile con java.sql.date, il quale però per ovvie ragioni di information hiding e limitazioni di dipendente infra-tier dovrebbe però essere relegato solo nel data access layer" e lo salvi nel tuo model.

Occhio però, come già accennato è una soluzione di ripiego e non garantisce una corretta consistenza dei dati se l'applicativo viene spostato in un'altra timezone. :)

Andreawave
10-03-2019, 15:03
Infatti per l'applicativo verrà sicuramente utilizzato un altro db(mariadb credo) e quindi la soluzione di ripiego potrebbe non funzionare. Ad ogni modo grazie mille! Gentilissimo!

Ibanez89
10-03-2019, 17:02
Infatti per l'applicativo verrà sicuramente utilizzato un altro db(mariadb credo) e quindi la soluzione di ripiego potrebbe non funzionare. Ad ogni modo grazie mille! Gentilissimo!

Quella che ho proposto io è testata con mariadb, le API sono identiche a mysql

Kaya
12-03-2019, 08:45
Ma scusa. è una settimana che ti martello con "è il timezone", davvero costa così fatica modificare una riga del my.cnf ?
Ibanez ha fatto tutta la spiegazione corretta, ma sinceramente non capisco per quale motivo qualcuno posta una domanda, gli si dice dove verificare e risolvere, e no che ostinato come un mulo continua.
Hai sistemato questo benedetto timezone nel file di configurazione?

Kaya
12-03-2019, 08:46
Quella che ho proposto io è testata con mariadb, le API sono identiche a mysql

Beh fondamentalmente MariaDB è il fork di MySql...

Ibanez89
13-03-2019, 20:39
Ma scusa. è una settimana che ti martello con "è il timezone", davvero costa così fatica modificare una riga del my.cnf ?
Ibanez ha fatto tutta la spiegazione corretta, ma sinceramente non capisco per quale motivo qualcuno posta una domanda, gli si dice dove verificare e risolvere, e no che ostinato come un mulo continua.
Hai sistemato questo benedetto timezone nel file di configurazione?

Magari lavora su un db remoto e/o non può farlo per problemi di autorizzazioni

Beh fondamentalmente MariaDB è il fork di MySql...

Sono pressappoco identici https://mariadb.com/kb/en/library/mariadb-vs-mysql-compatibility/

Andreawave
19-03-2019, 00:17
Ma scusa. è una settimana che ti martello con "è il timezone", davvero costa così fatica modificare una riga del my.cnf ?
Ibanez ha fatto tutta la spiegazione corretta, ma sinceramente non capisco per quale motivo qualcuno posta una domanda, gli si dice dove verificare e risolvere, e no che ostinato come un mulo continua.
Hai sistemato questo benedetto timezone nel file di configurazione?

Ho risolto.
Senza che ti agiti tanto, però! Si vede che non riuscivo ad accedere al my.cnf e non perché sono cocciuto, ok??

Kaya
19-03-2019, 09:01
Ho risolto.
Senza che ti agiti tanto, però! Si vede che non riuscivo ad accedere al my.cnf e non perché sono cocciuto, ok??

Non è che mi agito, ma se uno ti da un suggerimento - da te richiesto - è anche buona educazione dire "guarda non posso farlo perchè non ho accesso al file di configurazione".
Alchè quella persona ti avrebbe risposto
"visto che non puoi farlo da configurazione, assicurati sia impostata a livello di sessione, che puoi farlo con un comando sql (ref https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html )" e tutto si risolve in modo più rapido.
O sbaglio?
Tutto questo con la massima pace dei sensi