问题
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:
- 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.
- 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 yourconnect
operation. - Store dates and times for users into
TIMESTAMP
data types. They'll get converted to UTC as they're stored. - 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