首页 > 解决方案 > 在执行日期时间比较时,如何解决日期时间缺乏毫秒精度的问题?

问题描述

背景

我最近了解到SQL Server 的 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');

我的问题

我正在处理使用 SQL 来比较日期时间的现有 c# 代码>=。像这样的东西:

public Foo GetMyColumn(DateTime inputDatetime)
{
  // ...
}
select my_column
from my_table
where my_datetime >= @inputDatetime

我正在尝试重用此 c# 方法来执行排他比较...相当于 using >. 我怎样才能做到这一点?

我最初的尝试是向日期时间输入(在 c# 中)添加一个毫秒,但由于上述精度问题,这将不起作用。我想我可以增加 3 毫秒。这感觉就像一个黑客。但它会可靠地工作吗?

注意:请假设我无法更改此 SQL 或方法。

标签: c#sqlsql-serverdatetime

解决方案


您会发现 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 一样准确


推荐阅读