SQLite peut utiliser des types de données texte, réels ou entiers pour stocker des dates. De plus, chaque fois que vous effectuez une requête, les résultats sont affichés en utilisant le format %Y-%m-%d %H:%M:%S
.
Maintenant, si vous insérez / mettez à jour des valeurs de date / heure à l'aide des fonctions de date / heure SQLite, vous pouvez également stocker des millisecondes. Si tel est le cas, les résultats sont affichés en utilisant le format %Y-%m-%d %H:%M:%f
. Par exemple:
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
Maintenant, faire quelques requêtes pour vérifier si nous sommes réellement en mesure de comparer les temps:
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
Vous pouvez vérifier la même en SELECT
utilisant col2
et col3
vous obtiendrez les mêmes résultats. Comme vous pouvez le voir, la deuxième ligne (126 millisecondes) n'est pas renvoyée.
Notez que BETWEEN
c'est inclusif, donc ...
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');
... renverra le même ensemble.
Essayez de jouer avec différentes plages de date / heure et tout se comportera comme prévu.
Et sans strftime
fonction?
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
Qu'en est-il sans strftime
fonction et sans millisecondes?
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
Et alors 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
Fonctionne très bien.
Enfin, lorsqu'il s'agit d'opérations réelles au sein d'un programme (sans utiliser l'exécutable sqlite ...)
BTW: J'utilise JDBC (je ne suis pas sûr des autres langues) ... le pilote sqlite-jdbc v3.7.2 de xerial - peut-être que des révisions plus récentes modifient le comportement expliqué ci-dessous ... Si vous développez sous Android, vous ne le faites pas besoin d'un pilote jdbc. Toutes les opérations SQL peuvent être soumises à l'aide du SQLiteOpenHelper
.
JDBC a différentes méthodes pour obtenir des valeurs de date / heure réelle à partir d' une base de données: java.sql.Date
, java.sql.Time
et java.sql.Timestamp
.
Les méthodes connexes java.sql.ResultSet
sont (évidemment) getDate(..)
, getTime(..)
et getTimestamp()
respectivement.
Par exemple:
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.
Étant donné que SQLite n'a pas de type de données DATE / TIME / TIMESTAMP réel, toutes ces 3 méthodes retournent des valeurs comme si les objets étaient initialisés avec 0:
new java.sql.Date(0)
new java.sql.Time(0)
new java.sql.Timestamp(0)
Donc, la question est: comment pouvons-nous réellement sélectionner, insérer ou mettre à jour des objets Date / Heure / Horodatage? Il n'y a pas de réponse facile. Vous pouvez essayer différentes combinaisons, mais elles vous forceront à intégrer des fonctions SQLite dans toutes les instructions SQL. Il est beaucoup plus facile de définir une classe utilitaire pour transformer du texte en objets Date dans votre programme Java. Mais rappelez-vous toujours que SQLite transforme toute valeur de date en UTC + 0000.
En résumé, malgré la règle générale de toujours utiliser le type de données correct, ou même des entiers indiquant le temps Unix (millisecondes depuis l'époque), je trouve beaucoup plus facile d'utiliser le format SQLite par défaut ( '%Y-%m-%d %H:%M:%f'
ou en Java 'yyyy-MM-dd HH:mm:ss.SSS'
) plutôt que de compliquer toutes vos instructions SQL avec Fonctions SQLite. L'ancienne approche est beaucoup plus facile à maintenir.
TODO: Je vérifierai les résultats lors de l'utilisation de getDate / getTime / getTimestamp dans Android (API15 ou mieux) ... peut-être que le pilote interne est différent de sqlite-jdbc ...