How to handle MySQL timezone in script

前端 未结 1 763
余生分开走
余生分开走 2021-01-24 08:13

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

1条回答
  •  北海茫月
    2021-01-24 08:29

    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.

    0 讨论(0)
提交回复
热议问题