处理多个时区的应用程序中的时间处理

Time handling in application handling multiple timezone

我有来自多个时区的用户,并以 UTC 格式将时间存储在数据库中。 运行 时间部分单独存在问题。

按如下方式存储该周的用户工作时间。

Id UserId Day StTime EndTime
1 1 0 10:00 18:00
2 1 1 10:00 18:00
3 1 2 10:00 18:00
4 1 3 10:00 18:00
5 1 4 10:00 18:00

日期,0 表示星期日,1 表示星期一,...

此处,时间以 UTC 格式存储。时间正在根据浏览器时区转换为 UI。因为这里不需要日期部分,所以这里出现了问题。

例如,假设用户在 UI 中选择早上 7 点到晚上 7 点,时间将转换为 UTC,即今天 15:00 到明天 02:00。因此,在数据库中,时间存储为

Id UserId Day StTime EndTime
1 1 0 15:00 02:00
2 1 1 15:00 02:00
3 1 2 15:00 02:00
4 1 3 15:00 02:00
5 1 4 15:00 02:00

这里的开始时间大于结束时间,这是不正确的。

当只存储时区的时间部分时,我们需要如何处理时区?

我的要求是根据以下信息为用户获取空位。

  1. 预订时段
  2. 已阻止的广告位
  3. 工作时间

BookedSlots,

Id userId St_time(datetime) duration(mins)
1 1 2021-11-27 16:00:00 30
1 1 2021-11-27 18:00:00 45

这里的时间是UTC。

  1. BlockedSlots
Id userId St_time end_date st_time end_time
1 1 2021-11-22 2021-11-25 09:00 18:00
1 1 2021-12-17 2021-12-20 09:00 18:00

这里同样需要以UTC格式存储时间

  1. 工作时间
Id UserId Day StTime EndTime
1 1 0 15:00 02:00
2 1 1 15:00 02:00
3 1 2 15:00 02:00
4 1 3 15:00 02:00
5 1 4 15:00 02:00

我需要根据以上 3 个信息计算空位。但是,当我们将其存储在 UTC 中时,时间部分会造成混淆。处理此问题的最佳方法是什么?

如果你想要结束时间 > 开始时间

你可以做这样的计算

sTime = StTime
eTime = StTime + mod(EndTime-StTime+24hour, 24)

例如:

StTime=15
EndTime=02

sTime = 15
eTime = 15 + mod(2-15+24, 24) = 26

其中 26 表示 (24+2) => 第二天 + 2 小时 和

StTime=09
EndTime=18

sTime = 09
eTime = 09 + mod(18-09+24, 24) = 18

09到18将保持不变

在 Postgresql 中计算日期时间

SELECT TO_TIMESTAMP('2021-11-26 00:00:00', 'YYYY-MM-DD HH24:MI:SS') +StTime AS stime , TO_TIMESTAMP('2021-11-26 00:00:00', 'YYYY-MM-DD HH24:MI:SS')+StTime+(MOD((EXTRACT(EPOCH FROM (EndTime - StTime)::interval)+86400)::int4, 86400) || ' second')::interval AS etime FROM WorkingHours

您应该能够获得结束 > 开始的开始和结束日期时间

一个结果示例

UserId  StTime      EndTime       stime                   etime
1       15:00:00    02:00:00      2021-11-26 15:00:00     2021-11-27 02:00:00
2       09:00:00    18:00:00      2021-11-26 09:00:00     2021-11-26 18:00:00

希望对您有所帮助

避免午夜环绕的一种方法是将工作时间存储为具有开始时间和持续时间,而不是开始时间和结束时间,就像您为预订的时段所做的那样。您可以对阻塞的插槽执行相同的操作,以便为所有事件提供一个良好的一致存储模型。

我还建议存储用户当地时间的工作时间,以及 IANA timezone string 指示工作地点。以 UTC 存储的问题在于,某些时区全年都会进入和退出夏令时。假设我在纽约市,我希望我的工作时间为纽约时间 09:00 到 17:00。由于目前纽约是东部标准时间 (UTC-5),因此将转换为 14:00 到 22:00。一到夏天,纽约就会进入东部夏令时间(UTC-4),所以我的工作时间会突然变成10:00到18:00纽约时间。

您还可以将时区与用户信息一起存储,以便工作时间与时区无关。这将允许您在用户所在的任何时区指定类似“09:00 到 17:00”的内容。

任何时候你处理重复发生的事件,我总是发现将它们存储在事件将发生的时区更清晰,因为从 UTC 转换的逻辑全年都在变化。对于绝对事件,如​​预订和阻塞的插槽,将它们保持在 UTC 中仍然有意义,因为它们指的是一个特定的时间事件。