Actualización de tzdata en MySQL

Fabián Arias
LINETS Tech Talk
Published in
3 min readMar 8, 2013

Un problema que se nos ha vuelto común en esta época es la actualización de las Zonas Horarias de servidores, entre ellos servicios como MySQL.

Debido a que MySQL utiliza por omisión como time_zone a SYSTEM, es decir la zona horaria del sistema operativo, solo lo lee en el inicio de mysqld, lo que requiere reiniciar el servicio. Reiniciar un servidor de MySQL que se encuentra en producción está fuera de toda discusión, por lo que debemos hacerlo con el servidor en caliente. No todo está perdido, ya que existe una forma de hacerlo.

Para ello se debe activar una cualidad de MySQL que poco se usa que es la de utilizar las Zonas Horarias por su nombre en MySQL, lo que requiere cargar las tablas de time_zone en la base de datos “mysql” de MySQL.

Una vez que ya se tiene actualizada la tzdata del servidor, y por ende sus correspondientes archivos en /usr/share/zoneinfo en un Linux estándar, se deben transformar a SQL e insertarlos en las tablas correspondientes.

mysql_tzinfo_to_sql /usr/share/zoneinfo/ | mysql -p -uroot mysql

Con esto ya se tendrá actualizadas las tablas de time_zone en MySQL y se podrán utilizar directamente los nombres de las zonas horarias en el sistema. Y como extra, la actualización de las fechas de cambios horarios que como por estos días tenemos en Chile respecto a la DST.

Como ejemplo, acá tenemos un servidor que se le insertó la zoneinfo atrasada, sin las modificaciones realizadas al DST en Chile para esta semana:

mysql> SELECT CONVERT_TZ('2013-03-10 02:59:59','UTC', 'America/Santiago');
+-------------------------------------------------------------+
| CONVERT_TZ('2013-03-10 02:59:59','UTC', 'America/Santiago') |
+-------------------------------------------------------------+
| 2013-03-09 23:59:59 |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT CONVERT_TZ('2013-03-10 03:00:00','UTC', 'America/Santiago');
+-------------------------------------------------------------+
| CONVERT_TZ('2013-03-10 03:00:00','UTC', 'America/Santiago') |
+-------------------------------------------------------------+
| 2013-03-09 23:00:00 |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>

Podemos ver que en el cambio de horario que se debía realizar el 9 de Marzo hacia el 10 de Marzo, existe el cambio horario respecto de UTC, lo que es incorrecto.

En cambio, acá tenemos un servidor que ha sido actualizado respecto de la nueva data de zoneinfo con la corrección DST para el 28 de Abril:

mysql> SELECT CONVERT_TZ('2013-03-10 02:59:59','UTC', 'America/Santiago');
+-------------------------------------------------------------+
| CONVERT_TZ('2013-03-10 02:59:59','UTC', 'America/Santiago') |
+-------------------------------------------------------------+
| 2013-03-09 23:59:59 |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT CONVERT_TZ('2013-03-10 03:00:00','UTC', 'America/Santiago');
+-------------------------------------------------------------+
| CONVERT_TZ('2013-03-10 03:00:00','UTC', 'America/Santiago') |
+-------------------------------------------------------------+
| 2013-03-10 00:00:00 |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>

En este caso, no se cambia la hora el 9 de Marzo hacia el 10 de Marzo, sino cuando corresponde, que es el 28 de Abril.

mysql> SELECT CONVERT_TZ('2013-04-28 02:59:59','UTC', 'America/Santiago');
+-------------------------------------------------------------+
| CONVERT_TZ('2013-04-28 02:59:59','UTC', 'America/Santiago') |
+-------------------------------------------------------------+
| 2013-04-27 23:59:59 |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT CONVERT_TZ('2013-04-28 03:00:00','UTC', 'America/Santiago');
+-------------------------------------------------------------+
| CONVERT_TZ('2013-04-28 03:00:00','UTC', 'America/Santiago') |
+-------------------------------------------------------------+
| 2013-04-27 23:00:00 |
+-------------------------------------------------------------+
1 row in set (0.00 sec)
mysql>

Finalmente solo nos falta configurar la variable global "time_zone" a "America/Santiago".

mysql> SET GLOBAL time_zone="America/Santiago";
Query OK, 0 rows affected (0.00 sec)
mysql>

Con esto, estamos con un servidor correcto, en producción.

--

--

Fabián Arias
LINETS Tech Talk

Commercial Engineer, Economist, IT Consultant, Open Source Advocate, Sysape, not a window cleaner and all around good guy.