Разница между двумя датами в SQLite


110

Как узнать разницу в днях между двумя датами в SQLite? Я уже пробовал что-то подобное:

SELECT Date('now') - DateCreated FROM Payment

Он каждый раз возвращает 0.

Ответы:


123
 SELECT julianday('now') - julianday(DateCreated) FROM Payment;

10
Обратите внимание, что, несмотря на то, что можно подумать по названию функции, у этой функции более высокая степень детализации, чем у дней. Это количество дней, но может быть дробным.
Lindes

10
Имейте в виду, что julianday возвращает (дробное) количество «дней», то есть 24-часовых периодов, начиная с полудня по всемирному координированному времени в исходную дату. Обычно это не то, что вам нужно, если только вы не живете в 12 часах езды к западу от Гринвича. Например, если вы живете в Лондоне, то сегодня утром тот же июль, что и вчера днем.
JulianSymes,

2
Это работает, если вы DateCreatedнаходитесь в UTC. Если вместо этого используется местное время, вам необходимо преобразовать его julianday('now')в местное время. Я не мог найти нигде, где была бы эта информация. Если вам julianday('now') - julianday(DateCreated)нравится, что этот пост предлагает дату, хранящуюся в местном времени, ваш ответ будет отклонен от вашего смещения от GMT и будет неправильным. Хотя, возможно, это не лучшая практика для хранения дат по местному времени, это все же может происходить в приложениях, где часовые пояса не имеют значения (кроме случаев, когда инструмент, с которым вы работаете, навязывает их вам, как здесь).
vapcguy

3
При условии, что DateCreated находится в местном времени, если вы это сделаете julianday('now') - julianday(DateCreated, 'utc'), чтобы сделать оба UTC, это не будет работать так же, как это julianday('now', 'localtime') - julianday(DateCreated). Первый не учитывает дни летнего времени и добавит дополнительный час к созданным датам в марте-ноябре. Последнее действительно объясняет это. stackoverflow.com/questions/41007455/…
vapcguy

60

Разница в днях

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) As Integer)

Разница в часах

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) * 24 As Integer)

Разница в минутах

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) * 24 * 60 As Integer)

Разница в секундах

Select Cast ((
    JulianDay(ToDate) - JulianDay(FromDate)
) * 24 * 60 * 60 As Integer)

1
для sqlite версии 3.12.0 выражение приведения содержит AS TYPE в скобках. например, «Выбрать приведение (5.6 как целое число)»; sqlite.org/lang_expr.html#castexpr В остальном действительно полезные примеры.
rob

Спасибо @rob. Кто-то предлагал раньше так редактировать меня. Но когда я попробовал это в Sqlitebrowser, он не работал. Может быть, это из-за более старой версии. Так что я оставил это как есть ..
Sayka

Я только что использовал SQLitebrowser и получил упомянутую ошибку rob .. Могу ли я отредактировать ваш пост в современной формулировке?
Noumenon

@Noumenon, пожалуйста, предложите свое редактирование. Я проверю это в sqlitebrowser здесь, и, если сработает, обязательно одобряю ваше изменение. Спасибо за уделенное время.
Sayka

2
ИМХО, в этом ответе гораздо больше возможностей, чем в принятом.
Маркус Парсонс

33

Оба ответа предлагают решения немного более сложные, как и должно быть. Допустим, платеж был создан January 6, 2013. И мы хотим знать разницу между этой датой и сегодняшним днем.

sqlite> SELECT julianday() - julianday('2013-01-06');
34.7978485878557 

Разница составляет 34 дня. Мы можем использовать julianday('now')для большей ясности. Другими словами, нам не нужно указывать date()или datetime()функции в качестве параметров для julianday() работы.


Я не уверен, но если эта команда была в коде, а значение 6 января 2013 г. было получено из базы данных, необходимо учитывать используемый тип данных.
NoChance

23

Документация по SQLite - отличный справочник, а страницу DateAndTimeFunctions можно добавить в закладки.

Также полезно помнить, что довольно легко играть с запросами с помощью утилиты командной строки sqlite:

sqlite> select julianday(datetime('now'));
2454788.09219907
sqlite> select datetime(julianday(datetime('now')));
2008-11-17 14:13:55

1
Поскольку эта страница имеет рейтинг поисковой системы Google, вот текущая ссылка: sqlite.org/lang_datefunc.html
markusN 07

9

Этот ответ немного длинен, и документация не скажет вам этого (потому что они предполагают, что вы храните свои даты как даты в формате UTC в базе данных), но ответ на этот вопрос во многом зависит от часового пояса, в котором хранятся ваши даты in. Вы также не используете Date('now'), но используете эту julianday()функцию, чтобы вычислить обе даты относительно общей даты, а затем вычесть разницу этих результатов друг с другом.

Если ваши даты хранятся в формате UTC:

SELECT julianday('now') - julianday(DateCreated) FROM Payment;

Это то, что есть в верхнем рейтинге ответа, а также в документации . Если вы спросите меня, это только часть картины и очень упрощенный ответ.

Если ваши даты хранятся в местном времени, использование приведенного выше кода сделает ваш ответ НЕПРАВИЛЬНЫМ по количеству часов, в которых указано смещение по Гринвичу. Если вы, как и я, находитесь в восточной части США, то есть по Гринвичу -5, к вашему результату будут добавлены 5 часов. И если вы попытаетесь DateCreatedсогласоваться с UTC, потому что julianday('now')это не соответствует дате GMT:

SELECT julianday('now') - julianday(DateCreated, 'utc') FROM Payment;

У этого есть ошибка, из-за которой он добавляет час для DateCreatedлетнего времени (март-ноябрь). Предположим, что «сейчас» - это полдень в день, не относящийся к летнему времени, и вы создали что-то еще в июне (во время летнего времени) в полдень, ваш результат даст интервал в 1 час вместо 0 часов для части часов. Вам нужно будет написать функцию в коде вашего приложения, которая отображает результат, чтобы изменить результат и вычесть час из дат DST. Я делал это, пока не понял, что есть лучшее решение той проблемы, с которой я столкнулся: SQLite против Oracle - Расчет разницы в датах - часы

Вместо этого, как мне было указано, для дат, хранящихся в местном времени, сопоставьте оба с местным временем:

SELECT julianday('now', 'localtime') - julianday(DateCreated) FROM Payment;

Или добавьте 'Z'к местному времени:

julianday(datetime('now', 'localtime')||'Z') - julianday(CREATED_DATE||'Z')

Оба из них, кажется, компенсируют и не добавляют дополнительный час для дат DST и выполняют прямое вычитание - так что элемент, созданный в полдень в день DST, при проверке в полдень в день без DST, не получит дополнительный час, когда выполнение расчета.

И хотя я понимаю, что большинство скажет, что не храните даты в локальном времени в своей базе данных и храните их в UTC, чтобы вы не столкнулись с этим, ну, не каждое приложение имеет всемирную аудиторию, и не каждый программист хочет чтобы выполнять преобразование КАЖДОЙ даты в своей системе в UTC и обратно каждый раз, когда они выполняют GET или SET в базе данных и пытаются выяснить, является ли что-то локальным или в UTC.


«Это только часть картины и очень упрощенный ответ, если вы спросите меня». Да, ты прав. Но мой ответ был дан через 3 минуты после того, как он задал свой вопрос, а ваш - спустя два года. Упрощенно, но она, похоже, ему шла.
Фред

1
@ Фред Достаточно справедливо. Но на самом деле это привело меня к прогулке, как я описал выше, и поэтому мне это не помогло. Я хотел быть уверенным, что все, кто увидит это в будущем, точно знают, что происходит, чтобы они не попали в те же ловушки, что и я, или, если они это сделают, они будут знать, как из них выбраться.
vapcguy

@ Фред, это очень хорошее объяснение, и я не уверен, чего ожидать? Может свой ответ выложить?
NoChance

Спасибо за ваше объяснение. Я не уверен, что люди, занимающиеся SQLite, решили пойти против стандартов, которые люди привыкли принимать за долгие годы, и в итоге получили излишне сложную реализацию, которую трудно тестировать в критических аспектах, таких как дата и время! Представьте себе количество тестовых примеров, необходимых для проверки того, что каждая дата в приложении работает так, как этого ожидают люди!
NoChance

3

Просто примечание для написания функций таймера. Для тех, кто ищет количество отработанных часов, очень простое изменение этого параметра позволяет отображать часы плюс минуты в процентах от 60, как того требует большинство компаний по начислению заработной платы.

CAST ((julianday(clockOUT) - julianday(clockIN)) * 24 AS REAL) AS HoursWorked

Clock In            Clock Out           HoursWorked
2016-08-07 11:56    2016-08-07 18:46    6.83333332836628

Тем не менее, аккуратный маленький вопрос :)
vapcguy

3

Если вам нужно время в формате 00:00: я решил это так:

select strftime('%H:%M',CAST ((julianday(FinishTime) - julianday(StartTime)) AS REAL),'12:00') from something

2

Учитывая, что ваш формат даты следующий: «ГГГГ-ММ-ДД ЧЧ: ММ: СС», если вам нужно найти разницу между двумя датами в количестве месяцев:

(strftime('%m', date1) + 12*strftime('%Y', date1)) - (strftime('%m', date2) + 12*strftime('%Y', date2))


2

Во-первых, непонятно, какой у вас формат даты. Ответ уже есть strftime("%s").

Мне нравится расширять этот ответ.

SQLite имеет только следующие классы хранения: NULL, INTEGER, REAL, TEXT или BLOB. Чтобы упростить ситуацию, я предполагаю, что даты НАСТОЯЩИЕ и содержат секунды с 01.01.1970. Вот образец схемы, для которой я вставлю образец данных от «1 декабря 2018 года»:

CREATE TABLE Payment (DateCreated REAL);
INSERT INTO Payment VALUES (strftime("%s", "2018-12-01"));

Теперь давайте определим разницу в датах между «1 декабря 2018 года» и сейчас (когда я пишу это, это полдень 12 декабря 2018 года):

Разница дат в днях:

SELECT (strftime("%s", "now") - DateCreated) / 86400.0 FROM Payment;
-- Output: 11.066875

Разница дат в часах:

SELECT (strftime("%s", "now") - DateCreated) / 3600.0 FROM Payment;
-- Output: 265.606388888889

Разница дат в минутах:

SELECT (strftime("%s", "now") - DateCreated) / 60.0 FROM Payment;
-- Output: 15936.4833333333

Разница дат в секундах:

SELECT (strftime("%s", "now") - DateCreated) FROM Payment;
-- Output: 956195.0

2

Если вам нужна разница в секундах

SELECT strftime('%s', '2019-12-02 12:32:53') - strftime('%s', '2019-12-02 11:32:53')


0

В моем случае я должен рассчитывать разницу в минутах и julianday()не даю точного значения. Вместо этого я использую strftime():

SELECT (strftime('%s', [UserEnd]) - strftime('%s', [UserStart])) / 60

Обе даты преобразуются в unixtime (секунды), затем вычитаются, чтобы получить значение в секундах между двумя датами. Затем разделите его на 60.

https://www.sqlite.org/cvstrac/wiki?p=DateAndTimeFunctions

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.