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

使用C#向PostgreSQL插入DateTime的UTC时间问题及最佳实践

问题与代码

以下是我的代码:

static void Main(string[] args)
{
    DateTime dt1 = DateTime.Now.AddHours(-8);   //My local time zone is UTC+8
    DateTime dt2 = DateTime.UtcNow;            

    Console.WriteLine($"dt1:{dt1} | dt2:{dt2}");  //dt1:2024-05-10 09:46:10 AM | dt2:2024-05-10 09:46:10 AM

    insertDemo(dt1,dt1);
    insertDemo(dt2,dt2);
}
public static void insertDemo(DateTime ts,DateTime tsz)
{
    string connString = "...";
    using (var conn = new NpgsqlConnection(connString))
    {
        conn.Open();
        using (var command = new NpgsqlCommand("INSERT INTO demo VALUES (@ts,@tsz)", conn))
        {                    
            command.Parameters.AddWithValue("ts", ts);
            command.Parameters.AddWithValue("tsz", tsz);
            command.ExecuteNonQuery();
        }
        conn.Close();
    }
}

插入后的数据截图:
插入后的数据截图

我发现将DateTime.UtcNow插入PostgreSQL后值被修改,但DateTime.Now调整为UTC+8时区对应UTC时间后插入却未变化,请问这是为什么?另外,在数据库中存储UTC时间戳的最佳实践是什么?


原因分析

核心问题出在C# DateTime的**Kind属性**:

  • dt1是DateTime.Now(本地时间,Kind=Local)减去8小时得到的,它的Kind属性仍然是Local,Npgsql会把这个值当作本地时区的时间直接存入数据库,不会做时区转换。
  • dt2是DateTime.UtcNow,它的Kind属性是Utc,Npgsql会自动将UTC时间转换为PostgreSQL服务器配置的时区对应的时间(如果数据库时区不是UTC的话),所以你看到存储的值被修改了。

本质是:Npgsql根据DateTime.Kind来决定是否做时区转换,而非只看时间数值。

存储UTC时间戳的最佳实践
  • 使用正确的数据库类型:优先用PostgreSQL的TIMESTAMP WITH TIME ZONE(缩写timestamptz),它会自动存储UTC时间并关联时区信息,避免歧义;不要用不带时区的TIMESTAMP。
  • 统一UTC时间源:在C#中直接用DateTime.UtcNow(确保Kind=Utc),更推荐用DateTimeOffset类型——它自带时区偏移信息,Npgsql对其处理完全无歧义。
  • 强制连接时区为UTC:在数据库连接字符串中添加TimeZone=UTC,让Npgsql始终以UTC和数据库交互,彻底规避时区转换意外。
  • 延迟时区转换:从数据库读取时间后,不要在存储层转换时区,直到需要展示给用户或业务逻辑需要时,再转换为目标时区。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:50:03