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

Why is the date time offset the same for eastern and central time?

我创建了一个小应用程序来测试使用 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:

... The offset of the resulting DateTimeOffset object depends on the value of the DateTime.Kind property of the dateTime parameter:

  • If the value of the DateTime.Kind property is DateTimeKind.Utc, the date and time of the DateTimeOffset object is set equal to dateTime, and its Offset property is set equal to 0.

  • If the value of the DateTime.Kind property is DateTimeKind.Local or DateTimeKind.Unspecified, the date and time of the DateTimeOffset object is set equal to dateTime, and its Offset property is set equal to the offset of the local system's current time zone.

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

解决方案是在代码中使用 .NET DateTimeOffset 类型而不是 DateTime

  • 首先,将 Punch class 上的 PunchTime 属性 更改为 DateTimeOffset

  • 然后在你的InsertPunch方法中改变转换逻辑如下:

    DateTimeOffset punchTimeUtc = DateTimeOffset.UtcNow;
    TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(employee.TimeZoneId);
    DateTimeOffset punchTimeInUsersZone = TimeZoneInfo.ConvertTime(punchTimeUtc, timeZoneInfo);
    

其他都可以。