-
Notifications
You must be signed in to change notification settings - Fork 161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix storage of time.Time objects with non-local timezones in DATETIME columns. #77
base: master
Are you sure you want to change the base?
Conversation
… MySQL server. Before this change, storing a time.Time object with a non-local timezone in a database and then retrieving the object again resulted in a time.Time object denoting a different point in time. Example: the time "2013-08-09 21:30:43 +0800 CST" was stored in a DATETIME column of the database as "2013-08-09 21:30:43". Reading the value back resulted in "2013-08-09 21:30:43 +0100 BST". This commit fixes the problem by always converting time.Time objects to the local timezone before sending them to the MySQL server.
This is known MySQL issue. The problem is that DATETIME type doesn't contain any information about timezone. Your patch fixes your problem but introduces issues in code that relies on current godrv behavior. Current behavior:
Unfortunately database/sql doesn't provide any functionality to specify timezone for retrieved dates. I think that for now I can add some workaround to the godrv to specify default timezone, other than local. This doesn't solve the problem but maybe useful for most applications and doesn't break any of existing ones. mymysql native interface does this better. |
Dear Michał, On 13 Aug 2013, at 13:45, Michał Derkacz notifications@github.com wrote:
The problem with this is that on storage the information about timezone is just dropped, and on load the timezone is assumed to be the local timezone. Result: if you store a date with a non-local timezone and read it back, you get a time.Time object representing a different point in time (i.e. the .UnixNano values are different). What I would expect is, that only information about the timezone is lost, but that I get back the same point in time. The unit test I added checks for this.
Having a way to tell mymysql which timezone the values in the database should be stored in would be great! But I think this is a separate issue from the not-getting-the-right-time-back issue above. What do you think? All the best, Jochen |
I may have misunderstood what you wrote: there are two timezones which could be customisable:
When you wrote " I think that for now I can add some workaround to the godrv to specify default timezone, other than local", which of the two possibilities did you mean? |
I mean following rule:
So if your whole application works in some timezone, set this timezone only for retrieved dates will be enough. Dates presentation will be equal in Go and in MySQL so you can easy examine dates in database using any tool. If you have dozen of applications that work worldwide in different timezones, you need to rethink how to handle timezones correctly. I think that godrv should work transparently and doesn't try to fix this MySQL issue in any specific way. This is especially important in complicated an heterogeneous environment where database is used not only by Go programs. In such environment you need to develop some uniform standard to treat dates in MySQL and implement it in any application you use. |
Hi Michał, On 14 Aug 2013, at 11:42, Michał Derkacz notifications@github.com wrote:
Oh, I see, that's a possible plan. An alternative would be to use a fixed time zone for the values in the database column and convert on storage retrival. Advantage of simply dropping the timezone information:
Advantages of using a fixed timezone for storage:
I think both methods are valid approaches, but for my own use Would you be willing to take a patch which optionally converts
Yes, this sounds good to me (and local timezone is all I need All the best, Jochen |
I think that it is possible to add optional timezone for stored datetimes. By default it will be nil, which means drop timezone (current behavior). Default timezone can be a global godrv variable or it can be per connection variable. The first approach is easier to implement (only for godrv) but second can be more efficient and also useful for users of mymysql native interface. Now and for next three weeks I have a holidays so I don't want to code to much. But you are welcome to send me a pull request that I'll try review if my Internet connection will be good enough. |
Hi Ziutek, I've had a go at implementing your suggestion, looking forward to hear what you think. The new pull request is in #80 and replaces the one I suggested here. Some comments:
Please let me know if anything needs fixing, I'd be happy to change things if you spot anything wrong or too ugly. All the best, PS.: happy holidays! (and I'll also be mostly away for the next two weeks or so) |
There was dozen of things that wait for me after my holidays. Now I have some time to try review your changes Jochen. I think that there isn't a good idea to add timezone information to the pktReader. I think that timezone should be handled at upper layer. We have two function for obtain time from a row: (Row.Time, where you specify a location, and Row.Localtime, which assumes local location). I don't want to introduce next function. Instead, there can be added something like Conn.SetLocalLocation(l *time.Location) that will change location used by default. |
I think that this problem can't be fixed at mymysql.Conn level without broke current behavior because of mysql.Row definition. It is defined as an ordinary slice ([]interface{}) so there is no place for any timezone information for text results (text results contains only text dates/times as returned by server). It seems to be inconvenient to use some global variable for timezone in mymysql.native because it forces users to directly use mymysql.native (or mysql.thrsafe) variables/functions, but this package is intended to be only an engine for mymysql.mysql. We can get around this problem by add mymysql.location package that will be imported by all packages that need obtain/change location but it seems to be not a good idea. For other direction (queries sent to the server) text queries are formatted using fmt.Sprintf function. We can use reflection to find all time.Time in query parameters and change its location but this seems to be something confusing for users because they obtain different results from following commands: c.Query("select * from T where d > '%s'", t) q := fmt.Sprinf("select * from T where d > '%s', t) I think that we should concentrate to found solution only for godrv which doesn't provide any functionality for different timezones and leave current behavior in mymysql. It probably needs some support from mymysql.native to not sacrifice performance. |
Just to let you know: term started and I'm to busy at the moment to look into this. Maybe somebody else can have a go? Or maybe I'll get back to this when times are quieter ... |
In the worst case the application knows about a timezone variable it stores in the database. The app may need to be conscious of this anyway for user forms. The app has to get the user (customer) location somehow. There is a net-wide timezone database that can be used that is reliable. Store UTC time, ignoring Daylight saving time (summer time) and store the timezone, and maybe store summer time rules. Do this automatically as is easy to implement, document it and give examples of usage. Don't even think about Antarctica or the Mars colonies. Maybe we'll be dead by the time the Mars colonies get going. If there is more than one colony, make sure they're in the same timezone. Better yet, beat on Oracle and the Mariadb people to fix their damn database. Rubber hoses only, please. The fools have Unicode but not timezones — do they think the earth is flat? |
Also:
|
Storing time.Time objects with non-local timezones in DATETIME columns didn't work with the mymysql driver: when the value was stored, timezone information was simply ignored; when the value was retrieved, it was assumed to be local time. This commit fixes the problem, by converting all time.Time objects to the local timezone before sending them to the MySQL server.
I've included a test case to illustrate the problem and to verify that the problem is fixed by my change.