【问题标题】:Why is the date time offset the same for eastern and central time?为什么东部时间和中部时间的日期时间偏移相同?
【发布时间】:2021-04-14 12:25:42
【问题描述】:

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

【问题讨论】:

  • @Larnu 为什么要删除 SQL Server 标记?
  • 关于SQL Server的问题呢? (请注意,说代码具有 SQL Server 后端并不意味着它与 SQL Server 相关)。
  • 结果来自 SQL Server 中的最终结果。我认为如果列的数据类型、SQL Server 设置等很重要,这可能是相关的。
  • 您正在存储 UTC。您看到的偏移量来自您用来查看它的任何内容,并将其转换为您的时区。
  • 问题是你插入了错误的数据;这不是 SQL Server 的错。那是C#代码的错。 SQL Server 不会更改数据(除非存在您没有告诉我们的触发器)。

标签: c# time timezone timezone-offset


【解决方案1】:

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

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

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

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

  • 如果DateTime.Kind属性的值为DateTimeKind.LocalDateTimeKind.Unspecified,则DateTimeOffset对象的日期和时间设置为等于dateTime,其Offset属性设置为等于本地系统当前时区的偏移量。

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

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

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

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

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

其余的都很好。

【讨论】:

  • 做到了。我已经将PunchTime 属性设置为DateTimeOffset,所以我只需要你的最后一行代码来调用TimeZoneInfo.ConvertTime 而不是TimeZoneInfo.ConvertTimeFromUtc。谢谢。
  • 这是有道理的。但仍要确保您始终使用DateTimeOffset。它将避免此问题的任何其他可能发生,并将避免在 DST 回退转换期间处理不明确的时间边缘情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
  • 2015-08-26
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多