簡體   English   中英

在執行日期時間比較時,如何解決日期時間缺乏毫秒精度的問題?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM