You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地环境下C# DateTime时间晚于SQL Server对应时间的原因解析

本地部署场景下C#时间晚于SQL Server时间的原因解析

在本地同时部署.NET应用与SQL Server的场景中,出现了不符合直觉的时间差异:C#代码先获取DateTime.Now/DateTime.UtcNow值,再调用SQL存储过程执行插入操作,存储过程中用SYSDATETIME()/SYSUTCDATETIME()获取时间,但最终数据库记录里,C#的时间值反而大于SQL的时间值(即C#时间更晚)。以下是具体代码、结果及原因分析。

C# 代码

using System.Data;
using System.Data.SqlClient;

for (int i = 1; i <= 20; i++)
{
    AddRecord();
}
Console.WriteLine("20 records added in database....");

void AddRecord()
{
    try
    {
        string ConnectionString = @"data source=OM5\SQL2019; database=TestDb; integrated security=SSPI";
        using (SqlConnection connection = new SqlConnection(ConnectionString))
        {
            SqlCommand cmd = new SqlCommand()
            {
                CommandText = "SP_AddRecord",
                Connection = connection,
                CommandType = CommandType.StoredProcedure
            };

            SqlParameter param1 = new SqlParameter
            {
                ParameterName = "@CSharp_DateNow",
                SqlDbType = SqlDbType.DateTime2,
                Value = DateTime.Now,
                Direction = ParameterDirection.Input
            };
            cmd.Parameters.Add(param1);

            SqlParameter param2 = new SqlParameter
            {
                ParameterName = "@CSharp_DateUTCNow",
                SqlDbType = SqlDbType.DateTime2,
                Value = DateTime.UtcNow,
                Direction = ParameterDirection.Input
            };
            cmd.Parameters.Add(param2);

            connection.Open();
            cmd.ExecuteNonQuery();
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Exception Occurred: {ex.Message}");
    }
}

SQL 代码

CREATE TABLE [dbo].[Records](
    [Id] [int] PRIMARY KEY IDENTITY(1,1) NOT NULL,
    [SQL_SysDateTime] [datetime2](7) NOT NULL,
    [CSharp_DateNow] [datetime2](7) NOT NULL,
    [SQL_SysUTCDateTime] [datetime2](7) NOT NULL,
    [CSharp_DateUTCNow] [datetime2](7) NOT NULL
)

CREATE OR ALTER PROCEDURE [dbo].[SP_AddRecord]
@CSharp_DateNow datetime2,
@CSharp_DateUTCNow datetime2
AS
BEGIN
    SET NOCOUNT ON;

     insert into Records(SQL_SysDateTime, CSharp_DateNow, SQL_SysUTCDATETIME, CSharp_DateUTCNow) values
     (SYSDATETIME(),@CSharp_DateNow,SYSUTCDATETIME(),@CSharp_DateUTCNow)
END

执行结果

SQL本地时间C#本地时间差值(毫秒)SQL UTC时间C# UTC时间差值(毫秒)
2024-07-26 13:26:35.28983912024-07-26 13:26:34.97016583192024-07-26 07:56:35.28983912024-07-26 07:56:34.9726788317
2024-07-26 13:26:35.30546102024-07-26 13:26:35.3174393-122024-07-26 07:56:35.30546102024-07-26 07:56:35.3174492-12
2024-07-26 13:26:35.32108152024-07-26 13:26:35.321735402024-07-26 07:56:35.32108152024-07-26 07:56:35.32174610
2024-07-26 13:26:35.32108152024-07-26 13:26:35.3261818-52024-07-26 07:56:35.32108152024-07-26 07:56:35.3261915-5
2024-07-26 13:26:35.33670302024-07-26 13:26:35.331030952024-07-26 07:56:35.33670302024-07-26 07:56:35.33103845
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3411312-52024-07-26 07:56:35.33670302024-07-26 07:56:35.3411394-5
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3418632-52024-07-26 07:56:35.33670302024-07-26 07:56:35.3418676-5
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3430069-72024-07-26 07:56:35.33670302024-07-26 07:56:35.3430104-7
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3437519-72024-07-26 07:56:35.33670302024-07-26 07:56:35.3437554-7
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3446140-82024-07-26 07:56:35.33670302024-07-26 07:56:35.3446172-8
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3452865-92024-07-26 07:56:35.33670302024-07-26 07:56:35.3452894-9
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3459309-92024-07-26 07:56:35.33670302024-07-26 07:56:35.3459336-9
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3466520-102024-07-26 07:56:35.33670302024-07-26 07:56:35.3466552-10
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3475280-112024-07-26 07:56:35.33670302024-07-26 07:56:35.3475305-11
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3486445-122024-07-26 07:56:35.33670302024-07-26 07:56:35.3486474-12
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3492964-132024-07-26 07:56:35.33670302024-07-26 07:56:35.3492991-13
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3501936-142024-07-26 07:56:35.33670302024-07-26 07:56:35.3501961-14
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3506370-142024-07-26 07:56:35.33670302024-07-26 07:56:35.3506392-14
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3511339-152024-07-26 07:56:35.33670302024-07-26 07:56:35.3511362-15
2024-07-26 13:26:35.33670302024-07-26 13:26:35.3517053-152024-07-26 07:56:35.33670302024-07-26 07:56:35.3517087-15

核心原因解析

1. SQL Server的系统时间缓存策略

SQL Server为降低频繁读取操作系统时钟的性能开销,会缓存系统时间值。在快速批量操作场景中(比如循环调用存储过程),SQL Server会复用同一时间快照,而非每次调用SYSDATETIME()都重新读取最新时钟。从结果可见,第5条记录开始,SQL的时间值完全固定,而C#时间持续推进,这就是缓存机制的直接体现。

2. .NET与SQL的时间读取机制差异

  • .NET的DateTime.Now/DateTime.UtcNow直接调用Windows系统API(GetSystemTimeAsFileTime)获取时间,每次调用都会读取当前最新的系统时钟(或用户模式下的高频缓存),因此循环中每次读取的时间都会随系统时间正常推进。
  • SQL Server的SYSDATETIME()虽基于操作系统时钟,但缓存逻辑会在短时间多次调用时返回同一值,尤其是操作执行速度极快时,缓存不会及时更新。

3. 线程调度与批量执行的影响

当C#快速循环调用存储过程时,SQL Server可能将多个请求批量处理,共享同一时间上下文。此时即便C#每次先取时间再发送请求,SQL Server执行插入时使用的是批量处理时的缓存时间,导致SQL时间早于后续C#读取的时间。

官方依据

根据微软官方说明,SQL Server的系统时间函数(如SYSDATETIME)依赖操作系统时钟,但会对该值进行缓存以优化性能,避免频繁系统调用;而.NET的时间API更偏向实时读取系统时钟最新值,两者设计目标不同,因此出现时间差属于正常现象。

内容的提问来源于stack exchange,提问作者Shivam Pal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:20:58