L'incubo Date

di il
11 risposte

L'incubo Date

Come da titolo
programmino in java, devo inserire a db in un campo di tipo DATE, una data che dovrà avere semplicemente giorno/mese/anno.
In un altro campo di tipo DATE, dovrà avere giorno/mese/anno ed orario fisso a 00:00 ecc

c'è un modo per formattare in questo modo senza far diventare la data una stringa?

11 Risposte

  • Re: L'incubo Date

    Quando si ha a che fare con i DB bisogna guardare al package java.sql e, soprattutto, bisogna utilizzare i PreparedStatement, così da non doversi preoccupare della formattazione di alcunché.

    Quindi, per memorizzare un valore in un campo di tipo DATE, si usa il metodo setDate() di PreparedStatement che prende un oggetto java.sql.Date (da notare che è una sottoclasse di java.util.Date, che però, in questo caso, non c'entra poi molto).

    Per memorizzare un valore in un campo di tipo DATETIME, si usa il metodo setTimestamp() di PreparedStatement che prende un oggetto java.sql.Timestamp.

    Se hai un oggetto java.util.Date puoi ottenere un java.sql.Date o un java.sql.Timestamp semplicemente sfruttando il metodo getTime() dell'oggetto java.util.Date da passare al costruttore di ciascuna delle due classi:
    
    java.util.Date tuaData = ...;
    java.sql.Date dataDB = new java.sql.Date( tuaData.getTime() );
    java.sql.Timestamp ts = new java.sql.Timestamp( tuaData.getTime() );
    
    Sarà il driver JDBC ad occuparsi di formattare correttamente i due valori per il database che c'è sotto.

    Supponendo di voler inserire quei due oggetti in una tabella con i due campi (data1 di tipo DATE e data2 di tipo DATETIME):
    
    PreparedStatement pstmt = null;
    try {
       pstmt = con.prepareStatement("INSERT INTO tabella(data1, data2) VALUES (?, ?)");
       pstmt.setDate(1, dataDB);
       pstmt.setTimestamp(2, ts);
       pstmt.executeUpdate();
    } catch (Exception e) {
       e.printStackTrace();
    } finally {
       if (pstmt != null) {
          try { pstmt.close(); } catch (Exception e) { }
       }
    }
    
    Ciao.
  • Re: L'incubo Date

    Test90 ha scritto:


    programmino in java, devo inserire a db in un campo di tipo DATE, una data che dovrà avere semplicemente giorno/mese/anno.
    In un altro campo di tipo DATE, dovrà avere giorno/mese/anno ed orario fisso a 00:00 ecc
    Il tipo DATE non ha orario. Se vuoi una data con orario (anche messo fisso a 00:00), quello è il tipo TIMESTAMP (mappato con java.sql.Timestamp)

    Test90 ha scritto:


    c'è un modo per formattare in questo modo senza far diventare la data una stringa?
    Cosa usi per l'accesso al DB? Direttamente JDBC? Allora una colonna di tipo DATE si "mappa" in un java.sql.Date. La eventuale formattazione/parsing sta solo a monte se devi mostrare/richiedere la data all'utente.
  • Re: L'incubo Date

    Grazie ad entrambi, dò qualche info in più e mi date amgari una opinione sulla mia soluzione che non posso testare.

    La classe non è mia, devo solo apporre le modifiche dette.

    Nella insert bisogna inserire la data, attualmente c'è un new Date () di java.util che però inserisce anche l'orario da quello che mi è stato detto va eliminato. così va bene o poi la insert non va a buon fine? in pratica passo l'elaborazione di questo metodo
    LocalDate localDate = Instant.ofEpochMilli(newDate().getTime())
                                .atZone(ZoneId.systemDefault())
                                .toLocalDate();

    Per l'altro, stessa situazione, come metto fisso il timestamp a 0:00:00 ?
  • Re: L'incubo Date

    E se inserisco questo localdate, quando poi preleverò dal db combacerà con il tipo Date del mio dto? perché una volta prelevato devo confrontarlo con la data odierna e fare determiante cose nel caso sia minore.
  • Re: L'incubo Date

    Test90 ha scritto:


    LocalDate localDate = Instant.ofEpochMilli(newDate().getTime())
                                .atZone(ZoneId.systemDefault())
                                .toLocalDate();
    Questo è uno di quei classici "giri" inutili che dimostrano che chi l'ha scritto non sa usare la Date/Time API di Java 8.

    Se vuoi il LocalDate "corrente" (e nel ZoneId "di sistema"):
    LocalDate localDate = LocalDate.now();

    Test90 ha scritto:


    Per l'altro, stessa situazione, come metto fisso il timestamp a 0:00:00 ?
    Dipende da che tipo parti o quale vuoi arrivare ad ottenere.

    Se vuoi partire sempre da un LocalDate e vuoi ottenere un LocalDateTime:
    LocalDateTime ldt = LocalDate.now().atStartOfDay();
    System.out.println(ldt);      // Stampa es.  2020-05-05T00:00
  • Re: L'incubo Date

    Mi stanno facendo andare al manicomio.
    A DB la colonna è di tipo TIMESTAMP .
    Nel primo caso, bisogna inserire solo giorno, mese, anno. Ma così non va ad aggiungere in automatico anche l'orario essendo di tipo timestamp? Una volta prelevato questo campo dal db e valorizzato il mio dto, potrò fare un confronto tra data odierna e quella recuperata da db? ad esempio se di tipo Date usavo il compareTo, qui come faccio?
  • Re: L'incubo Date

    Test90 ha scritto:


    A DB la colonna è di tipo TIMESTAMP .
    Che DB usi? C'è la differenza nel tuo DB tra TIMESTAMP con e senza Timezone?

    Test90 ha scritto:


    Nel primo caso, bisogna inserire solo giorno, mese, anno. Ma così non va ad aggiungere in automatico anche l'orario essendo di tipo timestamp?
    Chiariamo una cosa quale driver JDBC stai usando? Per la precisione: con quale versione di JDBC è compliant?
    Perché la Date/Time API c'è ovviamente da Java 8 e in questa release c'è anche JDBC 4.2. Sfortunatamente i tipi come PreparedStatement NON sono stati (ancora) aggiornati, cioè non esiste al momento un es. setLocalDate o setLocalDateTime.
    Però la Date/Time API è supportata da JDBC 4.2 tramite il setObject?.

    Quindi se (SE) hai un driver almeno JDBC 4.2 compliant, es.:
    PreparedStatement pstm = // ........
    
    pstm.setObject(indice, LocalDate.now().atStartOfDay());

    Test90 ha scritto:


    Una volta prelevato questo campo dal db e valorizzato il mio dto, potrò fare un confronto tra data odierna e quella recuperata da db? ad esempio se di tipo Date usavo il compareTo, qui come faccio?
    Idem per il ResultSet, sfortunatamente non c'è un es. getLocalDateTime o cose del genere.
    Quindi:
    - usi il getTimestamp? per avere un java.sql.Timestamp, che puoi poi trasformare in altro
    - usi il getObject
  • Re: L'incubo Date

    andbin ha scritto:



    Che DB usi? C'è la differenza nel tuo DB tra TIMESTAMP con e senza Timezone?
    Su questo punto non ti so dire, non è un qualcosa fatto da me e non so neppure verificare. Quello che vedo è che se anche metto 00:00:00 come orario (ed a db vedo effettivamente 06/05/2020 00:00:00) quando il servizio viene richiamato una seconda volta va cmq a fare la insert quando non dovrebbe, visto che quella data è già presente ed è chiave primaria...
  • Re: L'incubo Date

    Test90 ha scritto:


    Su questo punto non ti so dire, non è un qualcosa fatto da me e non so neppure verificare.
    Ma saprai almeno che DB è, no? MySQL? PostgreSQL? Altro?

    Test90 ha scritto:


    Quello che vedo è che se anche metto 00:00:00 come orario (ed a db vedo effettivamente 06/05/2020 00:00:00) quando il servizio viene richiamato una seconda volta va cmq a fare la insert quando non dovrebbe, visto che quella data è già presente ed è chiave primaria...
    Puoi mostrare, anche solo in parte come avviene questa insert?
  • Re: L'incubo Date

    andbin ha scritto:


    Posto il postabile:
    in precendeza fa una select su una tabella prendendo e valorizzando campo1 e campo2 del mio dto.
    		Timestamp starttijd = new Timestamp(System.currentTimeMillis());	
    					starttijd.setHours(0);
    					starttijd.setMinutes(0);
    					starttijd.setSeconds(0);  

    //a questo punto inserisce nella seguente tab le info recuperate dalla select precedente + la data con gli 00:00:00. tutti e tre i campi sono pk, teoricamente dovrebbe avere sempre 06/05/2020 00:00:00 e così vedo da db, ma continua comunque ad inserire il nuovo record ogni volta che viene chiamato e non solo una volta al giorno
    String query = "INSERT INTO tabella(campo1, campo2, campo3) " + "VALUES (?,?,?) ";
     
                                                            Connector.call(queryInsert, Transformer, AltroTransformer,
    							DB2QueryType.UPDATE,  dto.getcampo1(),dto.getcampo2(), starttijd
    							);
  • Re: L'incubo Date

    Test90 ha scritto:


    		Timestamp starttijd = new Timestamp(System.currentTimeMillis());	
    					starttijd.setHours(0);
    					starttijd.setMinutes(0);
    					starttijd.setSeconds(0);  
    A parte il fatto che i setHours/setMinutes/setSeconds (che derivano da java.util.Date) sono deprecati (ormai dal JDK 1.1) e NON si dovrebbero usare.
    Ma in ogni caso questi set azzerano solo fino al secondo. Ma ... Timestamp ha precisione del nanosecondo. Però tu lo imposti con il currentTimeMillis() che ha solo la precisione del MILLIsecondo (e idem il costruttore di Timestamp). Quindi la parte micro/nano-secondi è certamente 0 ma i millisecondi ci sono!!

    Se tu stampi quel starttijd vedi es.

    2020-05-06 00:00:00.468

    Quindi non è vero che l'orario è proprio 0. Sono 468 millisecondi dopo la mezzanotte!

    Come si risolve? Si deve anche fare:

    starttijd.setNanos(0);

    setNanos è specifico di java.sql.Timestamp e NON è deprecato (si può usare).

    Test90 ha scritto:


    ma continua comunque ad inserire il nuovo record ogni volta che viene chiamato e non solo una volta al giorno
    E sarà mica per i millisecondi che ho appena detto??

    Test90 ha scritto:


    String query = "INSERT INTO tabella(campo1, campo2, campo3) " + "VALUES (?,?,?) ";
     
                                                            Connector.call(queryInsert, Transformer, AltroTransformer,
    							DB2QueryType.UPDATE,  dto.getcampo1(),dto.getcampo2(), starttijd
    							);
    Purtroppo questa API custom non mi dice nulla


    EDIT: se vuoi un Timestamp "odierno" ma con orario 0, è semplice:
    Timestamp mezzanotteDiOggi = Timestamp.valueOf(LocalDate.now().atStartOfDay());
Devi accedere o registrarti per scrivere nel forum
11 risposte