DateField e MySql

Buonasera,
sto proseguendo con lo studio di Cuba e la realizzazione di una piccola contabilità.
Ho notato una cosa che mi sembra quasi impossibile.

Ho un semplicissimo screen di edit di una entita dove c’e’ un campo data gestito dal controllo DateField, scrivo la data, ad esempio 21/10/2020 e premo salva. A video sembra tutto ok, ma se faccio refresh o riapro l’edit, la data e’ quella del giorno prima, cioe’ il 20/10/2020. Questa e’ una cosa che ho notato praticamente dal primo giorno, ma al momento non avevo dato peso alla cosa pensando di sbagliare qualcosa io.

Oggi pomeriggio, stavo creando un riepilogo dei movimenti di prima nota filtrati da data a data e mi venivano fuori numeri imprevisti. Alla fine ho capito che ero in presenza del problema della data del giorno prima che avevo notato in precedenza.

Il controllo rende la data giusta ho verificato.

Non capendoci piu’ niente, ho provato a loggare le query sul DB e ho notato che l’errore e’ proprio nella query, c’e’ la data del giorno prima.

Ho fatto ulteriori verifiche e ho notato che si verifica con MySql mentre con HSQLDB funziona, altri DB non ho potuto provarli.

La versione di mySql che sto utilizzando e’ la 5.7.31 in localhost sulla mia macchina con LinuxMint 19.3 64 bit.

Ho visto nel forum inglese che c’e’ un post su questo argomento, ma senza soluzione.

Qualcuno e’ in grado di darmi qualche indicazione per risolvere il problema?

Che motori di database usate?

Buona serata.

Marco

Ciao e bentornato sul forum :wink:

Potresti postare qualche dettaglio in più, tipo entità, DDL creata, e query che logghi?

Anche per questo riusciresti a condividere thread esatto a cui fai riferimento?

HSQL in locale, ma solo in primissime fasi, poi principalmente Postgres e SQL Server, MySQL mai usato in produzione con CUBA (ma lo uso per altre tecnologie, anche se MariaDB che preferisco su Linux).
Comunque mai capitato questo problema, se ovviamente i tipi di dati usati e le impostazioni di TZ ecc. sono tutte corrette (gestire in modo corretto data/ora per app internazionali non è banale, se non si decide di lavorare solo in ora locale o UTC).

Attendo info aggiuntive,
Paolo

Ciao Paolo,
il thread e’ questo: https://www.cuba-platform.com/discuss/t/date-stored-in-database-one-day-earlier/13120

Questa e’ l’entità di test:

package com.company.testdatafield.entity;

import com.haulmont.cuba.core.entity.StandardEntity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.time.LocalDate;

@Table(name = “TESTDATAFIELD_PROVA”)
@Entity(name = “testdatafield_Prova”)
public class Prova extends StandardEntity {
private static final long serialVersionUID = 715987456535412605L;

@Column(name = "DATA_PROVA")
private LocalDate data;

@Column(name = "COGNOME", length = 100)
private String cognome;

@Column(name = "NOME", length = 50)
private String nome;

public String getCognome() {
    return cognome;
}

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

public String getNome() {
    return nome;
}

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

public LocalDate getData() {
    return data;
}

public void setData(LocalDate data) {
    this.data = data;
}

}

Ho fatto un progettino ex novo due minuti fa con questa entità, gli ho fatto creare lo screen brose/edit a Cuba, l’ho provato per vedere se faceva il difetto prima di mandartelo. Confermo che lo fa su MySql, ma non HSQLDB. Le impostazioni del progetto sono quelle di default English/en

Dici che potrebbe essere un problema di impostazioni internazionali o di TimeZone? Con l’ERP in Vaadin siamo impazziti abbastanza con le impostazioni internazionali dovendo funzionare oltre che in Italia anche in alcuni paesi dell’Europa, Stati Uniti, Messico e Cina con i relativi fusi orari e impostazioni valute, numeri ecc…, ma alla fine ha funzionato piu’ o meno tutto :slight_smile:
In ogni caso al massimo avevamo avuto differenze di qualche ora sui LocalTime, un giorno intero preciso non mi era mai successo.

Domattina vedo di mandarti il log della query dell’INSERT e dell’UPDATE.

Grazie per ora

Marco

Rieccomi…

Dati inseriti nella form:

data_prova: 22/10/2020
cognome: Selmi
nome: Marco

TimeZone dell’utente admin impostazione di default quindi vuoto e senza check “Auto”. Le due ore di differenza dovrebbero essere fra UTC e Italia. Ho provato a fargli scrivere la TimeZone di default di Cuba e dice correttamente Europe/Rome.

Log del Cuba

2020-10-22 09:40:45.989 DEBUG [http-nio-8080-exec-3/app-core/admin] eclipselink.sql - <t 1806085313, conn 989673127> INSERT INTO TESTDATEFIELD_PROVA (ID, COGNOME, CREATE_TS, CREATED_BY, DATA_PROVA, DELETE_TS, DELETED_BY, NOME, UPDATE_TS, UPDATED_BY, VERSION) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
bind => [d76c12807bb72cfe9dc1e64ec1b5496c, Selmi, 2020-10-22 09:40:45.986, admin, 2020-10-22, null, null, Marco, 2020-10-22 09:40:45.986, null, 1]

Log di MySql

2020-10-22T07:40:45.991964Z 69 Query INSERT INTO TESTDATEFIELD_PROVA (ID, COGNOME, CREATE_TS, CREATED_BY, DATA_PROVA, DELETE_TS, DELETED_BY, NOME, UPDATE_TS, UPDATED_BY, VERSION) VALUES (‘d76c12807bb72cfe9dc1e64ec1b5496c’, ‘Selmi’, ‘2020-10-22 07:40:45.986’, ‘admin’, ‘2020-10-21’, null, null, ‘Marco’, ‘2020-10-22 07:40:45.986’, null, 1)

Grazie in anticipo per l’aiuto.

Marco

Ciao, grazie per i dettagli, ti chiedo solo una info in più, cioè la DDL della tabella su MySQL, per verificare il tipo della colonna…

P.

Ciao,

Questa e’ quella di Cuba (DDL Preview)

create table TESTDATEFIELD_PROVA (
ID varchar(32),
VERSION integer not null,
CREATE_TS datetime(3),
CREATED_BY varchar(50),
UPDATE_TS datetime(3),
UPDATED_BY varchar(50),
DELETE_TS datetime(3),
DELETED_BY varchar(50),

DATA_PROVA date,
COGNOME varchar(100),
NOME varchar(50),

primary key (ID)
)^

Questa e’ quella che mi rende mysql con SHOW CREATE TABLE

CREATE TABLE TESTDATEFIELD_PROVA (
ID varchar(32) NOT NULL,
VERSION int(11) NOT NULL,
CREATE_TS datetime(3) DEFAULT NULL,
CREATED_BY varchar(50) DEFAULT NULL,
UPDATE_TS datetime(3) DEFAULT NULL,
UPDATED_BY varchar(50) DEFAULT NULL,
DELETE_TS datetime(3) DEFAULT NULL,
DELETED_BY varchar(50) DEFAULT NULL,
DATA_PROVA date DEFAULT NULL,
COGNOME varchar(100) DEFAULT NULL,
NOME varchar(50) DEFAULT NULL,
PRIMARY KEY (ID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Marco

Ciao Marco,
allora ho riprodotto un repo di test qui: https://github.com/cubait/cuba-testdatefield

Il repo utilizza Docker per poter gestire parallelamente tutti gli RDBMS supportati da CUBA. Se vuoi provarlo, devi avere Docker installato e funzionante.

Per avviare un motore di DB specifico devi lanciare il comando:
./gradlew start<motore>
Ad esempio ./gradlew startMysql per far partire MYSQL (in realtà è MariaDB 10.x)
Ricordati che poi vanno fermati manualmente, con il comando ./gradlew stop<motore>

Nella dir docker vedi i vari sh per far partire e fermare i vari motori (con il nome del DB e i parametri di connessione da usare).

Venendo al problema, come sospettavo è solo una questione di TZ sballato tra server tomcat e server DB. Nel tuo caso i due settings sono diversi.
Tomcat come mi hai confermato prende il TZ del tuo SO (che è Europe/Rome), mentre mysql di default opera in UTC. In particolare CUBA quando crea la connessione a mysql/mariadb imposta serverTimezone=UTC. Puoi vedere questi parametri nel file app.properties del core.
Infatti se usi un date di mysql, quando lo salva prende 2 ore prima, e quindi salva il giorno prima…

Per risolvere (almeno in locale mentre sviluppi) apri in edit il file setenv.sh nella dir deploy/tomcat/bin e forza il TZ della JVM a UTC:

CATALINA_OPTS="-Xmx512m -Duser.timezone=UTC -Dfile.encoding=UTF-8 -Dapp.home=\"$CATALINA_BASE/../app_home\""

# Uncomment in case of slow startup on Linux VM
#CATALINA_OPTS="$CATALINA_OPTS -Djava.security.egd=file:/dev/./urandom"

CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"
#CATALINA_OPTS="$CATALINA_OPTS \
#-Djava.rmi.server.hostname=localhost \
#-Dcom.sun.management.jmxremote.port=7777 \
#-Dcom.sun.management.jmxremote.ssl=false \
#-Dcom.sun.management.jmxremote.authenticate=false"
#CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.password.file=../conf/jmxremote.password -Dcom.sun.management.jmxremote.access.file=../conf/jmxremote.access"

JPDA_OPTS="-Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=n"

CATALINA_OPTS="$CATALINA_OPTS $STUDIO_OPTS"

Ricordati di rifare la modifica se fai un re-deploy di Tomcat, perché ti cancella tutto da deploy…

Se invece vuoi sbatterti per usare un TZ diverso su Mysql (cosa che non consiglio personalmente), segui questo articolo: https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html

Il problema con MySQL (che considero nettamente inferiore a Postgres) è questo (emphasis mine):

Several tables in the mysql system schema exist to store time zone information (see Section 5.3, “The mysql System Schema”).
The MySQL installation procedure creates the time zone tables, but does not load them.
To do so manually, use the following instructions.

Inoltre queste tabelle dovresti mantenerle aggiornate a mano se cambiano ore legali/solari ecc. Uno sbattimento… Resta in UTC e fai girare Tomcat in UTC anche in prod.

Spero ti abbia chiarito tutto :wink:

Paolo

Ciao Paolo,
innanzitutto ti ringrazio e complimenti per la chiarezza e completezza della risposta.

Ho provato a fare la modifica UTC al mio tomcat locale e miracolosamente le date cominciano a funzionare correttamente anche con MySql.

Dal momento che sono in fase di studio e sono ancora all’inizio credo valga la pena passare subito a Postgres cosi’ me lo ritrovo dopo.
Imparare cose nuove e guardare da altre prospettive non fa mai male.

Credo che comunque questo post sarà molto utile a tutti gli eventuali utenti italiani che iniziano con Cuba.

Grazie di nuovo e buon lavoro

Marco

1 Mi Piace

Grazie Marco per le belle parole :wink:

Ottima scelta, ricorda solo di configurare correttamente anche PostgreSQL. Leggi questo articolo conciso e abbastanza esaustivo: https://kb.objectrocket.com/postgresql/postgresql-set-time-zone-1064
Ricorda che di default il driver JDBC dovrebbe prendere il timezone della JVM, che a sua volta prende il TZ dell’SO. Quindi se sei in Europe/Rome, la connessione a PG dovrebbe essere già con quel TZ. Il problema con MySQL è che OOB non funziona al di fuori di UTC, mentre PG è subito pronto a lavorare con altri TZ.
Consiglio comunque di modificare il file postgresql.conf come dice l’articolo per forzare il TZ a livello di demone.

A tal proposito ti chiederei di contrassegnare il mio post precedente come soluzione, così gli utenti futuri vedranno subito la risposta funzionante :wink: Grazie!

Buon weekend,
Paolo

Ehm…non come fare per contrassegnarlo come soluzione…

C’e’ solo il “Mi piace”…

Marco