问题描述
我创建了一个小应用程序来测试使用 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 的 DateTime
到 DateTimeOffset
隐式转换运算符所描述的相同效果,静默地强制这些值。来自those docs:
... 生成的 DateTimeOffset
对象的偏移量取决于 DateTime.Kind
参数的 dateTime
属性值:
-
如果
DateTime.Kind
属性的值为DateTimeKind.Utc
,则DateTimeOffset
对象的日期和时间被设置为等于dateTime
,其{{ 1}} 属性设置为等于 0。 -
如果
Offset
属性的值为DateTime.Kind
或DateTimeKind.Local
,则DateTimeKind.Unspecified
对象的日期和时间设置为等于 {{1} },并且它的DateTimeOffset
属性被设置为等于本地系统当前时区的偏移量。
在您提供的代码中,dateTime
将始终为 Offset
,因此在决定应用哪个偏移量时将使用系统本地时区。因此您存储 -5,因为您在东部时区并且日期属于标准时间段。
解决方案是在您的代码中使用 .NET punchTimeInUsersZone.Kind
类型而不是 DateTimeKind.Unspecified
。
-
首先,将
DateTimeOffset
类的DateTime
属性更改为PunchTime
。 -
然后在您的
Punch
方法中更改转换逻辑,如下所示:DateTimeOffset
其他都很好。