[英]How can I account for datetime's lack of millisecond precision when performing datetime comparisons?
我最近了解到SQL 服務器的 datetime 類型只存儲大約 1/300 秒的時間。
因此,鑒於這些數據:
create table datetime_test (id int, my_date datetime);
insert into datetime_test (id, my_date) values
(0, '2020-12-11 17:14:07.000'),
(1, '2020-12-11 17:14:07.197'),
(2, '2020-12-11 17:14:07.198'),
(3, '2020-12-11 17:14:08.000');
這個查詢將返回(1, 2, 3)
,而不是人們可能期望的(2, 3)
:
select id from datetime_test where my_date >= '2020-12-11 17:14:07.198';
原因是這個日期時間的毫秒部分實際上存儲為.197
:
-- Result: 2020-12-11 17:14:07.197
select convert(datetime, '2020-12-11 17:14:07.198');
我正在使用現有的 c# 代碼,該代碼使用 SQL 來比較使用>=
的日期時間。 像這樣的東西:
public Foo GetMyColumn(DateTime inputDatetime)
{
// ...
}
select my_column
from my_table
where my_datetime >= @inputDatetime
我正在嘗試重用此 c# 方法來執行排他比較......相當於使用>
。 我怎樣才能做到這一點?
我最初的嘗試是向日期時間輸入(在 c# 中)添加一個毫秒,但由於上述精度問題,這將不起作用。 我想我可以增加 3 毫秒。 這感覺就像一個黑客。 但它會可靠地工作嗎?
注意:請假設我無法更改此 SQL 或方法。
您會發現 windows 時鍾可能不如您需要的准確。 此外,您的服務器的時鍾不是那么准確,這取決於它可能滯后的負載,因此,當需要准確的時間時,我們使用帶有 GPS 定時器的特殊硬件。
此外,您的服務器上的時間和數據庫服務器上的時間不需要匹配,如果您的要求很難,那么它們將/可能“永遠不會匹配”。 只有一塊破損的手表每天准確 2 次...
請注意,始終在數據庫和代碼中使用 UTC 日期時間,這樣無論服務器托管在何處,您都擁有相同的時間。 UTC 日期時間在 .net 中有一個 ToLocalTime() ,並且數據庫在 TSQL 中有一個 GetUtcDate() 這樣你就不會被時區限制。
using System;
using System.Runtime.InteropServices;
public static class HighResolutionDateTime
{
public static bool IsAvailable { get; private set; }
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi)]
private static extern void GetSystemTimePreciseAsFileTime(out long filetime);
public static DateTime UtcNow
{
get {
if (!IsAvailable)
{
throw new InvalidOperationException("High resolution clock isn't available.");
}
long filetime;
GetSystemTimePreciseAsFileTime(out filetime);
return DateTime.FromFileTimeUtc(filetime);
}
}
static HighResolutionDateTime()
{
try
{
long filetime;
GetSystemTimePreciseAsFileTime(out filetime);
IsAvailable = true;
}
catch (EntryPointNotFoundException)
{ // Not running Windows 8 or higher.
IsAvailable = false;
}
}
}
#edit 根據評論比較日期時間,使用 datetime2(7) 作為數據列中的數據類型,這將與 .net datetime 一樣准確
根據文檔, datetime
時間“四舍五入到 0.000、0.003 或 007 秒的增量”。 因此,c# 解決方法是按照該模式將DateTime
輸入四舍五入到下一個數字。
像這樣的東西:
private DateTime RoundUp(DateTime datetime)
{
int lastMillisecondDigit;
do
{
datetime = datetime.AddMilliseconds(1);
lastMillisecondDigit = datetime.Millisecond % 10;
} while (lastMillisecondDigit != 0 && lastMillisecondDigit != 3 && lastMillisecondDigit != 7);
return datetime;
}
注意:我知道這是一個大黑客。 評論中有更好的解決方案,例如將數據類型更改為datetime2
。 但是,如果您無法更改數據庫或代碼,我認為這種解決方法可以解決問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.