Datetime 保存日期时间的最佳实践&;当数据依赖于日期时间时,数据库中的时区信息
关于在DB中保存datetime&timezones信息有很多问题,但在总体层面上有更多问题。这里我想谈谈一个具体的案例 系统规格Datetime 保存日期时间的最佳实践&;当数据依赖于日期时间时,数据库中的时区信息,datetime,timezone,utc,dst,datetimeoffset,Datetime,Timezone,Utc,Dst,Datetimeoffset,关于在DB中保存datetime&timezones信息有很多问题,但在总体层面上有更多问题。这里我想谈谈一个具体的案例 系统规格 我们有一个订单系统数据库 这是一个多租户系统,租户可以使用任意时区(它是任意的,但每个租户只有一个时区,保存在租户表中一次,从不更改) 业务规则需要包含在DB中 当租户向系统下订单时,订单号将根据其本地日期时间计算得出(它不是字面上的数字,而是某种标识符,如ORDR-13432-Year-Month-Day)。精确的计算目前并不重要,重要的是它取决于租户的本地
- 我们有一个订单系统数据库
- 这是一个多租户系统,租户可以使用任意时区(它是任意的,但每个租户只有一个时区,保存在租户表中一次,从不更改)
- 当租户向系统下订单时,订单号将根据其本地日期时间计算得出(它不是字面上的数字,而是某种标识符,如
)。精确的计算目前并不重要,重要的是它取决于租户的本地日期和时间ORDR-13432-Year-Month-Day
- 我们还希望能够在系统级别上选择在某些UTC日期时间之间下的所有订单,而不考虑租户(对于一般系统统计/报告)
- 我们最初的想法是在整个数据库中保存UTC日期时间,当然,保留租户相对于UTC的时区偏移,并让使用数据库的应用程序始终将日期时间转换为UTC,以便数据库本身始终使用UTC运行
- 保存本地租户datetime对每个租户都很好,但是我们遇到了以下问题:
SELECT * FROM ORDERS WHERE OrderDateTime BETWEEN UTCDateTime1 AND UTCDateTime2
OrderDateTime
表示不同的时间点,具体取决于租户。当然,这个查询可能包括join toTenants
表,以获取本地日期时间偏移量,然后动态计算OrderDateTime
,以进行调整。这是可能的,但不确定这是否是一个好方法
方法2
- 另一方面,在保存UTC datetime时,由于UTC中的日/月/年可能不同于本地datetime中的日/月/年,因此当我们计算订单号时
2016-12-31 20:00
。此时下的订单应获得订单号“ORDR-13432-2017-1-1”,但如果保存UTC,则将获得ORDR-13432-2016-12-31
在这种情况下,在DB中创建订单时,我们应该获取UTC日期时间、租户偏移量,并基于重新计算的租户本地时间编译OrderNumber,但仍然以UTC保存日期时间列
问题
为了解决这个问题,我们假设承租人不会改变位置。该位置的时区属性或时区本身可能会更改,这些更改将在系统中与此问题分开处理。我建议始终在内部使用UTC,并且仅在向用户显示日期时转换为时区。所以我倾向于选择方法2 如果有一条业务规则规定承租人的本地日期/时间必须是标识符的一部分,那么就这样吧。但在内部,您将订单日期保留为UTC 以您的示例为例:其时区为
UTC+06:00
,因此承租人的本地时间为2017-01-01 02:00
,相当于UTC中的2016-12-31 20:00
订单标识符将为ORDR-13432-2017-1-1
,订单日期将为UTC2016-12-31 20:00Z
要获取两个日期之间的所有订单,此查询是严格向前的:
从OrderDateTime介于UTCDateTime1和UTCDateTime2之间的订单中选择*
因为OrderDateTime
是UTC格式
如果要查找特定的租户,则可以获取相应的时区,相应地转换日期并搜索它。使用上述同一示例(承租人的时区为UTC+06:00
),以获取在2017-01-01
(承租人当地时间)内发出的所有订单:
——获取租户时区
--startUTC=承租人的本地2017-01-01 00:00转换为UTC(2016-12-31T18:00Z)
--endUTC=承租人的本地2017-01-01 23:59:59.999转换为UTC(2017-01-01T17:59:59.999)
从ORDERS中选择*,其中OrderDateTime介于startUTC和endUTC之间
这将正确获取ORDR-13432-2017-1-1
要在不同时区查询多个租户,这两种方法都需要联接,因此在这种情况下没有更好的方法
除非您使用租户的本地日期/时间创建一个额外的列(UTC
OrderDateTime
转换为租户的时区)。这将是多余的,但它可以帮助您处理在多个时区中搜索的查询。如果这是一个合理的权衡,那将取决于这些查询的频率。雨果的回答基本上是正确的,但我要补充几点:
- 存储客户的时区时,不要存储数字偏移。正如其他人指出的,与UTC的偏移量仅适用于单个点
... WHERE OrderDateTime >= @t1 AND OrderDateTime < @t2