How to handle MySQL timezone in script

不问归期 提交于 2019-12-31 03:45:29

问题


I am developing a mobile application. From the application calls are made to a web service which runs different queries based on mode (?mode=xx)

In some of those queries I use date functions like DATE(NOW()).

The data stored in the MySQL database is stored in GMT-7 (Mountain Time Canada).

I have yet to register a domain/host for this web service but when I do lets say it is hosted in a different city such as Toronto (which is GMT-5 - 2 hours ahead). Then at 10:05pm Mountain Time Canada a user uses the application to send a web request call which has a query like:

SELECT DATE(NOW()) 

Because the server is hosted in Toronto, that will return tomorrow's date, even though where the user is it is the day before and the application shows data based on the current day.

Anyone have any ideas on this?

Edit:

SYSTEM
2015-01-29 16:19:48
2015-01-29 23:19:48

is the result of running the query select @@time_zone, now(), utc_timestamp()

The queries deal with date (yyyy-mm-dd) and time (hh:mm:ss) column type.


回答1:


You ran this time-diagnostic query on your MySQL server.

select @@time_zone, now(), utc_timestamp()

It's clear from your local time and utc time that your server machine's system time zone setting is 'Canada/Mountain', and the MySQL server software doesn't have its own timezone setting.

If you pick up your tables and move them unchanged to a server in some nearby timezone, you can update your software always to issue the command

set time_zone = 'Canada/Mountain';

right after you connect from your software. This will make your new MySQL connection behave like your current one does time-zone-wise. If you own the MySQL server you can set its default time zone according to the directions on this page. http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

Now, here's the story about time data types. DATE, TIME, and DATETIME are all timezone-ignorant. Once you've stored a date/time value you'll get it back the same value even if you change your timezone settings.

The TIMESTAMP data type is timezone-sensitive. Those data items are always stored in UTC, also known as Z, time, formerly known as Greenwich Mean Time. They're always converted to UTC upon being stored, and always converted back upon being retrieved.

The builtin functions for getting current date and time (NOW() and friends) are timezone-sensitive. They'll yield values in local time. The exceptions are the three functions starting with UTC_ which yield values in UTC time.

Many MySQL multi-time-zone applications use the following operational discipline:

  1. Ask each user for a user-preference time zone, or figure it out from some other bit of personal data about the user. (Telephones have this information provisioned into them from the network.) Store that as a zoneinfo-friendly time zone descriptor ('America/New_York', 'Canada/Mountain', 'Europe/Vienna', etc) on the user's behalf.
  2. Upon establishing a MySQL session on behalf of the user, set the user's time zone with a set time_zone query like the one shown above. You should do this right after your connect operation.
  3. Store dates and times for users into TIMESTAMP data types. They'll get converted to UTC as they're stored.
  4. Retrieve them as needed. They'll get converted back to local time.

The idea is that your user's timezone is part of her context. This works well, because if user A is in Vancouver and user B in Halifax, and for some reason user B views user A's time data, it will be shown to B in Atlantic time more-or-less automatically.

It's also good because it deals transparently with the global vagaries of daylight-to-standard time changing. A timestamp from last summer will be displayed in last summer's local time.

Many managers of servers for global use set their system server time, or their MySQL default time zone, to UTC. (Yours doesn't.)

Another way to handle all this is the way in which you've started. Pick a time zone and store your timestamps with respect to that time zone. It's best if you pick a timezone that doesn't alternate between daylight and standard time in that case. Then, when storing times into the database, convert explicity. You'd store times from users in Ottawa by doing something like this.

INSERT INTO tbl (appt) VALUES ( 'whatever-time' - INTERVAL 120 MINUTE)

and you'd get the values out the same way. This is error-prone but you can make it work.

Finally, you can do your conversions yourself. If you want to know how many minutes of offset there are between some arbitary timezone and UTC, try these two queries.

set time_zone = 'Canada/Atlantic';
select timestampdiff(minute, utc_timestamp(), now());

At this time of year that gives back -240, which is -4:00. You need to use minutes rather than hours because of half-hour or quarter-hour timezone offsets in some countries.

Finally, watch out. TIMESTAMP data types don't represent times before 1970. And, on my MariaDB 10.0 instance it appears to go to hell in a bucket right after 2038-01-19T03:14:07 UTC when the time rolls over out of 32 bits.



来源:https://stackoverflow.com/questions/28226367/how-to-handle-mysql-timezone-in-script

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