为什么 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
DateTimeOffset
的 DateTime
将始终具有 DateTimeKind.Unspecified
,因此 ToUniversalTime
将假定源是 local ,而不是使用 DTO 的偏移量。
我在这些帖子的代码中看到了其他一些类似的错误,因此请仔细彻底测试。但是,一般方法是合理的。
我们正在使用 Node.js 后端,并注意到从我们的 SQL 服务器数据库读取的 DATETIMEOFFSET
s 以 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
库可用于将输出读取为 NSDateComponents
或 NSDate
。
这种方法的一个好处是任何数据库级检查或触发器都可以使用 DATETIMEOFFSET
进行日期比较,而不是尝试考虑具有基本 DATETIME
的单独偏移列。
我们正在使用 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
DateTimeOffset
的 DateTime
将始终具有 DateTimeKind.Unspecified
,因此 ToUniversalTime
将假定源是 local ,而不是使用 DTO 的偏移量。
我在这些帖子的代码中看到了其他一些类似的错误,因此请仔细彻底测试。但是,一般方法是合理的。
我们正在使用 Node.js 后端,并注意到从我们的 SQL 服务器数据库读取的 DATETIMEOFFSET
s 以 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
库可用于将输出读取为 NSDateComponents
或 NSDate
。
这种方法的一个好处是任何数据库级检查或触发器都可以使用 DATETIMEOFFSET
进行日期比较,而不是尝试考虑具有基本 DATETIME
的单独偏移列。