为什么东部时间和中部时间的日期时间偏移量相同?

问题描述

我创建了一个小应用程序来测试使用 UTC 偏移量的存储时间。我不明白结果。如果我在今天 14:01 运行程序,我会得到这个:

这个:

InsertPunch(new Employee { Id = 10,TimeZoneId = "Central Standard Time" });

数据库生成

2021-01-08 13:01:06.3594141 -05:00

这个:

InsertPunch(new Employee { Id = 12,TimeZoneId = "Eastern Standard Time" });

数据库生成

2021-01-08 14:01:07.5587251 -05:00

时间是对的;第一个确实是CT,第二个确实是ET。但是为什么两者的偏移量都是-5? CT 的偏移量不应该是 -6 吗?我假设我们可以看到这样的时间:

2021-01-08 14:01:07.5587251 -05:00

...我们知道 UTC 时间是 19:01 (14:01 + 5:00)。没错。但是CT的结果是错误的:13:01 + 5:00 = 18:01,而当前的UTC时间实际上是19:01。

我理解错了吗?或者我做错了什么?

    static void Main(string[] args)
    {
        InsertPunch(new Employee { Id = 10,TimeZoneId = "Central Standard Time" });
        InsertPunch(new Employee { Id = 12,TimeZoneId = "Eastern Standard Time" });

        Console.WriteLine("Press any key to end.");
        Console.ReadKey();
    }

    private static void InsertPunch(Employee employee)
    {
        var punchTimeUtc = DateTime.UtcNow; // Need timestamp in UTC to properly convert to employee's time zone.

        var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(employee.TimeZoneId); // Reference the employee's time zone.
        
        var punchTimeInUsersZone = TimeZoneInfo.ConvertTimeFromUtc(punchTimeUtc,timeZoneInfo);

        var punch = new Punch
        {
            EmployeeId = employee.Id,PunchTime = punchTimeInUsersZone
        };

        string sql = "INSERT INTO [time].[Punch] ([EmployeeId],[PunchTime]) VALUES (@EmployeeId,@PunchTime)";

        using (IDbConnection db = new sqlConnection(_connectionString))
        {
            db.Execute(sql,new { punch.EmployeeId,punch.PunchTime });
        }
    }

解决方法

我相信发生的情况是您的数据库中的字段是 datetimeoffset 类型(如您粘贴的示例中出现的偏移量所证明),但是您将 .NET DateTime 值传递到将数据插入该字段时的参数。

在这种情况下,SQL 客户端将使用与 .NET 的 DateTimeDateTimeOffset 隐式转换运算符所描述的相同效果,静默地强制这些值。来自those docs

... 生成的 DateTimeOffset 对象的偏移量取决于 DateTime.Kind 参数的 dateTime 属性值:

  • 如果DateTime.Kind属性的值为DateTimeKind.Utc,则DateTimeOffset对象的日期和时间被设置为等于dateTime,其{{ 1}} 属性设置为等于 0。

  • 如果 Offset 属性的值为 DateTime.KindDateTimeKind.Local,则 DateTimeKind.Unspecified 对象的日期和时间设置为等于 {{1} },并且它的DateTimeOffset属性被设置为等于本地系统当前时区的偏移量。

在您提供的代码中,dateTime 将始终为 Offset,因此在决定应用哪个偏移量时将使用系统本地时区。因此您存储 -5,因为您在东部时区并且日期属于标准时间段。

解决方案是在您的代码中使用 .NET punchTimeInUsersZone.Kind 类型而不是 DateTimeKind.Unspecified

  • 首先,将 DateTimeOffset 类的 DateTime 属性更改为 PunchTime

  • 然后在您的 Punch 方法中更改转换逻辑,如下所示:

    DateTimeOffset

其他都很好。