timezone reconciliation with SQL

家住魔仙堡 提交于 2019-12-25 18:41:29

问题


Question 1/3:

I have a number of MySQL databases to connect to and want to ensure time consistency across queries. So for example, one of these servers is currently in the CDT timezone.

> 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              |
+---------------------+--------------------+--------------------+---------------------+

Note: We're in DST right now, so it's CDT. I'm assuming this would automatically change to CST when outside DST, right?

So with the above knowledge, my DSN suffix looks something like this:

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

So, is there a programatic way in go to map from the 3-letter code CDT to the more formal timezone names like America/Chicago.

2/3:

The above presents a chicken/egg scenario: in order to determine the remote server's timezone, one needs to connect/query the server; with that knowledge the DSN parameters may change for future calls.

Can DSN parameters be changed after the fact, or does a brand new connection sql.DB connection pool need to be created?

3/3:

You may ask, why check to see if the timezone has changed - isn't it static? What should one do in a Load-Balanced DB situation? Two replicas could in theory be in differing timezones?

Should all columns with timestamps just be wrapped with an SQL UNIX_TIMESTAMP() to normalize the data and avoid this headache?

I could get into time-drifts too, but I'll stop here for now.


回答1:


1/3

go uses IANA's Time Zone Database with precise zone names. Trying to reverse engineer how MySQL determines the local timezone format from a (Linux) host and duplicate that logic in a go clients - as @MattJohnson pointed out - proves to be unreliable.

2/3

database/sql.DB - created via Open(drv, DSN) - will use the same DSN for all connections. While an sql.DB is meant to be created once and used many times - there is no way to change the DSN after the fact - so one would need to create a brand new sql.DB when changing the DSN.

3/3

So the better tack, appears to leverage MySQL to convert all datetime values from local to UTC timezone before transmission to the client. This removes the complication of setting the database's (possibly unknown) timezone at connection time via the DSN.

One promising option, is to set the connection's session timezone:

  • SET @@session.time_zone = "+00:00";
  • however, this only works for the current connection (within the connection pool). A go client however will not know which free connection they may be using at any give time.
  • So to ensure this always works, one would need to apply it manually before all queries. Even if only one DB connection is in use - if the connection fails and connection retry kicks in - any previous session state would be lost.

So instead, wrapping all datatime columns with a conversion function like so:

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

ensures the timezone calculation is done at query time and will not be lost during a connection reconnection etc.

So now the DSN no longer needs to specify loc - as UTC is the default. In fact the DSN only needs the suffix option of ?parseTime=true to allow the datetime to be translated into go's native time.Time.

Finally and most importantly, this will work with any server set to any timezone.

H/T to this answer.



来源:https://stackoverflow.com/questions/56397882/timezone-reconciliation-with-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!