Sự khác biệt giữa 2 ngày trong SQLite


110

Làm cách nào để nhận được sự khác biệt về số ngày giữa 2 ngày trong SQLite? Tôi đã thử một cái gì đó như thế này:

SELECT Date('now') - DateCreated FROM Payment

Nó trả về 0 mọi lúc.

Câu trả lời:


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

10
Lưu ý rằng bất chấp tên hàm có thể khiến người ta nghĩ gì, điều này có mức độ chi tiết cao hơn so với ngày. Đó là một số ngày, nhưng có thể là một phần nhỏ.
lindes

10
Hãy nhớ rằng julianday trả về số (phân số) của 'ngày' - tức là khoảng thời gian 24 giờ, kể từ trưa UTC vào ngày gốc. Đó thường không phải là thứ bạn cần, trừ khi bạn sống cách Greenwich 12 giờ về phía tây. Ví dụ: nếu bạn sống ở Luân Đôn, sáng nay cùng ngày với chiều hôm qua.
JulianSymes

2
Nó hoạt động nếu bạn DateCreatedđang ở UTC. Thay vào đó, nếu đó là giờ địa phương, bạn phải chuyển đổi julianday('now')sang giờ địa phương. Tôi không thể tìm thấy bất cứ nơi nào có thông tin này. Nếu bạn julianday('now') - julianday(DateCreated)thích bài đăng này đề xuất với ngày được lưu trữ theo giờ địa phương, câu trả lời của bạn sẽ bị lệch so với thời gian bù giờ so với GMT và sẽ sai. Mặc dù có thể không phải là phương pháp hay nhất để lưu trữ ngày tháng theo giờ địa phương, nhưng nó vẫn có thể xảy ra trong các ứng dụng có múi giờ không quan trọng (ngoại trừ khi công cụ bạn đang làm việc buộc chúng vào bạn, như ở đây).
vapcguy

3
Với giả định DateCreate là theo giờ địa phương, nếu bạn làm vậy julianday('now') - julianday(DateCreated, 'utc'), để tạo cả hai UTC, nó không hoạt động giống như cách làm julianday('now', 'localtime') - julianday(DateCreated). Trước đây không tính đến ngày DST và sẽ thêm một giờ vào các ngày đã tạo trong tháng 3-tháng 11. Điều sau thực sự giải thích cho nó. stackoverflow.com/questions/41007455/…
vapcguy

60

Sự khác biệt trong ngày

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

Sự khác biệt trong giờ

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

Sự khác biệt trong vài phút

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

Sự khác biệt trong vài giây

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

1
đối với phiên bản sqlite 3.12.0, biểu thức ép kiểu có LOẠI AS bên trong dấu ngoặc. ví dụ: "Chọn Truyền (5.6 Là Số nguyên);" sqlite.org/lang_expr.html#castexpr Nếu không thì các ví dụ thực sự hữu ích.
cướp

Cảm ơn bạn @rob. Trước đây đã có người đề xuất chỉnh sửa tôi như vậy. Nhưng khi tôi thử nó trong Sqlitebrowser, nó không hoạt động. Có lẽ vì là phiên bản cũ hơn. Vì vậy, tôi giữ nó vì nó là ..
Sayka

Tôi vừa sử dụng SQLitebrowser và đã đề cập đến lỗi cướp được đề cập .. Tôi có thể chỉnh sửa bài đăng của bạn theo cách diễn đạt hiện đại không?
Noumenon

@Noumenon vui lòng đề xuất chỉnh sửa của bạn. Tôi sẽ kiểm tra nó trong sqlitebrowser tại đây và nếu hoạt động, chắc chắn sẽ chấp thuận chỉnh sửa của bạn. Cảm ơn bạn đã dành thời gian.
Sayka

2
Câu trả lời này có nhiều tính năng hơn câu trả lời được chấp nhận, IMHO.
Marcus Parsons

33

Cả hai câu trả lời đều cung cấp các giải pháp phức tạp hơn một chút, khi chúng cần phải như vậy. Giả sử thanh toán đã được tạo vào January 6, 2013. Và chúng tôi muốn biết sự khác biệt giữa ngày này và ngày hôm nay.

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

Sự khác biệt là 34 ngày. Chúng tôi có thể sử dụng julianday('now')để rõ ràng hơn. Nói cách khác, chúng ta không cần đặt date()hoặc datetime()hàm như các tham số để julianday() hoạt động.


Tôi không chắc chắn, nhưng nếu lệnh này nằm trong mã và giá trị ngày 6 tháng 1 năm 2013 đến từ cơ sở dữ liệu, thì người ta cần xem xét kiểu dữ liệu được sử dụng.
NoChance

23

Tài liệu SQLite là một tài liệu tham khảo tuyệt vời và trang DateAndTimeFunctions là một trang tốt để đánh dấu.

Cũng hữu ích khi nhớ rằng khá dễ dàng để thực hiện các truy vấn bằng tiện ích dòng lệnh sqlite:

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

1
Vì trang này đi kèm với xếp hạng công cụ tìm kiếm của google, đây là liên kết hiện tại: sqlite.org/lang_datefunc.html
markusN Ngày

9

Câu trả lời này hơi dài dòng và tài liệu sẽ không cho bạn biết điều này (vì họ cho rằng bạn đang lưu trữ ngày của mình dưới dạng ngày UTC trong cơ sở dữ liệu), nhưng câu trả lời cho câu hỏi này phụ thuộc phần lớn vào múi giờ mà ngày của bạn được lưu trữ trong. Bạn cũng không sử dụng Date('now'), nhưng sử dụng julianday()hàm, để tính toán cả hai ngày ngược lại với một ngày chung, sau đó trừ chênh lệch của các kết quả đó cho nhau.

Nếu ngày của bạn được lưu trữ theo giờ UTC:

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

Đây là câu trả lời được xếp hạng hàng đầu và cũng có trong tài liệu . Nó chỉ là một phần của bức tranh, và một câu trả lời rất đơn giản, nếu bạn hỏi tôi.

Nếu ngày của bạn được lưu theo giờ địa phương, việc sử dụng mã trên sẽ khiến câu trả lời của bạn SAI theo số giờ bù giờ GMT của bạn. Nếu bạn ở miền Đông Hoa Kỳ như tôi, giờ là GMT -5, kết quả của bạn sẽ có thêm 5 giờ nữa. Và nếu bạn cố gắng DateCreatedtuân theo UTC vì julianday('now')đi ngược lại ngày GMT:

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

Điều này có một lỗi trong đó nó sẽ thêm một giờ cho một giờ DateCreatedtrong Giờ tiết kiệm ánh sáng ban ngày (tháng 3 đến tháng 11). Giả sử "bây giờ" là vào buổi trưa của một ngày không phải DST và bạn đã tạo thứ gì đó hồi tháng 6 (trong DST) vào buổi trưa, kết quả của bạn sẽ cách nhau 1 giờ, thay vì 0 giờ, cho phần giờ. Bạn phải viết một hàm trong mã ứng dụng của bạn đang hiển thị kết quả để sửa đổi kết quả và trừ đi một giờ cho các ngày DST. Tôi đã làm điều đó, cho đến khi tôi nhận ra có một giải pháp tốt hơn cho vấn đề mà tôi đang gặp phải: SQLite so với Oracle - Tính toán chênh lệch ngày - giờ

Thay vào đó, như tôi đã chỉ ra, đối với các ngày được lưu trữ theo giờ địa phương, hãy làm cho cả hai khớp với giờ địa phương:

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

Hoặc thêm 'Z'vào giờ địa phương:

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

Cả hai điều này dường như bù trừ và không cộng thêm giờ cho các ngày DST và thực hiện phép trừ thẳng - do đó, mục đó được tạo vào buổi trưa của ngày DST, khi kiểm tra vào buổi trưa của ngày không phải DST, sẽ không nhận được thêm một giờ khi thực hiện phép tính.

Và mặc dù tôi nhận ra hầu hết sẽ nói rằng không lưu trữ ngày tháng theo giờ địa phương trong cơ sở dữ liệu của bạn và lưu trữ chúng theo giờ UTC để bạn không gặp phải vấn đề này, nhưng không phải mọi ứng dụng đều có đối tượng trên toàn thế giới và không phải lập trình viên nào cũng muốn để chuyển đổi MỖI ngày trong hệ thống của họ sang UTC và quay lại mỗi lần họ thực hiện GET hoặc SET trong cơ sở dữ liệu và xử lý xem có thứ gì đó là cục bộ hay ở UTC hay không.


"Nó chỉ là một phần của bức tranh, và một câu trả lời rất đơn giản, nếu bạn hỏi tôi." Uh, đúng vậy. Nhưng câu trả lời của tôi đã được đưa ra 3 phút sau khi anh ấy hỏi câu hỏi của mình khi bạn đến sau hơn hai năm. Đơn giản nhưng cô ấy có vẻ hợp với anh.
Fred

1
@Fred Đủ công bằng. Nhưng nó thực sự đưa tôi đi một chuyến, như tôi đã mô tả ở trên, và vì vậy không giúp được gì cho tôi. Tôi muốn chắc chắn rằng bất cứ ai nhìn thấy điều này trong tương lai đều biết chính xác chuyện gì đang xảy ra để họ không gặp phải những cạm bẫy giống như tôi đã làm - hoặc, nếu có, họ sẽ biết cách thoát ra khỏi chúng.
vapcguy

@Fred, đây là một lời giải thích rất tốt và tôi không chắc những gì mong đợi? Có thể đăng câu trả lời của bạn?
NoChance

Cảm ơn vì lời giải thích của bạn. Tôi không chắc những người sử dụng SQLite đã quyết định đi ngược lại các tiêu chuẩn mà mọi người đã chấp nhận trong nhiều năm và kết thúc bằng một triển khai phức tạp không cần thiết và khó kiểm tra ở một khía cạnh quan trọng như ngày và giờ! Hãy tưởng tượng số lượng trường hợp thử nghiệm cần thiết để xác minh mỗi ngày trong ứng dụng hoạt động như con người mong đợi!
NoChance

3

Chỉ là một lưu ý để viết các chức năng đồng hồ thời gian. Đối với những người đang tìm kiếm giờ làm việc, một sự thay đổi rất đơn giản là số giờ cộng với số phút được hiển thị theo tỷ lệ 60 như hầu hết các công ty trả lương muốn.

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

Tuy nhiên, truy vấn nhỏ gọn gàng :)
vapcguy

3

Nếu bạn muốn thời gian ở định dạng 00:00: Tôi đã giải quyết nó như vậy:

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

2

Giả sử rằng định dạng ngày của bạn như sau: "YYYY-MM-DD HH: MM: SS", nếu bạn cần tìm sự khác biệt giữa hai ngày theo số tháng:

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


2

Thứ nhất, không rõ định dạng ngày tháng của bạn là gì. Đã có một câu trả lời liên quan strftime("%s").

Tôi muốn mở rộng câu trả lời đó.

SQLite chỉ có các lớp lưu trữ sau: NULL, INTEGER, REAL, TEXT hoặc BLOB. Để đơn giản hóa mọi thứ, tôi sẽ giả sử ngày tháng là THỰC có chứa giây kể từ 1970-01-01. Đây là lược đồ mẫu mà tôi sẽ đưa vào dữ liệu mẫu của "ngày 1 tháng 12 năm 2018":

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

Bây giờ chúng ta hãy tìm ra sự khác biệt về ngày giữa "ngày 1 tháng 12 năm 2018" và bây giờ (khi tôi viết điều này, đó là giữa ngày 12 tháng 12 năm 2018):

Ngày chênh lệch trong ngày:

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

Ngày chênh lệch theo giờ:

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

Ngày chênh lệch tính bằng phút:

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

Chênh lệch ngày tính bằng giây:

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

2

Nếu bạn muốn sự khác biệt trong vài giây

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

0

Nếu bạn muốn có hồ sơ giữa các ngày,

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

0

Trong trường hợp của tôi, tôi phải tính toán sự khác biệt theo phút và julianday()không đưa ra giá trị chính xác. Thay vào đó, tôi sử dụng strftime():

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

Cả hai ngày đều được chuyển đổi thành đơn thời gian (giây), sau đó được trừ đi để nhận giá trị tính bằng giây giữa hai ngày. Tiếp theo, chia nó cho 60.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.