O SQLite pode usar tipos de dados de texto, reais ou inteiros para armazenar datas. Ainda mais, sempre que você realiza uma consulta, os resultados são mostrados usando o formato %Y-%m-%d %H:%M:%S
.
Agora, se você inserir / atualizar valores de data / hora usando as funções de data / hora do SQLite, também poderá armazenar milissegundos. Se for esse o caso, os resultados são mostrados usando o formato %Y-%m-%d %H:%M:%f
. Por exemplo:
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
Agora, faça algumas consultas para verificar se conseguimos comparar os tempos:
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
Você pode verificar o mesmo SELECT
usando col2
e col3
e você vai obter os mesmos resultados. Como você pode ver, a segunda linha (126 milissegundos) não é retornada.
Observe que BETWEEN
é inclusivo, portanto ...
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');
... retornará o mesmo conjunto.
Tente brincar com diferentes intervalos de data / hora e tudo se comportará conforme o esperado.
E sem strftime
função?
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
Que tal sem strftime
função e sem milissegundos?
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
Que tal 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
Funciona muito bem.
Finalmente, ao lidar com operações reais dentro de um programa (sem usar o executável sqlite ...)
BTW: Estou usando JDBC (não tenho certeza sobre outros idiomas) ... o driver sqlite-jdbc v3.7.2 da xerial - talvez as revisões mais recentes alterem o comportamento explicado abaixo ... Se você está desenvolvendo no Android, não precisa precisa de um driver jdbc. Todas as operações SQL podem ser enviadas usando o SQLiteOpenHelper
.
JDBC tem diferentes métodos para obter valores de data / hora real a partir de um banco de dados: java.sql.Date
, java.sql.Time
, e java.sql.Timestamp
.
Os métodos relacionados em java.sql.ResultSet
são (obviamente) getDate(..)
, getTime(..)
e, getTimestamp()
respectivamente.
Por exemplo:
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.
Como o SQLite não possui um tipo de dados DATE / TIME / TIMESTAMP real, todos esses três métodos retornam valores como se os objetos fossem inicializados com 0:
new java.sql.Date(0)
new java.sql.Time(0)
new java.sql.Timestamp(0)
Portanto, a pergunta é: como podemos realmente selecionar, inserir ou atualizar objetos Data / Hora / Data e Hora? Não há resposta fácil. Você pode tentar combinações diferentes, mas elas o forçarão a incorporar funções SQLite em todas as instruções SQL. É muito mais fácil definir uma classe de utilitário para transformar texto em objetos Date dentro do seu programa Java. Mas lembre-se sempre de que o SQLite transforma qualquer valor de data em UTC + 0000.
Em resumo, apesar da regra geral de sempre usar o tipo de dados correto ou mesmo números inteiros que denotam tempo Unix (milissegundos desde a época), acho muito mais fácil usar o formato SQLite padrão ( '%Y-%m-%d %H:%M:%f'
ou em Java 'yyyy-MM-dd HH:mm:ss.SSS'
) para complicar todas as suas instruções SQL com Funções SQLite. A abordagem anterior é muito mais fácil de manter.
TODO: Vou verificar os resultados ao usar getDate / getTime / getTimestamp dentro do Android (API15 ou melhor) ... talvez o driver interno seja diferente do sqlite-jdbc ...