SQLite'da 2 tarih arasındaki fark


110

SQLite'da 2 tarih arasındaki gün farkını nasıl elde ederim? Zaten böyle bir şey denedim:

SELECT Date('now') - DateCreated FROM Payment

Her seferinde 0 döndürür.

Yanıtlar:


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

10
Unutmayın ki işlev adı insanı düşündürse de, bu günlerden daha yüksek ayrıntı düzeyine sahiptir. Birkaç gündür, ancak kesirli olabilir.
lindes

10
Julianday'in 'günlerin' (kesirli) sayısını, yani menşe tarihinde UTC öğleden sonra 24 saatlik periyotları döndürdüğünü unutmayın . Greenwich'in 12 saat batısında yaşamadığınız sürece genellikle ihtiyacınız olan şey bu değildir. Örneğin, Londra'da yaşıyorsanız, bu sabah dün öğleden sonra ile aynı jülyanday'da.
JulianSymes

2
Sizin DateCreatedUTC'de ise çalışır . Bunun yerine yerel saat ise, yerel saate çevirmeniz julianday('now')gerekir. Bu bilgiye sahip hiçbir yer bulamadım. Bunu yaparsanız julianday('now') - julianday(DateCreated)bu yayını yerel saatle saklanan bir tarihle anlaşılacağı gibi, cevabın sizin GMT ofset tarafından kapalı olacak ve yanlış olacaktır. Tarihleri ​​yerel saatte depolamak için en iyi uygulama olmasa da, saat dilimlerinin önemli olmadığı uygulamalarda yine de olabilir (burada olduğu gibi, birlikte çalıştığınız aracın onları size zorlaması dışında).
vapcguy

3
DateCreated'in yerel saatte olduğu varsayımıyla, eğer yaparsanız julianday('now') - julianday(DateCreated, 'utc'), her iki UTC'yi de yapmak için, aynı şekilde çalışmaz julianday('now', 'localtime') - julianday(DateCreated). Birincisi, DST günlerini hesaba katmaz ve Mart-Kasım'da oluşturulan tarihlere fazladan bir saat ekler. İkincisi aslında bunu açıklıyor. stackoverflow.com/questions/41007455/…
vapcguy

60

Günlerdeki Fark

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

Saat Farkı

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

Dakika Farkı

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

Saniyedeki Fark

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

1
sqlite sürüm 3.12.0 için, atama ifadesi parantez içinde AS TYPE'a sahiptir. örneğin "Yayın Seç (5.6 Olarak Tamsayı);" sqlite.org/lang_expr.html#castexpr Aksi takdirde gerçekten yararlı örnekler.
soygun

Teşekkür ederim @rob. Daha önce birisi beni böyle düzenlemeyi teklif etti. Ama onu Sqlitebrowser'da denediğimde çalışmıyordu. Belki de eski versiyon olduğu için. Bu yüzden olduğu gibi tuttum ..
Sayka

Az önce SQLitebrowser'ı kullandım ve rob'dan bahsedilen hatayı aldım .. Gönderinizi modern ifadelerle düzenleyebilir miyim?
Noumenon

@Noumenon lütfen düzenlemenizi önerin. Burada sqlitebrowser'da kontrol edeceğim ve eğer çalışırsa, düzenlemenizi kesinlikle onaylayacağım. Zaman ayırdığın için teşekkürler.
Sayka

2
Bu cevap, kabul edilen cevap olan IMHO'dan çok daha fazla özellik dolu.
Marcus Parsons

33

Her iki cevap da olması gerektiği gibi biraz daha karmaşık çözümler sunar. Ödemenin tarihinde oluşturulduğunu varsayalım January 6, 2013. Ve bu tarih ile bugün arasındaki farkı bilmek istiyoruz.

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

Aradaki fark 34 gündür. Daha julianday('now')iyi netlik için kullanabiliriz . Başka bir deyişle, çalışmak için parametre olarak koymamız date()veya datetime()işlev görmemiz gerekmez julianday() .


Emin değilim, ancak bu komut kodda ise ve 6 Ocak 2013 değeri veritabanından geldiyse, kullanılan veri türünü dikkate almak gerekir.
NoChance

23

SQLite belgeleri harika bir referanstır ve DateAndTimeFunctions sayfası yer imlerine eklemek için iyi bir sayfadır.

Ayrıca sqlite komut satırı yardımcı programıyla sorgularla oynamanın oldukça kolay olduğunu hatırlamakta fayda var:

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

1
Bu sayfa bir google arama motoru sıralamasıyla birlikte geldiğinden, şu anki bağlantı: sqlite.org/lang_datefunc.html
markusN

9

Bu cevap biraz uzun solukludur ve belgeler size bunu söylemeyecektir (çünkü tarihlerinizi veritabanında UTC tarihleri ​​olarak sakladığınızı varsayarlar), ancak bu sorunun cevabı büyük ölçüde tarihlerinizin depolandığı saat dilimine bağlıdır. Ayrıca kullanmazsınız Date('now'), ancakjulianday() , her iki tarihi de ortak bir tarihe göre hesaplamak işlevi , ardından bu sonuçların birbirinden farkını çıkarırsınız.

Tarihleriniz UTC olarak saklanıyorsa:

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

Bu, en üst sıradaki yanıtın sahip olduğu şeydir ve ayrıca belgelerde bulunur . Bana sorarsan, resmin sadece bir parçası ve çok basit bir cevap.

Tarihleriniz yerel saatte saklanıyorsa, yukarıdaki kodu kullanmak cevabınızı GMT farkınızın kaç saat kadar YANLIŞ yapacaktır . Eğer benim gibi Doğu ABD'deyseniz, GMT -5, sonucunuz üzerine 5 saat eklenecektir. Ve eğer DateCreatedUTC'ye uymaya çalışırsanız, çünkü julianday('now')GMT tarihine aykırıdır:

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

Bu, DateCreatedYaz Saati Uygulaması (Mart-Kasım) sırasındaki bir saat için bir saat ekleyeceği bir hataya sahiptir . DST olmayan bir günde "şimdi" öğesinin öğlen olduğunu ve Haziran ayında (DST sırasında) öğle vakti bir şey oluşturduğunuzu, sonucunuzun saatler bölümü için 0 saat yerine 1 saat ara vereceğini söyleyin. Sonucu değiştirmek ve DST tarihlerinden bir saat çıkarmak için uygulamanızın koduna sonucu görüntüleyen bir işlev yazmanız gerekir. Bunu, yaşadığım soruna daha iyi bir çözüm olduğunu anlayana kadar yaptım: SQLite ve Oracle - Tarih farklılıklarını hesaplama - saat

Bunun yerine, bana belirtildiği gibi, yerel saatte depolanan tarihler için her ikisini de yerel saatle eşleştirin:

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

Veya 'Z'yerel saate ekleyin :

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

Bunların her ikisi de telafi ediyor gibi görünüyor ve DST tarihleri ​​için fazladan saat eklemiyor ve doğrudan çıkarma yapıyor - böylece DST günü öğle vakti, DST olmayan bir günde öğlen check-in yaparken, ekstra bir saat almayacak. hesaplama yapmak.

Ve çoğunun tarihleri ​​veritabanınızda yerel saatte saklamayın ve bunları UTC'de saklamanızı söyleyeceğimi fark etsem de, bununla karşılaşmazsınız, her uygulamanın dünya çapında bir izleyici kitlesi yoktur ve her programcı istemez. sistemlerindeki HER tarihin UTC'ye dönüştürülmesinden geçmek ve veritabanında her GET veya SET yaptıklarında tekrar geri gitmek ve bir şeyin yerel mi yoksa UTC'de mi olduğunu bulmakla uğraşmak.


"Bana sorarsan, resmin sadece bir parçası ve çok basit bir cevap." Evet, haklısın. Ama cevabım, sorusunu sorduktan 3 dakika sonra, sizinki iki yıl sonra geldiğinde verildi. Basit ama ona yakışıyor gibiydi.
Fred

1
@Fred Fair yeterince. Ama aslında yukarıda anlattığım gibi beni bir gezintiye çıkardı ve bu yüzden bana yardımcı olmadı. Gelecekte bunu gören herkesin neler olup bittiğini tam olarak bildiğinden emin olmak istedim, bu yüzden benim yaptığım tuzaklara düşmediler - ya da yapsalar, onlardan nasıl kurtulacaklarını bileceklerdi.
vapcguy

@Fred, bu çok iyi bir açıklama ve ne beklediğinden emin değilim? Belki cevabını gönder?
NoChance

Açıklaman için teşekkürler. SQLite çalışanlarının, insanların yıllar içinde kabul ettiği standartlara aykırı davranmaya karar verdiklerinden ve gereksiz derecede karmaşık bir uygulama ile sonuçlandığından ve tarih ve saat gibi kritik bir açıdan test edilmesi zor olduğundan emin değilim! İnsanların beklediği gibi uygulamadaki her tarihi doğrulamak için gereken test senaryolarının sayısını hayal edin!
NoChance

3

Timeclock işlevlerini yazmak için sadece bir not. Çalışılan saatleri arayanlar için, bunun çok basit bir değişikliği, saatleri ve dakikaları çoğu bordro şirketinin istediği gibi 60'ın bir yüzdesi olarak gösterir.

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

Yine de güzel küçük bir sorgu :)
vapcguy

3

00:00 biçiminde saat istiyorsanız: Bunu şu şekilde çözdüm:

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

2

Tarih biçiminizin aşağıdaki gibi olduğunu varsayarsak: "YYYY-AA-GG SS: DD: SS", iki tarih arasındaki farkı ay sayısı olarak bulmanız gerekiyorsa:

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


2

İlk olarak, tarih formatınızın ne olduğu belli değil. Zaten içeren bir cevap var strftime("%s").

Bu cevabı genişletmeyi seviyorum.

SQLite yalnızca şu depolama sınıflarına sahiptir: NULL, INTEGER, REAL, TEXT veya BLOB. İşleri basitleştirmek için, tarihlerin GERÇEK olduğunu ve 1970-01-01'den bu yana geçen saniyeleri içerdiğini varsayacağım. İşte "1 Aralık 2018" örnek verilerine koyacağım örnek bir şema:

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

Şimdi "1 Aralık 2018" ile şimdiki tarih arasındaki tarih farkını bulalım (bunu yazarken 12 Aralık 2018 öğlen):

Gün cinsinden tarih farkı:

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

Saat cinsinden tarih farkı:

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

Dakika cinsinden tarih farkı:

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

Saniye cinsinden tarih farkı:

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

2

Saniyeler içinde fark istiyorsanız

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

0

Günler arasında kayıt istiyorsanız,

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

0

Benim durumumda farkı dakika cinsinden hesaplamam gerekiyor ve julianday()doğru bir değer vermiyor. Bunun yerine kullanıyorum strftime():

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

Her iki tarih de unixtime'a (saniye) dönüştürülür, ardından iki tarih arasında saniye cinsinden değer elde etmek için çıkarılır. Ardından, 60'a bölün.

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.