ความแตกต่างระหว่าง 2 วันที่ใน SQLite


110

ฉันจะได้รับความแตกต่างระหว่างวันที่ 2 วันใน 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
ด้วยสมมติฐานที่ DateCreated อยู่ในเวลาท้องถิ่นถ้าคุณทำjulianday('now') - julianday(DateCreated, 'utc')เพื่อให้ทั้งสอง UTC julianday('now', 'localtime') - julianday(DateCreated)ก็ไม่ได้ทำงานแบบเดียวกับที่ทำ เดิมไม่มีบัญชีสำหรับวัน DST และจะเพิ่มชั่วโมงพิเศษในวันที่สร้างในเดือน มี.ค. - พ.ย. หลังทำบัญชีได้จริง 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 อยู่ภายในวงเล็บ เช่น "Select Cast (5.6 As Integer);" sqlite.org/lang_expr.html#castexprตัวอย่างอื่นที่มีประโยชน์จริงๆ
ปล้น

ขอบคุณ @rob. มีคนเสนอให้แก้ไขฉันแบบนั้นมาก่อน แต่เมื่อฉันลองใน Sqlitebrowser มันไม่ทำงาน อาจจะเป็นเพราะเป็นรุ่นเก่า ก็เลยเก็บเอาไว้เหมือนเดิม ..
Sayka

ฉันเพิ่งใช้ SQLitebrowser และได้รับ error rob ที่กล่าวถึง .. ฉันขอแก้ไขโพสต์ของคุณเป็นถ้อยคำที่ทันสมัย
Noumenon

@ นูเมนนอนโปรดเสนอการแก้ไขของคุณ ฉันจะตรวจสอบใน sqlitebrowser ที่นี่และหากใช้งานได้ก็จะอนุมัติการแก้ไขของคุณอย่างแน่นอน ขอขอบคุณสำหรับเวลาของคุณ.
Sayka

2
คำตอบนี้มีคุณสมบัติครบถ้วนมากกว่าคำตอบที่ยอมรับ IMHO
Marcus Parsons

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

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 กับ 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 นาทีหลังจากที่เขาถามคำถามของเขาเมื่อคุณมาถึงสองปีต่อมา เรียบง่าย แต่ดูเหมือนว่าเธอจะเหมาะกับเขา
Fred

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

ระบุว่ารูปแบบวันที่ของคุณเป็นดังนี้: "YYYY-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


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

วันที่ทั้งสองจะถูกแปลงเป็น unixtime (วินาที) จากนั้นลบออกเพื่อให้ได้ค่าเป็นวินาทีระหว่างวันที่ทั้งสอง ถัดไปหารด้วย 60

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.