问题
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