Різниця між двома датами в SQLite


110

Як я можу отримати різницю в днях між двома датами в SQLite? Я вже спробував щось подібне:

SELECT Date('now') - DateCreated FROM Payment

Він щоразу повертає 0.

Відповіді:


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

10
Зауважте, що незважаючи на те, що назва функції може змусити задуматися, ця деталізація відрізняється більшою кількістю днів. Це число днів, але може бути дробовим.
lindes

10
Майте на увазі, що julianday повертає (дробову) кількість "днів" - тобто періоди 24 години, починаючи з полудня UTC за датою початку. Зазвичай це не те, що потрібно, якщо тільки ти не живеш 12 годин на захід від Грінвіча. Наприклад, якщо ви живете в Лондоні, сьогодні вранці в той же липень, що і вчора вдень.
JulianSymes

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

3
З припущенням, що DateCreate знаходиться в місцевому часі, якщо ви зробите 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. Хтось раніше пропонував мене редагувати так. Але коли я спробував це в Sqlitebrowser, він не працював. Можливо, це тому, що вона є старшою версією. Тож я зберегла це так, як є ..
Сайка

Я щойно використав SQLitebrowser і згадав про помилку, яка була відзначена. Чи можу я відредагувати вашу публікацію в сучасній редакції?
Номенон

@Noumenon, будь ласка, запропонуйте свої зміни. Я перевірю це в sqlitebrowser тут, і якщо він працює, обов'язково схвалюю вашу редакцію. Спасибі за ваш час.
Сайка

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
Оскільки ця сторінка оснащена
markusN

9

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

Якщо ваші дати зберігаються в UTC:

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

Про це є відповідь вищого рейтингу, а також є в документації . Це лише частина малюнка і дуже спрощена відповідь, якщо ви запитаєте мене.

Якщо ваші дати зберігаються за місцевим часом, використовуючи вищевказаний код, ваша відповідь НЕПОЗНАЧАЄ за кількість годин, за якими ваш компенсатор GMT зміщений. Якщо ви перебуваєте на сході США, як я, що є GMT -5, ваш результат додасть до нього 5 годин. І якщо ви спробуєте зробити DateCreatedвідповідність UTC, оскільки це julianday('now')суперечить даті GMT:

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

Це помилка, де вона додасть годину за DateCreated що знаходиться в літній час (березень-листопад). Скажіть, що "зараз" - це опівдні в не-DST день, і ви створили щось ще в червні (під час DST) опівдні, ваш результат дасть 1 годину, замість 0 годин, на частину годин. Вам потрібно буде записати функцію в код програми, яка відображає результат, щоб змінити результат і відняти годину від дати DST. Я робив це, доки не зрозумів, що є кращий варіант вирішення цієї проблеми: SQLite vs. 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
@Fred Справедливо. Але це насправді взяло мене на прогулянку, як я описав вище, і тому мені не допомогло. Я хотів бути впевненим, що хтось бачить це в майбутньому, точно знав, що відбувається, щоб вони не потрапили на ті самі підводні камені, що і я - або, якби це було, вони знали б, як з них вийти.
vapcguy

@Fred, це дуже хороше пояснення, і я не впевнений, що чекати? Можливо, опублікуйте свою відповідь?
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


3

Якщо ви хочете часу у форматі 00:00: я вирішив так:

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

2

Враховуючи, що ваш формат дати наступний: "РРРР-MM-DD HH: MM: SS", якщо вам потрібно знайти різницю між двома датами в кількості місяців:

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


2

По-перше, незрозуміло, який саме формат вашої дати. Тут вже є відповідь із участюstrftime("%s") .

Мені подобається розширювати цю відповідь.

SQLite має лише такі класи зберігання: NULL, INTEGER, REAL, TEXT або BLOB. Для спрощення речей, я припускаю, що дати справжні, що містять секунди з 1970-01-01. Ось зразкова схема, для якої я поміщу у вибіркові дані "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

Якщо ви хочете записувати між днями,

select count(col_Name) from dataset where cast(julianday("now")- julianday(_Last_updated) as int)<=0;

0

У моєму випадку я повинен обчислити різницю в хвилинах і julianday()не дає точного значення. Натомість я використовую strftime():

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

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.