Italian MSSQL server e date

micro

Well-Known Member
Licensed User
Longtime User
Salve ragazzi
un piccolo problema con il salvataggio delle date in un database mssql (con impostato lingua italiano).
Nel campo data se gli passo una data formattata gg/MM/yyyy (perchè è così che lavoro in B4J) me la ritrovo memorizzato così: yyyy-MM-gg.
E' la prima volta che mi accingo a fare prove con mssql e non saprei cosa impostare per avere una data formattata come la Ns. classica.
Ho provato anche all'inizio quando controllo la presenza delle tabelle nel DB ad inserire questo codice:
B4X:
Dim sql As SQL = pool.GetConnection
sql.BeginTransaction
sql.ExecNonQuery("SET DATEFORMAT dmy")
sql.ExecNonQuery("SET LANGUAGE Italian")
sql.TransactionSuccessful
sql.Close
ma nulla.
Qualcuno che ci è già passato?
Grazie
 

Picena Informatica

Active Member
Licensed User
Longtime User
Salvala come stringa: yyyyMMdd HHmmss o come double. In entrambi i casi puoi fare ricerche e query coerenti. La riconversione non è automatica.
 

sirjo66

Well-Known Member
Licensed User
Longtime User
attenti a non fare confusione tra il tipo di dato (che è una data) e la sua rappresentazione visiva

(piccola parentesi: personalmente uso il "SET DATEFORMAT ymd" ma questo è soggettivo)

Se tu utilizzi il "SET DATEFORMAT dmy", gli stai semplicemente dicendo in che formato gli passerai una data, e lui quindi sa come convertirsela nel suo formato e la memorizza quindi correttamente dentro nel database.
Poi, una volta che vai a leggerla, questo è un altro discorso, perchè comunque ti ritrovi un dato che è di tipo "data" e sta a te trasformarla in stringa nel formato che più ti piace (dmy, mdy o altro).
Nel database la data viene sempre memorizzata come yyyymmgg (che è appunto l'impostazione internazione di default), perchè così il database può facilmente fare ricerche, ma soprattutto riesce a metterla in ordine crescende/decrescente senza problemi dato che è proprio un numero progressivo intero

Se la data che leggi è comunque corretta, ti basta solamente stare attento a quando la devi visualizzare a video (cioè quando la devi trasformare da "data" a "stringa")

Per qualsiasi altro dubbio chiedi pure

Sergio
 

micro

Well-Known Member
Licensed User
Longtime User
Salvala come stringa:
bhè picenainformatica è quello che ho fatto sino ad ora e mai avuto problemi ma penso che a livello prestazionale
se un campo è date è meglio usarla per quello che è.

Se tu utilizzi il "SET DATEFORMAT dmy", gli stai semplicemente dicendo in che formato gli passerai una data, e lui quindi sa come convertirsela nel suo formato e la memorizza quindi correttamente dentro nel database.
Poi, una volta che vai a leggerla, questo è un altro discorso, perchè comunque ti ritrovi un dato che è di tipo "data" e sta a te trasformarla in stringa nel formato che più ti piace (dmy, mdy o altro).
Nel database la data viene sempre memorizzata come yyyymmgg (che è appunto l'impostazione internazione di default), perchè così il database può facilmente fare ricerche, ma soprattutto riesce a metterla in ordine crescende/decrescente senza problemi dato che è proprio un numero progressivo intero

Se la data che leggi è comunque corretta, ti basta solamente stare attento a quando la devi visualizzare a video (cioè quando la devi trasformare da "data" a "stringa")
Perfetto Sergio mi hai chiarito un bel pò, grazie come sempre.

Grazie a tutti per le info
 
Last edited:

micro

Well-Known Member
Licensed User
Longtime User
Una perplessità; ma tu sergio dici di convertirla in stringa per visualizzarla nel modo che gradisco da codice B4J oppure con istruzioni sql perchè mi sembra che ce ne siano, vedi CONVERT.

Ancora qualcosa che non va perchè leggendo in giro con CONVERT dovrei riuscirci ma ho problemi.

Se inserisco una map in sql con DBUtils.InsertMaps, dove ho una key di questo tipo:
B4X:
mapins.Put("DATA", DateTime.Date(DateTime.DateParse(mapmem.Get("Data"))))
e dove mapmem.Get("Data") = "28/10/2016/, mi scrive il record senza problemi e nel campo DATA mi ritovo 2016-10-28.
Se aggiungo alla stessa key della map:
B4X:
mapins.Put("DATA", "CONVERT(date, '" & DateTime.Date(DateTime.DateParse(mapmem.Get("Data")) & "', 3"))
dove 3 secondo lo standard britannico dovrebbe rappresentare la data in gg/mm/yyyy, mi compare questo errore
B4X:
(SQLException) java.sql.SQLException: Conversione non riuscita durante la conversione di una stringa di caratteri in una data o ora.

Ora mi sto incartando
 
Last edited:

sirjo66

Well-Known Member
Licensed User
Longtime User
da quel che mi risulta la funzione CONVERT serve per convertire i dati nel formato che tu vuoi quando vai a LEGGERLI (cioè quando usi SELECT) e non quando vai a scriverli.
Infatti non capisco il perchè di tutto questo, tu hai detto che nel campo DATA ti ritrovi 2016-10-28 che è qiusto, perchè allora utilizzi il CONVERT ??

Semmai il CONVERT lo usi quando leggi il database, ma anche qui secondo me è sbagliato.

Ancora non capisco dove devi visualizzare questa data e con che codice lo fai.
Tu hai un problema di visualizzazione, non di memorizzazione, infatti nel database la data è corretta.

E' come se io ti dicessi che ho un problema di questo tipo:
B4X:
Dim aaa As Int
aaa = 0x50
Msgbox(aaa,"")
vado ad assegnare ad una variabile di tipo Int il valore 0x50 (in esadecimale) ma poi quando lo visualizzo con MsgBox mi ritrovo il valore 80 (decimale) mentre io voglio ritrovarmi di nuovo il valore 0x50 e ti dico che non capisco come fare ad assegnarli il valore 0x50 esadecimale anzichè il valore 80 decimale
Tu che rispondi ??
Mi dirai che 0x50 e 80 decimale è la stessa cosa e che l'assegnazione della variabile è corretta, ed è infatti la stessa cosa che ti dico io per il tuo caso.
Tu hai assegnato correttamente al campo DATA una data valida, ora quando la leggi sta a te visualizzarla in modo corretto, mostraci il codice di quando la leggi e la visualizzi

Sergio
 
Last edited:

sirjo66

Well-Known Member
Licensed User
Longtime User
dove 3 secondo lo standard britannico dovrebbe rappresentare la data in gg/mm/yyyy

Sbagliato anche questo !!

3 = gg/mm/aa

103 = gg/mm/aaaa
 

micro

Well-Known Member
Licensed User
Longtime User
Si Sergio tutto giusto quello che dici, avevo sistemato agendo sul DateFormat in B4j in lettura dal Db, qualche passaggio in più perché leggo in un formato e glielo passo in un altro perché gradisco dd/MM/yyyy ma alla fine ho capito come venirne a capo.
Devo vedere come fare il Convert dalla query
Così evito qualche passaggio in b4j.
Grazie ancora.
 

sirjo66

Well-Known Member
Licensed User
Longtime User
esatto, devi utilizzare il CONVERT quando leggi dal database, così ti ritrovi già la data nel formato corretto ed eviti di dover convertire dopo

;)

l'unico svantaggio è che in questo caso ti ritrovi una stringa, e non una data, ma se non devi fare ulteriori calcoli puoi fare così senza problemi
 

micro

Well-Known Member
Licensed User
Longtime User
l'unico svantaggio è che in questo caso ti ritrovi una stringa, e non una data, ma se non devi fare ulteriori calcoli puoi fare così senza problemi
esatto, per ora non servono calcoli.
Un'altra cosa, in un semplice "SELCT * FROM Table" per riempire una TableView come lo inserisco il CONVERT considerando che ci sono due campi con le date chiamate DATA_PARTENZA e DATA_SPEDIZIONE ?
Grazie e Buon fine settimana a tutti.
 

sirjo66

Well-Known Member
Licensed User
Longtime User
esatto, per ora non servono calcoli.
Un'altra cosa, in un semplice "SELCT * FROM Table" per riempire una TableView come lo inserisco il CONVERT considerando che ci sono due campi con le date chiamate DATA_PARTENZA e DATA_SPEDIZIONE ?
Grazie e Buon fine settimana a tutti.

Ad esempio così:
B4X:
select *, CONVERT(varchar, DATA_PARTENZA, 103) as strDataPartenza, CONVERT(varchar, DATA_SPEDIZIONE, 103) as strDataSpedizione from Table

Ti ritroverai così i campi strDataPartenza e strDataSpedizione con le date nel formato che vuoi tu

Sergio
 

micro

Well-Known Member
Licensed User
Longtime User
Ok, grazie
Avrei preferito che SQL fosse più dalla mia parte :D nel senso che se mettevo
B4X:
CONVERT(varchar, DATA_PARTENZA, 103) as DATA_PARTENZA
la colonna restava sempre quella ma con i valori come li voglio io, mentre mi ricrea un ulteriore colonna accodata alla fine.
Ho contorto un attimo la Sub in DBUtils ma almeno non creo diversi Select perchè non tutte le tabelle hanno dei campi Data ed io ho una una singola Sub che voglio mantenere pulita.
B4X:
Public Sub ExecuteTableView(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView)
    TableView1.Items.Clear
    Dim cur As ResultSet
    Dim datas As Long
    If StringArgs = Null Then
        Dim StringArgs(0) As String
    End If
    cur = SQL.ExecQuery2(Query, StringArgs)
    Dim cols As List
    cols.Initialize
    For i = 0 To cur.ColumnCount - 1
        cols.Add(cur.GetColumnName(i))
    Next
    TableView1.SetColumns(cols)
    Do While cur.NextRow
        Dim values(cur.ColumnCount) As String
        For col = 0 To cur.ColumnCount - 1
            values(col) = cur.GetString2(col)
            If cur.GetColumnName(col).ToUpperCase.StartsWith("DATA") Then
                DateTime.DateFormat = "yyyy-MM-dd"
                datas = DateTime.DateParse(values(col))
                DateTime.DateFormat = "dd/MM/yyyy"
                If datas > 0 Then values(col) = DateTime.Date(datas)
            End If
        Next
        TableView1.Items.Add(values)
        If Limit > 0 And TableView1.Items.Size >= Limit Then Exit
    Loop
    cur.Close
End Sub
Non credo vengano degradate più di tanto le prestazioni in lettura.
 

LucaMs

Expert
Licensed User
Longtime User
Non mi intrometto perché le date mi stancano più del necessario e oggi sono particolarmente pigro :p

L'unica cosa che farei, ammesso che il codice sopra funzioni e sia "ottimale", salverei il formato data correntemente impostato prima della routine e lo reimposterei alla fine.

Cioè, se il programmatore nel proprio progetto utilizza un proprio formato per le date, questo va reimpostato all'uscita dalla routine.
 

micro

Well-Known Member
Licensed User
Longtime User
L'unica cosa che farei, ammesso che il codice sopra funzioni e sia "ottimale", salverei il formato data correntemente impostato prima della routine e lo reimposterei alla fine.
Ciao Luca è un piacere risentirti.
Di funzionare funziona perchè l'ho provato, non so dirti quanto sia ottimale ma considera che il CONVERT di SQL lo fa in questo caso B4J quindi presumo che grosse differenze non ce ne siano.
Io il DataFormat lo utilizzo come è giusto che sia all'inizializzazione del programma e non lo tocco più ma in questo caso considerando il formato di memorizzazione in mssql che è diferrente da quello che gradisco sono costretto a fare in quel modo.
In quel ciclo sopra che vedi se non uso prima un DateFormat e dopo un altro il DateParse e la reimpostazione al mio formato fallisce.
 

LucaMs

Expert
Licensed User
Longtime User
Ciao.

Non mi sono spiegato.

Non critico la modifica che hai fatto alla ExecuteTableView (perché non ho voglia di metterci i due neuroni stanchi :D), mi fido e suppongo che funzioni bene.

Dicevo, proprio perché...
Io il DataFormat lo utilizzo come è giusto che sia all'inizializzazione del programma
la routine ExecuteTableView dovrebbe memorizzare all'inizio il DateFormat impostato dal programmatore nel proprio progetto, come fai tu, e reimpostarlo all'uscita, per conservare, quindi, l'impostazione voluta dal programmatore.

Insomma, aggiungerei:
B4X:
Public Sub ExecuteTableView(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView)
    Private CurrentDateFormat As String = DateTime.DateFormat
'...
'...
    DateTime.DateFormat = CurrentDateFormat
End Sub
 

micro

Well-Known Member
Licensed User
Longtime User
Insomma, aggiungerei:
B4X:
Public Sub ExecuteTableView(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView)
    Private CurrentDateFormat As String = DateTime.DateFormat
'...
'...
    DateTime.DateFormat = CurrentDateFormat
End Sub

Se faccio come dici tu questa parte di codice che segue che si occupa della conversione non funzionerebbe
perchè è qui che leggo record per record in un formato e lo trasformo in un altro
B4X:
For col = 0 To cur.ColumnCount - 1
        values(col) = cur.GetString2(col)
        If cur.GetColumnName(col).ToUpperCase.StartsWith("DATA") Then
            DateTime.DateFormat = "yyyy-MM-dd"
            datas = DateTime.DateParse(values(col))
            DateTime.DateFormat = "dd/MM/yyyy"
            If datas > 0 Then values(col) = DateTime.Date(datas)
        End If
Next
E' la prima cosa che ho fatto perchè è quella che viene subito in mente (parlo del tuo suggerimento) ma va bene
se è solo un record che devo leggere.
 

LucaMs

Expert
Licensed User
Longtime User
Non hai letto bene e non hai provato.

Proprio perché tu modifichi il DateFormat all'interno della routine (in particolare nel ciclo for next) penso che si debba salvare l'impostazione del formato quando si entra nella routine e ripristinarlo quando si esce, così all'interno della routine puoi utilizzare il formato che vuoi (cosa che fai perché ti serve).

Se faccio come dici tu questa parte di codice che segue che si occupa della conversione non funzionerebbe
Se io aggiungo, come "ho fatto", una variabile "buffer" (CurrentDateFormat) per salvare il formato quando si entra nella routine per poi ripristinarlo all'uscita, prima della End Sub, questo non può influire sul codice interno alla routine (e quindi interno al ciclo For Next)
 

micro

Well-Known Member
Licensed User
Longtime User
E' proprio vero che a una certa età è difficile farsi capire o non capire l'altro che cerca di spiegarti :D
Perdonami Luca, faccio passo per passo:
B4X:
If cur.GetColumnName(col).ToUpperCase.StartsWith("DATA") Then
qui ho la colonna DATAxxxxx dal db che è in questo formato yyyy-MM-dd,
se non faccio
B4X:
DateTime.DateFormat = "yyyy-MM-dd"
il codice che segue
B4X:
datas = DateTime.DateParse(values(col))
proprio perchè io lavoro con
B4X:
DateTime.DateFormat = "dd/MM/yyyy"
solleverebbe un'eccezione
dopo che ho la data nel mio formato devo correggere la cella in quel momento
quindi o agisco di reverse e sostituisco gli "-" con "/" o con qualche substring,
oppure semplicemente come ho fatto
B4X:
DateTime.DateFormat = "dd/MM/yyyy"
If datas > 0 Then values(col) = DateTime.Date(datas)
dopo che ciclo gli altri record se non rimetto nuovamente il DateFormat non funzionerebbe.
Quindi potrei anche fare come suggerisci tu però nel ciclo devo inserire delle operazioni
di aggiustaggio stringa e non so se così sono più veloce.
Visto che DataFormat è un'istruzione di sistema pensavo fosse più performante e quindi conveniente
cambiare quella più volte.
 

sirjo66

Well-Known Member
Licensed User
Longtime User
Ok, grazie
Avrei preferito che SQL fosse più dalla mia parte :D nel senso che se mettevo
B4X:
CONVERT(varchar, DATA_PARTENZA, 103) as DATA_PARTENZA
la colonna restava sempre quella ma con i valori come li voglio io, mentre mi ricrea un ulteriore colonna accodata alla fine.

Esatto, ecco perchè ho chiamato le nuove colonne strDataPartenza e strDataSpedizione, per non confonderle con le altre già esistenti.

Una soluzione a questo è eliminare l'asterisco (che vuol dire "tutte le colonne"), ed elencare esattamente tutte le colonne che vuoi, ad esempio:
B4X:
select ID, Nome, Cognome, AltriDati, BlaBlaBla, CONVERT(varchar, DATA_PARTENZA, 103) as DATA_PARTENZA, CONVERT(varchar, DATA_SPEDIZIONE, 103) as DATA_SPEDIZIONE from Table
 

LucaMs

Expert
Licensed User
Longtime User
E' proprio vero che a una certa età è difficile farsi capire o non capire l'altro che cerca di spiegarti :D

Infatti, c'era un comico che diceva qualcosa tipo: "parlamm e non c capimm"

Io non ho voluto addentrarmi nella discussione (troppa fatica):
Non mi intrometto perché le date mi stancano più del necessario e oggi sono particolarmente pigro :p

Ho voluto solo dire che, in alcuni casi, come questo, se una routine d'utilità modifica un valore (DateFormat) che è poi utilizzato dall'intera app, questo valore va poi ripristinato; quindi, non sto criticando la routine e ciò che fa perché non lo so nemmeno, non mi sono addentrato nella faccenda (anche perché io userei un long).

Forse riesco a spiegarmi meglio con un esempio molto simile.

Mettiamo che il programmatore metta nello Starter un proprio formato per il Time per visualizzare anche i millisecondi che, di default, non vengono visualizzati.
Se poi ha una routine (paragonabile a ExecuteTableView) nella quale per motivi di necessità il formato viene modificato SOLO localmente, questo va ripristinato all'uscita dalla routine.

' Starter
B4X:
DateTime.TimeFormat = "hh:mm:ss:SSS ' visualizza anche i millisecondi


' Modulo di codice con routine di utilità
B4X:
Sub MyRoutine
    Private CurrentTimeFormat = DateTime.TimeFormat

' qui per necessità DateTime.TimeFormat viene impostato in maniera diversa
    DateTime.TimeFormat = "hh:mm" ' solo ore e minuti
' calcoli vari
' ...

' Reimposto il formato precedente all'entrata nella funzione
' perchè può essere stato impostato altrove dal programmatore
    DateTime.TimeFormat = CurrentTimeFormat

End Sub
 
Last edited:
Top