【问题标题】:How to handle timezones?如何处理时区?
【发布时间】:2014-03-12 01:56:57
【问题描述】:

我知道这个问题已经被问过几次了,但我想我对它稍微不同的方面感兴趣。

我的网站有两种用户。我们称他们为前端 (FE) 用户和后端 (BE) 用户。 FE 用户未经身份验证(他们没有用户帐户,因此没有时区),但他们可以创建预订并选择特定的日期和时间。

BE 用户拥有用户帐户。他们可以选择自己的时区。当他们查看预订时,它应该显示与 FE 用户输入的时间完全相同的时间。如果我将此时间转换为使用 BE 的时区,则时间会出现偏差。

但是,其他日期时间(例如创建预订的时间)转换为 BE 的时区。

例如,如果 FE 用户在 2014 年 3 月 11 日下午 5:00 创建预订,它将作为 UTC 时间 2014 年 3 月 11 日下午 5:00 存储在数据库中。 BE用户查看时,会从数据库中拉出,保留UTC,显示为下午5:00。

如果他们查看预订的创建时间,它可能是在 UTC 下午 2:00 记录的,但如果我向 BE 用户显示下午 2:00,他可能会感到困惑,因为它甚至可能出现在未来(如果 UTC领先于他的本地时区)!

因此,据我所知,解决此问题的唯一方法是非常小心我将时区转换为哪些日期,以及我不理会哪些日期,对吗?有没有简单的方法可以解决这个问题,以便我可以在整个应用程序中使用一致的时区?

【问题讨论】:

    标签: timezone


    【解决方案1】:

    ...解决这个问题的唯一方法是非常小心我将时区转换为哪些日期,以及我不理会哪些日期,对吗?

    总的来说,这是个好主意。与时间打交道意味着了解您正在处理的内容的上下文。如果您尝试只设置一次然后忘记它,您的应用程序中可能至少有一部分行为不正确。

    在您的特定用例中,您将“预订”描述为在未指定的时区输入。但是然后您说您将它们存储为UTC。如果预订确实与任何时区无关,那么您应该在与他们合作时引入 UTC。只是不指定它们。 (如果您提供有关您的语言和数据库的详细信息,我可以推荐特定的数据类型。)

    但是 - 可能存在您没有考虑的上下文。当您进行预订时,是针对特定的位置吗?如果是这样,则可以考虑该位置的时区而不是用户的时区。您可以使用该位置的时区来转换为 UTC,或者您可以存储一个“日期-时间偏移”组合值,该值已标准化为该位置的时区。如果您需要的话,两者都可以合理地转换预订时间。只有您可以决定这对您的应用是否有意义。

    关于记录的时间,这是一个不同的上下文。它当然可以是 UTC,然后只是转换为查看它的人的时区。

    【讨论】:

    • 我正在使用 MariaDB。我认为 Maria/MySQL 的工作方式是所有日期时间都保存为 UTC,并在您提取数据时转换为数据库的时区设置(我也设置为 UTC)。实际上,这可能只适用于TIMESTAMPs,我认为DATETIMEs 没有时区?手册对此有点不清楚。预订确实有关联的位置,但这些也是用户输入的;查找时区可能有点困难。如果不需要,我想我不想走那条路。
    • 参考here。另外,MariaDB 是从 MySQL 派生的,所以参考hereDATETIME 没有时区。 TIMESTAMP 基于 UTC。
    • 因此,我建议您使用DATETIME 记录预订时间,TIMESTAMP 记录预订时间。看,不同的上下文,不同的数据类型。 :)
    • TIMESTAMP 实际上并不存储时区。它只是在 MySQL 设置的任何时区之间进行转换,如果它发生变化,这似乎是一种毫无意义的潜在危险。此外,它仅限于 1970-2038 年,除非我的应用程序可以使用 24 年,否则这对我的预期用途来说不是问题。不过,使用TIMESTAMP 有什么好处?
    • TIMESTAMP 是参照 UTC 存储的,所以它是一个准确的时间点。当您与之交互时,您使用当前时区设置中的本地时间,可以为每个连接设置。 (见第 7 段 [这里]dev.mysql.com/doc/refman/5.7/en/datetime.html))。如果您愿意,也可以使用CURRENT_TIMESTAMP() 函数。但可以肯定的是,您也可以使用DATETIME。只是您需要手动确保该值是 UTC。
    【解决方案2】:

    有两种解决方案:

    1. 如果 FE 用户将日期设置为 UTC - 您可以将它们显示为 UTC 以表示 BE 或将它们转换为 BE 时区 - 两种变体都可以,只需向 BE 用户提及时区,他们就不会感到困惑
    2. FE 用户在创建预约时需要指明时区,然后将其转换为 UTC 存储在 DB 中,然后可以显示在 BE 用户的时区中

    最主要的 - 在输出期间始终在实际日期时间值附近指示时区

    【讨论】:

    • FE 用户不知道他们输入的是 UTC 日期,我不能要求他们选择时区。它是隐含的,基于预订发生的位置。基本上,时区对系统来说是未知的,但人们会根据常识立即知道他们所指的时区。因此,我也无法为 BE 用户指定时区,因为我不知道它是什么。但是,我记录的任何时间戳,我都知道时区。
    • 我想这回答了我自己的问题。我无法显示或转换我不知道的内容。
    • @Mark 对,您需要向用户询问时区,其他方式系统将无法工作,您可以简化此过程 - 但在创建表单上假设一些时区(基于 ip 或 javascript),但使用FE 用户可以更改它
    • 系统为什么不能工作?我也不能使用 IP 或 JavaScript。用户的系统时钟可能是错误的,或者他们可能在实际时区之外。不能要求用户输入;一个额外的字段太多了,FE 用户几乎肯定会在某个时候把它搞砸。
    • @Mark 系统将不起作用,因为您实际上不知道数字(由 FE 输入)的含义,您不能使用“未知”时间,因此您必须添加字段并使用任何技术来设置它的默认值
    猜你喜欢
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    相关资源
    最近更新 更多