Różnica między 2 datami w SQLite


110

Jak uzyskać różnicę w dniach między dwiema datami w SQLite? Próbowałem już czegoś takiego:

SELECT Date('now') - DateCreated FROM Payment

Za każdym razem zwraca 0.

Odpowiedzi:


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

10
Zauważ, że pomimo tego, co nazwa funkcji może sugerować, ma ona większą szczegółowość niż dni. To liczba dni, ale może być ułamkowa.
Lindes

10
Należy pamiętać, że julianday zwraca (ułamkową) liczbę „dni” - tj. Okresów 24-godzinnych od południa czasu UTC w dniu początkowym. Zwykle tego nie potrzebujesz, chyba że mieszkasz 12 godzin na zachód od Greenwich. Np. Jeśli mieszkasz w Londynie, dzisiejszy poranek przypada w ten sam dzień lipca, co wczoraj po południu.
JulianSymes

2
Działa, jeśli jesteś DateCreatedw UTC. Jeśli zamiast tego jest to czas lokalny, musisz dokonać konwersji julianday('now')na czas lokalny. Nie mogłem znaleźć miejsca, w którym można by znaleźć te informacje. Jeśli julianday('now') - julianday(DateCreated)podoba Ci się ten post, który sugeruje z datą przechowywaną w czasie lokalnym, Twoja odpowiedź będzie przesunięta o przesunięcie względem GMT i będzie błędna. Chociaż przechowywanie dat w czasie lokalnym może nie być najlepszą praktyką, może się to zdarzyć w aplikacjach, w których strefy czasowe nie mają znaczenia (z wyjątkiem sytuacji, gdy narzędzie, z którym pracujesz, wymusza je na tobie, jak tutaj).
vapcguy

3
Przy założeniu, że DateCreated jest w czasie lokalnym, jeśli to zrobisz julianday('now') - julianday(DateCreated, 'utc'), aby zrobić oba UTC, nie działa to tak samo jak robienie julianday('now', 'localtime') - julianday(DateCreated). Ta pierwsza nie uwzględnia dni czasu letniego i doda dodatkową godzinę do utworzonych dat w marcu-listopadzie. Ten ostatni faktycznie to wyjaśnia. stackoverflow.com/questions/41007455/ ...
vapcguy

60

Różnica w dniach

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

Różnica w godzinach

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

Różnica w minutach

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

Różnica w sekundach

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

1
dla sqlite w wersji 3.12.0 wyrażenie rzutowania zawiera AS TYPE w nawiasach. np. „Select Cast (5.6 As Integer)”; sqlite.org/lang_expr.html#castexpr Poza tym bardzo przydatne przykłady.
obrabować

Dziękuję @rob. Ktoś wcześniej zaproponował mi taką edycję. Ale kiedy wypróbowałem to w Sqlitebrowser, nie działało. Może to dlatego, że jest starszą wersją. Więc zachowałem to tak, jak jest ...
Sayka

Właśnie użyłem SQLitebrowser i otrzymałem błąd, o którym wspominał rob. Czy mogę zmienić Twój post na nowoczesne brzmienie?
Noumenon

@Noumenon, zaproponuj swoją zmianę. Sprawdzę to w sqlitebrowser tutaj i jeśli zadziała, na pewno zatwierdzę twoją edycję. Dziękuję za Twój czas.
Sayka

2
Ta odpowiedź jest znacznie bardziej wypełniona funkcjami niż zaakceptowana odpowiedź, IMHO.
Marcus Parsons

33

Obie odpowiedzi dostarczają rozwiązań nieco bardziej złożonych, ponieważ muszą być. Powiedzmy, że płatność została utworzona w dniu January 6, 2013. Chcemy poznać różnicę między tą datą a dniem dzisiejszym.

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

Różnica wynosi 34 dni. Możemy użyć julianday('now')dla lepszej przejrzystości. Innymi słowy, nie musimy wstawiać date()ani datetime()funkcjonować jako parametry do julianday() działania.


Nie jestem pewien, ale jeśli to polecenie było w kodzie, a wartość pochodziła z bazy danych 6 stycznia 2013 r., Należy wziąć pod uwagę zastosowany typ danych.
NoChance

23

Dokumentacja SQLite to świetne źródło informacji, a strona DateAndTimeFunctions jest dobra do dodania do zakładek.

Warto również pamiętać, że korzystanie z zapytań za pomocą narzędzia wiersza poleceń sqlite jest dość łatwe:

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

1
Ponieważ ta strona zawiera ranking wyszukiwarek Google, tutaj aktualny link: sqlite.org/lang_datefunc.html
markusN

9

Ta odpowiedź jest trochę rozwlekła, a dokumentacja tego nie powie (ponieważ zakładają, że przechowujesz swoje daty jako daty UTC w bazie danych), ale odpowiedź na to pytanie zależy w dużej mierze od strefy czasowej, w której przechowywane są twoje daty in. Nie Date('now')używasz również julianday()funkcji , ale używasz tej funkcji, aby obliczyć obie daty w odniesieniu do wspólnej daty, a następnie odjąć różnicę między tymi wynikami.

Jeśli twoje daty są przechowywane w UTC:

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

To właśnie zawiera najwyżej sklasyfikowana odpowiedź, a także znajduje się w dokumentacji . To tylko część obrazu i bardzo uproszczona odpowiedź, jeśli o mnie chodzi.

Jeśli Twoje daty są przechowywane w czasie lokalnym, użycie powyższego kodu spowoduje, że odpowiedź będzie NIEPRAWIDŁOWA, biorąc pod uwagę liczbę godzin przesunięcia względem GMT. Jeśli jesteś we wschodnich Stanach Zjednoczonych, tak jak ja, czyli GMT -5, Twój wynik będzie miał 5 godzin. A jeśli spróbujesz DateCreateddostosować się do UTC, ponieważ julianday('now')jest to data GMT:

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

Ma to błąd DateCreatedpolegający na tym, że doda godzinę dla czasu letniego (marzec-listopad). Powiedz, że „teraz” jest w południe w dniu innym niż czas letni, a utworzyłeś coś w czerwcu (podczas czasu letniego) w południe, a wynik będzie obejmował 1 godzinę przerwy zamiast 0 godzin dla części godzinowej. Musiałbyś napisać funkcję w kodzie aplikacji, która wyświetla wynik, aby zmodyfikować wynik i odjąć godzinę od dat czasu letniego. Robiłem to, dopóki nie zdałem sobie sprawy, że istnieje lepsze rozwiązanie tego problemu, który miałem: SQLite vs. Oracle - Obliczanie różnic w datach - godziny

Zamiast tego, jak mi wskazano, w przypadku dat przechowywanych w czasie lokalnym należy dopasować oba do czasu lokalnego:

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

Lub dołącz 'Z'do czasu lokalnego:

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

Oba wydają się rekompensować i nie dodawać dodatkowej godziny do dat czasu letniego i odejmować bezpośrednio - tak, że element utworzony w południe w dniu czasu letniego, sprawdzając w południe w dniu innym niż letni czas letni, nie otrzyma dodatkowej godziny, gdy wykonanie obliczeń.

I chociaż wiem, że większość powie, że nie przechowuj dat w czasie lokalnym w swojej bazie danych i przechowuj je w UTC, abyś tego nie spotkał, cóż, nie każda aplikacja ma odbiorców na całym świecie i nie każdy programista chce aby przejść przez konwersję KAŻDEJ daty w ich systemie na UTC iz powrotem za każdym razem, gdy wykonują GET lub SET w bazie danych i radzą sobie z ustaleniem, czy coś jest lokalne, czy w UTC.


„To tylko część obrazu i bardzo uproszczona odpowiedź, jeśli o mnie chodzi”. Tak, masz rację. Ale moja odpowiedź została udzielona 3 minuty po tym, jak zadał swoje pytanie, a twoje nadeszło dwa lata później. To proste, ale wydawała się mu odpowiadać.
Fred,

1
@ Fred Fair wystarczająco. Ale tak naprawdę zabrał mnie na przejażdżkę, jak opisałem powyżej, więc mi nie pomogło. Chciałem mieć pewność, że każdy, kto zobaczy to w przyszłości, dokładnie wie, co się dzieje, więc nie napotkał tych samych pułapek, co ja - a jeśli tak, to wiedzieliby, jak się z nich wydostać.
vapcguy

@Fred, to bardzo dobre wyjaśnienie i nie jestem pewien, czego się spodziewać? Może opublikuj swoją odpowiedź?
NoChance

Dziękuję za wyjaśnienie. Nie jestem pewien, czy ludzie z SQLite zdecydowali się sprzeciwić standardom, które ludzie przyjęli przez lata i skończyli z niepotrzebnie złożoną implementacją i trudną do przetestowania w krytycznym aspekcie, takim jak data i godzina! Wyobraź sobie liczbę przypadków testowych wymaganych do zweryfikowania, że ​​każda data w aplikacji działa zgodnie z oczekiwaniami ludzi!
NoChance

3

Tylko uwaga do pisania funkcji timeclock. Dla tych, którzy szukają przepracowanych godzin, bardzo prosta zmiana powoduje, że godziny plus minuty są wyświetlane jako procent 60, tak jak chce tego większość firm płacowych.

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

Mimo wszystko
fajne,

3

Jeśli chcesz mieć czas w formacie 00:00: rozwiązałem to w ten sposób:

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

2

Biorąc pod uwagę, że format daty jest następujący: „RRRR-MM-DD GG: MM: SS”, jeśli chcesz znaleźć różnicę między dwiema datami w liczbie miesięcy:

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


2

Po pierwsze, nie jest jasne, jaki jest twój format daty. Jest już odpowiedź angażująca strftime("%s").

Lubię rozwinąć tę odpowiedź.

SQLite ma tylko następujące klasy pamięci: NULL, INTEGER, REAL, TEXT lub BLOB. Dla uproszczenia założę, że daty są PRAWDZIWE i zawierają sekundy od 01.01.1970. Oto przykładowy schemat, dla którego wstawię przykładowe dane z „1 grudnia 2018 r.”:

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

Teraz obliczmy różnicę dat między „1 grudnia 2018 r.” A teraz (gdy to piszę, jest południe 12 grudnia 2018 r.):

Różnica dat w dniach:

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

Różnica dat w godzinach:

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

Różnica dat w minutach:

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

Różnica dat w sekundach:

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

2

Jeśli chcesz różnicy w sekundach

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

0

Jeśli chcesz nagrywać między dniami,

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

0

W moim przypadku muszę obliczyć różnicę w minutach i julianday()nie podaje dokładnej wartości. Zamiast tego używam strftime():

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

Obie daty są konwertowane na unixtime (sekundy), a następnie odejmowane, aby uzyskać wartość w sekundach między dwiema datami. Następnie podziel go przez 60.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.