【发布时间】:2017-12-11 10:38:07
【问题描述】:
关于在 DB 中保存日期时间和时区信息存在很多问题,但总体而言更多。这里我想谈一个具体的案例。
系统规格
- 我们有一个订单系统数据库
- 这是一个多租户系统,租户可以使用任意时区(它是任意的,但每个租户只有一个时区,保存在租户表中一次并且永远不会更改)
需要在 DB 中涵盖业务规则
- 当租户向系统下订单时,订单号会根据他们的本地日期时间计算(它不是字面意义上的数字,而是某种标识符,例如
ORDR-13432-Year-Month-Day)。目前精确计算并不重要,重要的是它取决于租户本地日期时间 - 我们还希望能够在系统级别选择所有订单,无论租户如何(用于一般系统统计/报告)
我们最初的想法
- 我们最初的想法是在整个数据库中保存 UTC 日期时间,当然,保持租户时区相对于 UTC 的偏移,并让使用数据库的应用程序始终将日期时间转换为 UTC,以便数据库本身始终使用 UTC。
方法 1
-
为每个租户保存本地租户的日期时间会很好,但是我们遇到了以下查询的问题:
SELECT * FROM ORDERS WHERE OrderDateTime BETWEEN UTCDateTime1 AND UTCDateTime2
这是有问题的,因为此查询中的 OrderDateTime 表示不同的时间点,具体取决于租户。当然,此查询可能包括加入Tenants 表以获取本地日期时间偏移量,然后会即时计算OrderDateTime 以进行调整。有可能,但不确定这是否是一个好方法?
方法 2
- 另一方面,在保存 UTC 日期时间时,当我们计算 OrderNumber 时,因为 UTC 中的日/月/年可能与本地日期时间中的不同
我们举个极端的例子;假设租户比 UTC 时间早 6 小时,他的本地日期时间是 2017-01-01 02:00。
UTC 将是2016-12-31 20:00。此时下的订单应该得到 OrderNumber 'ORDR-13432-2017-1-1',但如果保存 UTC,它将得到 ORDR-13432-2016-12-31。
在这种情况下,在 DB 中创建 Order 时,我们应该获取 UTC 日期时间,租户偏移量并根据重新计算的租户本地时间编译 OrderNumber,但仍将 DateTime 列保存为 UTC。
问题
- 处理这种情况的首选方法是什么?
- 是否有一个很好的解决方案来保存 UTC 日期时间,因为系统级报告对我们来说非常好?
- 如果要保存 UTC,方法 2) 是处理这些情况的好方法,还是有更好/推荐的方法?
[更新]
基于 Gerard Ashton 和 Hugo 的 cmets:
最初的问题是关于租户是否可以更改时区以及如果政治当局更改时区属性或某些地区的时区会发生什么的细节并不清楚。 当然这是极其重要的,但它不在这个问题的中心。我们可能会在一个单独的问题中解决这个问题。
为了这个问题,假设租户不会更改位置。该位置的时区属性或时区本身可能会更改,这些更改将在系统中与此问题分开处理。
【问题讨论】:
-
本地时区永远不会改变的假设是有风险的。如果时区存储为标准化名称(东部标准时间),那么您还必须在整个数据库历史中跟踪夏令时的开始和结束日期。如果存储为与 UTC 的数字偏移量,它将在受夏令时影响的区域发生变化。在极少数情况下,政治分区可能会从一个时区更改为另一个时区。
-
“本地时区永不改变”的声明是每个租户的。这只是意味着一旦租户选择了他们的时区,他们将始终使用该时区。时区本身的所有潜在潜在变化。
-
也许时区问题超出了您的控制范围。但是如果我是租户并且美国国会和州立法机构决定将我办公室的时区从山区时间更改为中部时间,并且数据库提供商不允许我更改数据库中的时区,我会不开心。您是以名称还是数值来跟踪时区?
-
@KevinChristopherHenry 我完全同意,但在这种情况下,它是必需的业务规则。客户希望 OrderNumber 以这种方式组成。它不是开发人员的选择。
-
在订单号中使用订单日期并没有错。规范化不适用于那个,无论如何都被高估了......
标签: datetime timezone utc dst datetimeoffset