SQLite может использовать текстовые, реальные или целочисленные типы данных для хранения дат. Более того, всякий раз, когда вы выполняете запрос, результаты отображаются в формате %Y-%m-%d %H:%M:%S
.
Теперь, если вы вставляете / обновляете значения даты / времени, используя функции даты / времени SQLite, вы также можете хранить миллисекунды. Если это так, результаты отображаются в формате %Y-%m-%d %H:%M:%f
. Например:
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
Теперь выполним несколько запросов, чтобы проверить, действительно ли мы можем сравнивать время:
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
Вы можете проверить то же самое , SELECT
используя col2
и col3
и вы получите те же результаты. Как видите, второй ряд (126 миллисекунд) не возвращается.
Обратите внимание, что BETWEEN
это включено, поэтому ...
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');
... вернет тот же набор.
Попробуйте поиграть с разными диапазонами даты и времени, и все будет работать так, как ожидается.
Как насчет без strftime
функции?
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
Как насчет без strftime
функции и без миллисекунд?
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
Как насчет 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
Работает просто отлично.
Наконец, когда речь идет о реальных операциях внутри программы (без использования исполняемого файла sqlite ...)
Кстати: я использую JDBC (не уверен насчет других языков) ... драйвер sqlite-jdbc v3.7.2 от xerial - возможно, более новые версии меняют поведение, описанное ниже ... Если вы разрабатываете в Android, вы не делаете нужен jdbc-драйвер. Все операции SQL могут быть отправлены с использованием SQLiteOpenHelper
.
JDBC имеет различные методы , чтобы получить фактические значения даты / времени из базы данных: java.sql.Date
, java.sql.Time
, и java.sql.Timestamp
.
Соответствующие методы в java.sql.ResultSet
(очевидно) getDate(..)
, getTime(..)
и getTimestamp()
соответственно.
Например:
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.
Поскольку SQLite не имеет фактического типа данных DATE / TIME / TIMESTAMP, все эти 3 метода возвращают значения, как если бы объекты были инициализированы с 0:
new java.sql.Date(0)
new java.sql.Time(0)
new java.sql.Timestamp(0)
Итак, вопрос заключается в следующем: как мы можем на самом деле выбирать, вставлять или обновлять объекты Date / Time / Timestamp? Там нет простого ответа. Вы можете попробовать разные комбинации, но они заставят вас встроить функции SQLite во все операторы SQL. Намного проще определить служебный класс для преобразования текста в объекты Date внутри вашей Java-программы. Но всегда помните, что SQLite преобразует любое значение даты в UTC + 0000.
Таким образом, несмотря на общее правило всегда использовать правильный тип данных или даже целые числа, обозначающие время Unix (миллисекунды с начала эпохи), я считаю, что гораздо проще использовать формат SQLite по умолчанию ( '%Y-%m-%d %H:%M:%f'
или в Java 'yyyy-MM-dd HH:mm:ss.SSS'
), а не усложнять все ваши операторы SQL с помощью SQLite функции. Первый подход гораздо проще поддерживать.
TODO: Я проверю результаты при использовании getDate / getTime / getTimestamp внутри Android (API15 или лучше) ... возможно, внутренний драйвер отличается от sqlite-jdbc ...