【问题标题】:Looking for patterns to work with Timezones and dates Front-end(React) and Backend(nodejs)寻找与时区和日期一起使用的模式前端(React)和后端(nodejs)
【发布时间】:2020-11-16 22:07:01
【问题描述】:

我正在寻找开发模式来为广大国家或不同国家的不同用户处理不同的时区。

我想知道在现有的世界级软件中是否有任何完全被接受和实施的软件。

到目前为止,我的想法是使用特定时区存储用户配置文件并更改后端查询中的所有日期。

后端将接收本地时间的日期,包括 TZ,并将其以 UTC 格式存储在数据库中。

对于检索结果列表,这非常有效,但是对于需要对 10 月份的所有销售额进行分组的查询进行分组,如果您处于负 TZ 或销售额中,您还应该将 9 月 30 日的日期分组如果您在正时区,则为 11 月 1 日。

对于这种情况,是直接使用用户存储的 TZ 并将其减去/添加到使用 select 子句中的一些 db 函数从 db 检索到的日期时间。

我能解释一下吗?

请记住,例如,如果我必须从 9 月 1 日开始检索数据库的一些销售额

【问题讨论】:

  • 您的后端接收的是仅日期值(例如2020-11-16)还是日期时间值(例如2020-11-16 12:34:56)?另外,您是否阅读过the timezone tag wiki 并了解用户时区需要是时区标识符(例如America/New_York)而不是时区偏移量(例如-05:00)?您正在运行哪个数据库平台,您存储数据的字段是什么数据类型?
  • 感谢@MattJohnson-Pint 的回复,我的问题不在于过滤,我正在做正确的事情,为后端提供具有对应时区的时间戳。我的问题是,只有当我必须按月分组时,才能很好地进行期间过滤,但显示 8 月的销售额(例如 UTC)应该在 9 月分组。感谢您的维基链接
  • 如果你想要一个实际的答案,我仍然需要你回答我的问题。
  • 我正在使用 Mysql 和字段数据类型 datetime,因为我读过 timestamp 存在严重的性能问题。是的,我理解了区域标识符的事情
  • 您错过了第一个问题。你在处理 dates 还是 date+times ?换句话说,是“此订单于2020年11月16日下单”中的订单日期,还是中的订单的确切本地时间+日期+时区“这个订单是在 2020 年 11 月 16 日 12:34:56 在America/Los_Angeles 下的”,还是你收到像2020-11-16T12:34:56-08:00 这样的日期+时间+偏移量?这很重要。

标签: node.js reactjs timezone timezone-offset timestamp-with-timezone


【解决方案1】:

简单回顾一下您告诉我们的内容:

  • 您收到2020-11-16T12:34:56-08:00 之类的数据
  • 您将其以 UTC (2020-11-16T20:34:56Z) 格式存储到 MySQL 中的 datetime 字段中。
  • 您还拥有用户的时区,作为 IANA 时区标识符 (America/Los_Angeles)
  • 您现在想要编写一个查询来获取一段时间内的所有数据,例如给定月份内的所有数据。

在 MySQL 中,datetime 类型与 timestamp 类型的不同之处在于它处理时区转换的方式。来自the MySQL docs

MySQL 将 TIMESTAMP 值从当前时区转换为 UTC 进行存储,然后从 UTC 转换回当前时区进行检索。 (这不会发生在其他类型,例如 DATETIME。)

因此,如果您要使用 timestamp 类型,您唯一需要做的就是在运行查询时将会话时区设置为用户的时区。 (了解每个会话的时区in the docs here。)

您提到出于性能考虑,您选择了日期时间而不是时间戳。这不是普遍真理。我会非常仔细地查看您的实际使用情况,看看您是否遇到了性能问题。您更有可能缺少索引或编写不可搜索的查询。据我所知,timestamp 类型没有普遍存在的性能问题。

如果您仍想使用datetime 类型,那么 MySQL 不会为您进行时区转换。因此,您需要首先将开始/结束日期时间从本地时间转换为 UTC。然后您可以对这些 UTC 值执行范围查询。

使用 either 方法,您需要考虑哪个时区实际上与查询相关。在许多情况下,重要的是特定于业务的时区。在其他情况下,它将是用户。您给出的关于“10 月份的所有销售”的用例很好地说明了这一点。如果他们位于不同的时区,那么对于企业而言,这可能确实不同于对于客户而言。您可能希望它们与众不同,或者您可能希望迫使客户从业务的角度看待事物,反之亦然。这实际上取决于您如何经营该业务。

最后 - 这样的查询应始终作为 范围查询 执行,即从头到尾。通常这最好在您的where 子句中表示为半开区间,例如:

select * from Orders where OrderDate >= @start and < @end

但是,如果您要聚合结果并需要使用group by 子句,那么您将需要一些额外的步骤:

  • 如果企业只有一个时区,您可能需要添加第二个字段,其中的数据已预先转换为该时区。应该是 datedatetime - 而不是 timestamp。然后,您可以使用该字段进行分组。

  • 您可能需要如前所述将子查询作为范围查询运行,然后在分组之前转换为特定时区。您可以使用 MySQL convert_tz 函数。

【讨论】:

    猜你喜欢
    • 2018-12-06
    • 2018-04-21
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2020-02-12
    • 1970-01-01
    • 2021-06-16
    • 2015-10-15
    相关资源
    最近更新 更多