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 ...)
BTW: Я використовую 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)
Отже, питання полягає в тому, як ми можемо насправді вибирати, вставляти або оновлювати об’єкти Дата / Час / Часові позначки? Немає простої відповіді. Ви можете спробувати різні комбінації, але вони змусять вас вставляти функції 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 ...