与SQL进行时区协调

时间:2019-05-31 15:28:00

标签: mysql go timezone timestamp-with-timezone

问题1/3:

我有多个MySQL数据库可以连接,并希望确保查询之间的时间一致性。因此,例如,这些服务器之一当前位于CDT时区。

> select CURRENT_TIMESTAMP, @@system_time_zone, @@global.time_zone, @@session.time_zone;

+---------------------+--------------------+--------------------+---------------------+
| CURRENT_TIMESTAMP   | @@system_time_zone | @@global.time_zone | @@session.time_zone |
+---------------------+--------------------+--------------------+---------------------+
| 2019-05-31 09:44:45 | CDT                | SYSTEM             | SYSTEM              |
+---------------------+--------------------+--------------------+---------------------+

注意:我们现在在DST中,所以它是CDT。我假设,它将在CST之外自动更改为DST,对吧?

基于上述知识,我的DSN后缀看起来像这样:

...?parseTime=true&loc=America%2FChicago // i.e. 'America/Chicago' - maybe 'CST6CDT' would work too?

因此,go中是否有一种编程方式可以将3字母代码CDT映射到更正式的时区名称,例如America/Chicago

2/3:

上面介绍了一个鸡/蛋的情况:为了确定远程服务器的时区,需要连接/查询服务器;知道这一点后,DSN参数可能会为将来的调用而更改。

事实之后是否可以更改DSN参数,还是需要创建全新的连接sql.DB连接池?

3/3:

您可能会问,为什么要检查时区是否已更改-它不是静态的吗?在负载平衡的数据库情况下应该做什么?理论上两个副本可以在不同的时区吗?

是否应该将所有带有时间戳记的列都用SQL UNIX_TIMESTAMP()包装起来以规范化数据并避免这种麻烦?

我也可以涉猎时间,但我现在就停在这里。

1 个答案:

答案 0 :(得分:0)

1/3

go使用IANA的Time Zone Database和精确的区域名称。 试图逆向工程MySQL如何从(Linux)主机确定本地时区格式并在go客户端中复制该逻辑(如@MattJohnson所指出的那样)被证明是不可靠的。

2/3

通过database/sql.DB创建的

Open(drv, DSN) –将对所有连接使用相同的DSN。尽管sql.DB只能创建一次并使用很多次-事后没有办法更改DSN-因此在更改时,您需要创建一个全新的sql.DB DSN

3/3

因此,更好的办法似乎是在传输给客户端之前,利用MySQL将所有datetime值从本地转换为UTC时区。这消除了在连接时通过DSN设置数据库(可能未知)时区的麻烦。

一个有希望的选择是设置连接的会话时区:

  • SET @@session.time_zone = "+00:00";
  • 但是,这仅适用于 current 连接(在连接池中)。但是,go客户端在任何给定时间都不知道他们可能正在使用哪个免费连接。
  • 因此,为确保始终有效,需要在 所有查询 之前手动应用它。即使仅使用一个数据库连接-如果连接失败并且连接重试开始-任何以前的会话状态都将丢失。

因此,用如下转换函数包装所有datatime列:

CONVERT_TZ(`STAMP_UPDATED`,@@session.time_zone,'+00:00')

确保时区计算在查询时完成,并且在连接重新连接等过程中不会丢失。

因此,DSN现在不再需要指定loc-因为UTC是默认设置。实际上,DSN仅需要后缀选项?parseTime=true即可将datetime转换为go的本机time.Time

最后也是最重要的一点,这将适用于设置为任何时区的任何服务器。

对此answer的H / T。