SQLite può utilizzare tipi di dati di testo, reali o interi per memorizzare le date. Inoltre, ogni volta che si esegue una query, i risultati vengono visualizzati utilizzando il formato %Y-%m-%d %H:%M:%S
.
Ora, se inserisci / aggiorni i valori di data / ora utilizzando le funzioni di data / ora di SQLite, puoi effettivamente memorizzare anche i millisecondi. In tal caso, i risultati vengono visualizzati utilizzando il formato %Y-%m-%d %H:%M:%f
. Per esempio:
sqlite> create table test_table(col1 text, col2 real, col3 integer);
sqlite> insert into test_table values (
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123')
);
sqlite> insert into test_table values (
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126')
);
sqlite> select * from test_table;
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
Ora, facendo alcune domande per verificare se siamo effettivamente in grado di confrontare i tempi:
sqlite> select * from test_table /* using col1 */
where col1 between
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.121') and
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.125');
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
Puoi controllare lo stesso SELECT
usando col2
e col3
e otterrai gli stessi risultati. Come puoi vedere, la seconda riga (126 millisecondi) non viene restituita.
Nota che BETWEEN
è inclusivo, quindi ...
sqlite> select * from test_table
where col1 between
/* Note that we are using 123 milliseconds down _here_ */
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123') and
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.125');
... restituirà lo stesso set.
Prova a giocare con diversi intervalli di data / ora e tutto si comporterà come previsto.
Che dire senza strftime
funzione?
sqlite> select * from test_table /* using col1 */
where col1 between
'2014-03-01 13:01:01.121' and
'2014-03-01 13:01:01.125';
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
Che dire senza strftime
funzione e senza millisecondi?
sqlite> select * from test_table /* using col1 */
where col1 between
'2014-03-01 13:01:01' and
'2014-03-01 13:01:02';
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
Che dire ORDER BY
?
sqlite> select * from test_table order by 1 desc;
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
sqlite> select * from test_table order by 1 asc;
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
Funziona bene.
Infine, quando si ha a che fare con operazioni reali all'interno di un programma (senza usare l'eseguibile sqlite ...)
A proposito: sto usando JDBC (non sono sicuro di altre lingue) ... il driver sqlite-jdbc v3.7.2 da xerial - forse le revisioni più recenti cambiano il comportamento spiegato di seguito ... Se stai sviluppando in Android, non lo fai serve un driver jdbc. Tutte le operazioni SQL possono essere inviate utilizzando il SQLiteOpenHelper
.
JDBC ha metodi diversi per ottenere i valori reali di data / ora da un database: java.sql.Date
, java.sql.Time
, e java.sql.Timestamp
.
I metodi correlati a java.sql.ResultSet
sono (ovviamente) getDate(..)
, getTime(..)
e getTimestamp()
rispettivamente.
Per esempio:
Statement stmt = ... // Get statement from connection
ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_TABLE");
while (rs.next()) {
System.out.println("COL1 : "+rs.getDate("COL1"));
System.out.println("COL1 : "+rs.getTime("COL1"));
System.out.println("COL1 : "+rs.getTimestamp("COL1"));
System.out.println("COL2 : "+rs.getDate("COL2"));
System.out.println("COL2 : "+rs.getTime("COL2"));
System.out.println("COL2 : "+rs.getTimestamp("COL2"));
System.out.println("COL3 : "+rs.getDate("COL3"));
System.out.println("COL3 : "+rs.getTime("COL3"));
System.out.println("COL3 : "+rs.getTimestamp("COL3"));
}
// close rs and stmt.
Poiché SQLite non ha un tipo di dati DATE / TIME / TIMESTAMP effettivo, tutti questi 3 metodi restituiscono valori come se gli oggetti fossero inizializzati con 0:
new java.sql.Date(0)
new java.sql.Time(0)
new java.sql.Timestamp(0)
Quindi, la domanda è: come possiamo effettivamente selezionare, inserire o aggiornare gli oggetti Data / Ora / Timestamp? Non c'è una risposta facile. Puoi provare diverse combinazioni, ma ti costringeranno a incorporare le funzioni SQLite in tutte le istruzioni SQL. È molto più semplice definire una classe di utilità per trasformare il testo in oggetti Date all'interno del programma Java. Ma ricorda sempre che SQLite trasforma qualsiasi valore di data in UTC + 0000.
In sintesi, nonostante la regola generale di utilizzare sempre il tipo di dati corretto, o anche numeri interi che indicano il tempo Unix (millisecondi dall'epoca), trovo molto più facile utilizzare il formato SQLite predefinito ( '%Y-%m-%d %H:%M:%f'
o in Java 'yyyy-MM-dd HH:mm:ss.SSS'
) piuttosto che complicare tutte le tue istruzioni SQL con Funzioni SQLite. Il primo approccio è molto più semplice da mantenere.
TODO: Controllerò i risultati quando uso getDate / getTime / getTimestamp all'interno di Android (API15 o superiore) ... forse il driver interno è diverso da sqlite-jdbc ...