90

Can MySQL convert a stored UTC time to local time-zoned time directly in a normal select statement?

Let's say you have some data with a timestamp (UTC).

CREATE TABLE `SomeDateTable` (
  `id`    int(11) NOT NULL auto_increment,
  `value` float NOT NULL default '0',
  `date`  datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`)
)

Then when I

"select value, date from SomeDateTable";

I of course get all the dates as in their stored UTC form.

But let's say that I would like to have them in another timezone (with DST), can I then add some magic to the select query so that I get all the dates back in the selected timezone?

"select value, TIMEZONE(date, "Europe/Berlin") from SomeDateTable";

Or must I do this in some other layer on top, like in some php code? (it seems to be how most people have solved this problem).


If your MySQL installation allows you to use CONVERT_TZ it is a very clean solution, this example shows how to use it.

SELECT CONVERT_TZ( '2010-01-01 12:00', 'UTC', 'Europe/Stockholm' )

However I don't know if this is a good way since some MySQL installation is missing this function, use with care.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
Johan
  • 20,067
  • 28
  • 92
  • 110

6 Answers6

61

Yup, there's the convert_tz function.

ashleedawg
  • 20,365
  • 9
  • 72
  • 105
Stephen Fischer
  • 2,445
  • 2
  • 23
  • 38
  • 1
    Seems to be the correct thing but I hit this bug directly: http://bugs.mysql.com/bug.php?id=12445 my server was missing timezone data... – Johan Feb 02 '10 at 21:27
  • 10
    mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql – Johan Feb 02 '10 at 21:33
39

For those unable to configure the mysql environment (e.g. due to lack of SUPER access) to use human-friendly timezone names like "America/Denver" or "GMT" you can also use the function with numeric offsets like this:

CONVERT_TZ(date,'+00:00','-07:00')
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
tmsimont
  • 2,651
  • 2
  • 25
  • 36
  • 9
    That will not work if that timezone has Daylight saving time (http://www.timeanddate.com/time/dst/) since you will have different offset sommer and winter, and there is also some examples with 30min DST... – Johan Sep 02 '13 at 14:57
  • interesting.. in my case I have to run a few queries from PHP and don't want to do any TZ handling with the results in PHP, but I could easily alter the numeric value in the select query. thanks – tmsimont Sep 03 '13 at 15:40
21

One can easily use

CONVERT_TZ(your_timestamp_column_name, 'UTC', 'your_desired_timezone_name')

For example:

CONVERT_TZ(timeperiod, 'UTC', 'Asia/Karachi')

Plus this can also be used in WHERE clause to compare after the timezone is converted (but its always better to just compare in UTC timezones and convert to local timezone while displaying the timestamp)

WHERE CONVERT_TZ(timeperiod, 'UTC', {$this->timezone}) NOT BETWEEN {$timeperiods['today_start']} AND {$timeperiods['today_end']}
MR_AMDEV
  • 1,712
  • 2
  • 21
  • 38
  • 1
    When I did your "WHERE CONVERT_TZ" query in mysql, it did a whole table scan even though I used an indexed column for my 'timeperiod' and absolute timestamp values for 'Between start and end'. I've read that it's generally not a good idea to use column functions in a 'WHERE' or 'HAVING' clause. – McAuley Feb 13 '20 at 04:56
  • You could be right but on the other side, if you donot use it in where class then how we are going to compare values? – MR_AMDEV Apr 25 '20 at 12:18
  • Good point, and the only suggestion I have for that is to be very careful with the WHERE clause in order to minimize/mitigate tablespace scans. Partitioning the table on 'timeperiod' might be helpful in that area. Or, the server-side language could be used to do timezone conversion, but that's probably getting out of the realm of the OP's question. – McAuley Apr 28 '20 at 21:29
13
select convert_tz(now(),@@session.time_zone,'+03:00')

For get the time only use:

time(convert_tz(now(),@@session.time_zone,'+03:00'))
Giacomo1968
  • 25,759
  • 11
  • 71
  • 103
Jestin
  • 578
  • 5
  • 10
8

1. Correctly setup your server:

On server, su to root and do this:

# mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql

(Note that the command at the end is of course mysql , and, you're sending it to a table which happens to have the same name: mysql.)

Next, you can now # ls /usr/share/zoneinfo .

Use that command to see all the time zone info on ubuntu or almost any unixish server.

(BTW that's the convenient way to find the exact official name of some time zone.)

2. It's then trivial in mysql:

For example

mysql> select ts, CONVERT_TZ(ts, 'UTC', 'Pacific/Tahiti') from example_table ;
+---------------------+-----------------------------------------+
| ts                  | CONVERT_TZ(ts, 'UTC', 'Pacific/Tahiti') |
+---------------------+-----------------------------------------+
| 2020-10-20 16:59:57 | 2020-10-20 06:59:57                     |
| 2020-10-20 17:02:59 | 2020-10-20 07:02:59                     |
| 2020-10-20 17:30:08 | 2020-10-20 07:30:08                     |
| 2020-10-20 18:36:29 | 2020-10-20 08:36:29                     |
| 2020-10-20 18:37:20 | 2020-10-20 08:37:20                     |
| 2020-10-20 18:37:20 | 2020-10-20 08:37:20                     |
| 2020-10-20 19:00:18 | 2020-10-20 09:00:18                     |
+---------------------+-----------------------------------------+
Fattie
  • 27,874
  • 70
  • 431
  • 719
3

I propose to use

SET time_zone = 'proper timezone';

being done once right after connect to database. and after this all timestamps will be converted automatically when selecting them.

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • 16
    Important to note that this will not automatically convert DATE, TIME, and DATETIME fields. This will only do automatic conversions for TIMESTAMP fields and affect the results of NOW() and CURDATE() functions. – Tom May 19 '12 at 03:28
  • If you want this to be permanent, you can also change the time_zone parameter. – jamsandwich Nov 27 '17 at 03:35