为什么 Azure 会丢失 DateTimeOffset 字段中的时区信息?

Why does Azure lose timezone information in DateTimeOffset fields?

我们正在使用 Microsoft 的 Azure 移动服务开发 IOS 应用程序。 Web GUI 将日期时间创建为 DateTimeOffset 字段,这很好。但是当我们让移动设备将日期时间放入数据库,然后通过 Entity Framework 从数据库中读取它们时,我们看到它们已调整为 UCT。 (当我们在 SSMS 中查看记录时,我们看到同样的事情。)

我一直对 SQL 的标准日期时间类型缺乏时区支持感到沮丧,我认为 DateTimeOffset 会更好。但如果我想要 UTC 时间,我会把它们存储在 UTC 中。如果用户输入的时间为 3:00 AM,CST,我想知道他输入的是 CST。将它转换为 UTC 并丢弃偏移量对我来说毫无意义,因为它假设 3:00 AM CST 和 3:00 AM PDT 是相同的。

我可以进行某种数据库配置来防止 Azure 数据库以 UTC 格式存储日期吗?

问题是在 Azure 移动服务中,属性 被转换为 JavaScript Date 对象,不能不保留偏移量。

有几篇博文描述了这个问题,以及可能的解决方法:

本质上,它们都采用相同的方法将偏移量拆分到一个单独的字段中。然而,仔细观察这些,他们都犯了一个严重的错误:

dto.DateTime.ToUniversalTime()

实际上应该是:

dto.UtcDateTime

DateTimeOffsetDateTime 将始终具有 DateTimeKind.Unspecified,因此 ToUniversalTime 将假定源是 local ,而不是使用 DTO 的偏移量。

我在这些帖子的代码中看到了其他一些类似的错误,因此请仔细彻底测试。但是,一般方法是合理的。

我们正在使用 Node.js 后端,并注意到从我们的 SQL 服务器数据库读取的 DATETIMEOFFSETs 以 UTC 返回,无论偏移量如何。另一种方法是在查询级别转换 DATETIMEOFFSET ,以便将其输出为带有时区信息的字符串。下面将一个 DATETIMEOFFSET(0) 字段转换为 ISO8601 格式;但是,可以使用其他可能的样式,如记录 here:

SELECT CONVERT(VARCHAR(33), [StartDate], 126) AS [StartDate] FROM [Products];

现在的新输出是:"2016-05-26T00:00:00-06:00" 而不是 "2016-05-26T06:00:00+00:00"

当然,这意味着客户端必须将字符串序列化为各自的格式。在 iOS 中,ISO8601 库可用于将输出读取为 NSDateComponentsNSDate

这种方法的一个好处是任何数据库级检查或触发器都可以使用 DATETIMEOFFSET 进行日期比较,而不是尝试考虑具有基本 DATETIME 的单独偏移列。