如果我将所有日期保存为 UTC +0,如何在不同时区获得一致的数据
How do I get consistent data across different timezones if I am saving all the dates in UTC +0
我有一个系统,华盛顿特区的用户可以在其中创建 post
。此 post 以 UTC +0 时间保存在我的系统中。然后,我可以使用一个报告系统,它会提供有关特定日期范围内每个创建的 post 的信息。假设我 select 日期范围从 March 21st 00:00:00
到 March 28th 23:59:59
但在我的系统中有人在 March 28th 22:30:00
华盛顿特区时间创建了 post。华盛顿特区比 UTC 晚几个小时,所以这个 post 会被保存在 March 29th 02:30:00
左右,所以当我生成 3 月 21 日到 3 月 28 日的报告时,我不会得到正确的结果,因为有1 post 已在华盛顿时间 3 月 28 日创建,但那是 3 月 29 日 UTC +0 时间。
我首先通过获取客户端的 UTC 偏移量并将其发送到服务器来解决这个问题,然后将该偏移量添加到我的日期范围中:
// JavaScript
"offsetHours" : parseInt(new Date().getTimezoneOffset() / -60)
"offsetMinutes" : (new Date().getTimezoneOffset() / -60) % 1 * 60
// Python
_range["from"] = strToDate(_range["from"]) - datetime.timedelta(hours = int(request.headers["offsetHours"]), minutes=int(request.headers["offsetMinutes"]))
这解决了问题,但引发了另一个问题。现在,如果我从 2 个不同的时区生成相同时间范围(从 3 月 21 日到 28 日)的报告,我将得到不同的结果。这是因为 2 个用户有不同的偏移量,因此他们影响 from
范围的时间间隔不同。
这个问题有什么解决办法吗?
您描述的不一定是问题,而是世界各地时间运作方式的副作用。
在任何给定时间,世界上某处通常 不止一个“日期”生效。如果您要保存发生的事件的时间戳,并且您的客户遍布世界各地,那么您保存的日期不一定与用户认为在他们自己的时区内的日期相同。无论您将时间戳与 UTC 还是特定时区对齐,都是如此。
因此,您必须就应用程序的预期工作方式做出业务决策。您希望您的每日报告反映在 UTC 日内发布的帖子,还是在根据您公司总部时区的一天内发布的帖子?然后以 UTC 格式存储时间戳,并(可选)在报告之前或报告期间调整为您公司的时区。
但是,如果您希望每日报告反映用户时区中的日期,那么您可能还想存储用户的时区 ID(例如 America/New_York
- 而不是数字偏移量),以便你可以转换成那个。请记住,如果用户位于不同的时区,从单一时区的角度来看,您的报告可能看起来很奇怪。
另一种经常使用的技术(主要是出于性能原因,但也是为了逻辑清晰),是将基于 UTC 的时间戳 和 保留为单独的字段适用的“营业日”。通常这样的字段是只是一个日期字段,存储的是2021-03-29
这样的值,没有任何时间和时区。该字段可以根据您决定适用于您的业务的任何规则预先转换为时区。然后它成为一个很好的索引候选者,并且适用于每日报告的范围查询。
最后 - 没有一种“正确”的方法可以做到这一点。您必须决定什么最适合您的用例。如果您在一家较大的公司工作并且不确定业务需求,请询问可能已经手动执行过类似 activity 的人。 (通常是大型组织中的会计或销售人员。)
我有一个系统,华盛顿特区的用户可以在其中创建 post
。此 post 以 UTC +0 时间保存在我的系统中。然后,我可以使用一个报告系统,它会提供有关特定日期范围内每个创建的 post 的信息。假设我 select 日期范围从 March 21st 00:00:00
到 March 28th 23:59:59
但在我的系统中有人在 March 28th 22:30:00
华盛顿特区时间创建了 post。华盛顿特区比 UTC 晚几个小时,所以这个 post 会被保存在 March 29th 02:30:00
左右,所以当我生成 3 月 21 日到 3 月 28 日的报告时,我不会得到正确的结果,因为有1 post 已在华盛顿时间 3 月 28 日创建,但那是 3 月 29 日 UTC +0 时间。
我首先通过获取客户端的 UTC 偏移量并将其发送到服务器来解决这个问题,然后将该偏移量添加到我的日期范围中:
// JavaScript
"offsetHours" : parseInt(new Date().getTimezoneOffset() / -60)
"offsetMinutes" : (new Date().getTimezoneOffset() / -60) % 1 * 60
// Python
_range["from"] = strToDate(_range["from"]) - datetime.timedelta(hours = int(request.headers["offsetHours"]), minutes=int(request.headers["offsetMinutes"]))
这解决了问题,但引发了另一个问题。现在,如果我从 2 个不同的时区生成相同时间范围(从 3 月 21 日到 28 日)的报告,我将得到不同的结果。这是因为 2 个用户有不同的偏移量,因此他们影响 from
范围的时间间隔不同。
这个问题有什么解决办法吗?
您描述的不一定是问题,而是世界各地时间运作方式的副作用。
在任何给定时间,世界上某处通常 不止一个“日期”生效。如果您要保存发生的事件的时间戳,并且您的客户遍布世界各地,那么您保存的日期不一定与用户认为在他们自己的时区内的日期相同。无论您将时间戳与 UTC 还是特定时区对齐,都是如此。
因此,您必须就应用程序的预期工作方式做出业务决策。您希望您的每日报告反映在 UTC 日内发布的帖子,还是在根据您公司总部时区的一天内发布的帖子?然后以 UTC 格式存储时间戳,并(可选)在报告之前或报告期间调整为您公司的时区。
但是,如果您希望每日报告反映用户时区中的日期,那么您可能还想存储用户的时区 ID(例如 America/New_York
- 而不是数字偏移量),以便你可以转换成那个。请记住,如果用户位于不同的时区,从单一时区的角度来看,您的报告可能看起来很奇怪。
另一种经常使用的技术(主要是出于性能原因,但也是为了逻辑清晰),是将基于 UTC 的时间戳 和 保留为单独的字段适用的“营业日”。通常这样的字段是只是一个日期字段,存储的是2021-03-29
这样的值,没有任何时间和时区。该字段可以根据您决定适用于您的业务的任何规则预先转换为时区。然后它成为一个很好的索引候选者,并且适用于每日报告的范围查询。
最后 - 没有一种“正确”的方法可以做到这一点。您必须决定什么最适合您的用例。如果您在一家较大的公司工作并且不确定业务需求,请询问可能已经手动执行过类似 activity 的人。 (通常是大型组织中的会计或销售人员。)