To set the MySQL timezone to UTC without privilege:
SET SESSION time_zone = '+0:00'
to read the timezone which currently applies to NOW(), FROM_UNIXTIME(),
UNIX_TIMESTAMP(), and the implicit conversion done when reading and
writing columns of the TIMESTAMP type:
SELECT @@session.time_zone
do not use the magic timezone name 'SYSTEM' anywhere, because if you have
used 'SET SESSION time_zone' then you are not operating under 'SYSTEM'
timezone. For example CONVERT_TZ(, 'SYSTEM', @@session.time_zone)
is no longer a no-op in that case.
to write a UNIX timestamp into a DATETIME column in UTC, regardless of the
session timezone:
CONVERT_TZ(FROM_UNIXTIME(%ld), @@session.time_zone, '+0:00') (**note)
to write the same to a TIMESTAMP column, instead of a DATETIME column:
FROM_UNIXTIME(%ld)
to write the present time to a DATETIME column in UTC, regardless of the
session timezone:
CONVERT_TZ(NOW(), @@session.time_zone, '+0:00') (**note)
to write the same to a TIMESTAMP column:
NOW()
to read a UNIX timestamp out of a DATETIME column stored in UTC:
UNIX_TIMESTAMP(CONVERT_TZ(column, '+0:00', @@session.time_zone)) (**note)
to read a UNIX timestamp out of a TIMESTAMP column:
UNIX_TIMESTAMP(column)
to read a date and time, in UTC, pretty-printed by MySQL, out of a DATETIME
column stored in UTC:
SELECT column
to read the same date out of a TIMESTAMP column:
SET SESSION time_zone = '+0:00'
SELECT column
it is not possible to use CONVERT_TZ to read a TIMESTAMP column. You
_have_ to set the session time_zone instead. You'd think CONVERT_TZ
would work, but AFAICT passing @@session.time_zone as an argument to
CONVERT_TZ works on INSERT but does not work on SELECT.
summary:
If you don't want to set the MySQL process's timezone to UTC (even just
for the session), then this should be safe and correct:
* use only TIMESTAMP columns
* move all data in and out of the database exclusively using
FROM_UNIXTIME() and UNIX_TIMESTAMP() coercion
If you care about leap seconds, and understand leap seconds and the difference
between UTC, TAI, and GMT:
http://en.wikipedia.org/wiki/UNIX_time#Non-synchronous_Network_Time_Protocol-based_variant
and for some reason believe that MySQL will actually store leap seconds in
a column, calculate intervals including leap seconds magically solving the
impossiblity of doing this six months into the future, and you believe NOW()
will sometimes return 23:59:60, and in spite of the lack of documentation about
all this you believe the whole thing will cooperate with
your overall application to handle leap seconds (i.e., you never ask the
kernel for the present time with a syscall instead you SELECT NOW(), or if you
ask the kernel you ask with ntp_gettime() and pay attention to the return code
not just the ntptimeval, and you have some magical library that takes (returncode,
ntptimeval) and translates it into SQL time or user-presentable time, and
you think it will work to roll your clock back to before a leap second to test
this whole monster (I don't), and you are loading fresh leap second data into
both MySQL and your Unix (returncode, ntptimeval) pretty-printing library at
least twice a year, then:
* you must set the session time_zone to UTC.
* once you've done that, you must read/write the database
with SQL time representation, never using FROM_UNIXTIME() or
UNIX_TIMESTAMP().
* you should probably use TIMESTAMP columns, but DATETIME columns
should also work if the time_zone stays UTC. If you touch the
database from outside your app, for example you try to put NOW()
into such a column from phpMyAdmin with time_zone local, that will
be wrong if you used DATETIME and right if you use TIMESTAMP.
If you want to use DATETIME columns without setting the session time_zone,
* change your mind. There is no way to make a DATETIME column
unambiguously represent the hour between 1 and 2am each fall in
timezones that have summer time. This is (**note).
* If you choose to have a DATETIME column but store it as UTC
instead of storing local time like MySQL expects you to be doing,
then you must accomplish this using 'SET SESSION time_zone' to
avoid the summertime problem above. If you use CONVERT_TZ
anywhere to accomplish this goal, you will have the summer
time 1 - 2am ambiguity problem.
* It is not an issue of ``using the same timezone everywhere.''
It is not merely a matter of the database being tied to a
particular local timezone without having that local timezone
stored inside the database, so problems arise from
the inelegance of the database on its own not fully representing
your data until you unlock it with the secret key---knowledge of
the local timezone. And it's not a matter of avoiding messy
implicit conversions---passing local time on the interface between
application and MySQL when both app and MySQL are dealing
internally in UTC, which can go awry every time the timezone rules
change if the querying application and MySQL itself do not have
the same tzinfo dataset which is quite likely. EVEN IF ALL THESE
THINGS WERE TAKEN CARE OF by some extremely meticulous person, you
would STILL have the summertime ``fall back'' issue above. You
simply cannot use DATETIME at all.
* Do not talk to me about leap seconds when there is one hour each
year that you cannot handle at all.