La hora de MySQL se puede ver afectada por los cambios que los entes gubernamentales hacen a la hora local de los países pero también por la necesidad que tienen algunas regiones de adelantar o retrasar su hora dependiendo de la época del año para aprovechar la luz del día.
Lo ideal en estas situaciones es que MySQL haga el cambio del día y hora de forma automática, esto viene dado por la utilización de las zonas horarias (time zones en inglés). MySQL mantiene una serie de tablas en la base de datos mysql para almacenar esta información: time_zone, time_zone_name, time_zone_leap_second, time_zone_transition, y time_zone_transition_type.
Cargar la información de las zonas
Durante la instalación MySQL no carga información alguna en dichas tablas, puedes comprobarlo haciendo la siguiente consulta:
MariaDB [(none)]> SELECT COUNT(*) FROM mysql.time_zone_name; +----------+ | COUNT(*) | +----------+ | 0 | +----------+
Si tu sistema operativo soporta la base de datos zoneinfo
, el cual es un conjunto de archivos binarios que describen la información de las zonas, lo recomendable es cargarlas con la utilidad mysql_tzinfo_to_sql. Ejemplos de tales sistemas son: Linux, MacOS en algunas versiones, FreeBSD, Solaris. Ellos por lo general la mantienen en el directorio /usr/share/zoneinfo
.
Puede ser que la ruta no coincida en tu sistema operativo así que todavía puedes intentar con el siguiente comando para determinar su ubicación:
ls -la /etc/localtime lrwxrwxrwx 1 root root 37 oct 16 09:29 /etc/localtime -> ../usr/share/zoneinfo/America/Caracas
Ahora procedemos a indicarle la ubicación a la utilidad mysql_tzinfo_to_sql
para cargar todas las zonas disponibles allí. La utilidad genera un script SQL así que debemos usar el comando pipe para que estas instrucciones se ejecuten desde MySQL y llenen las tablas adecuadas, el comando de consola es el siguiente:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -uroot -p mysql
Comprueba que has tenido éxito, repitiendo la consulta de las zonas y deben tener una cuenta mayor que cero. Después de esto es necesario que reinicies el servidor MySQL para que tome los cambios.
Si tu sistema operativo no ofrece soporte para zoneinfo sino que tiene una base de datos de zonas propia tal como Windows, entonces debes usar un script que contiene las instrucciones SQL que permiten cargar las tablas con la información más reciente de la base de datos de zoneinfo.
- El procedimiento para cargar las tablas varía ligeramente:
- Descarga el script desde
https://dev.mysql.com/downloads/timezones.html
- Escoge el archivo que contenga el sufijo sql en su nombre de archivo o
file_name
Por ejemplo :timezone_2019c_posix_sql.zip
- Desempaquétalo
- Carga las tablas con la siguiente instrucción:
mysql -u root -p mysql < file_name
Ver los nombres de las zona en zoneinfo
En el directorio donde está la base de datos zoneinfo puedes ver las zonas disponibles. Puedes determinar el nombre de una zona mediante su path relativo, por ejemplo: America/Caracas
, US/Eastern
. Como puedes imaginar, generalmente antepones el nombre del continente seguido por el nombre de la ciudad excepto en aquellos casos como Brazil
, US
que contienen varias zonas.
Si no posees la base de datos zoneinfo puedes encontrar el nombre de una zona haciendo la consulta directamente en las tablas de MySQL, por ejemplo:
MariaDB [(none)]> SELECT * FROM mysql.time_zone_name WHERE name LIKE '%Caracas'; +-----------------------+--------------+ | Name | Time_zone_id | +-----------------------+--------------+ | America/Caracas | 90 | | posix/America/Caracas | 697 | | right/America/Caracas | 1304 | +-----------------------+--------------+
Consultar la información en zoneinfo
Puesto que son archivos binarios la información debe ser consultada con una utilidad, en Linux es zdump
:
Veamos un ejemplo simplificado para el año 2019 en Europe/Madrid
:
zdump -v Europe/Madrid | grep 2019 Europe/Madrid Sun Mar 31 00:59:59 2019 UT = Sun Mar 31 01:59:59 2019 CET isdst=0 gmtoff=3600 Europe/Madrid Sun Mar 31 01:00:00 2019 UT = Sun Mar 31 03:00:00 2019 CEST isdst=1 gmtoff=7200 Europe/Madrid Sun Oct 27 00:59:59 2019 UT = Sun Oct 27 02:59:59 2019 CEST isdst=1 gmtoff=7200 Europe/Madrid Sun Oct 27 01:00:00 2019 UT = Sun Oct 27 02:00:00 2019 CET isdst=0 gmtoff=3600
Puedes apreciar claramente el inicio del horario de verano CEST con el cambio de las dos primeras líneas en el campo isdst=1 (es DST igual a verdadero) el 31 de Marzo de 2019 a las 2:00 de la madrugada en el horario de invierno o CET. También puedes ver la hora correspondiente en UTC, y el desplazamiento de UTC en segundos en el campo gmtoff (gmt offset).
Comprobar un cambio de hora legal
Veamos el cambio más reciente en Venezuela, haré la consulta de la base de datos en Linux pero si no es tu caso con revisar el anuncio del cambio de hora en tu país será suficiente.
zdump -v America/Caracas | grep 2016 America/Caracas Sun May 1 06:59:59 2016 UT = Sun May 1 02:29:59 2016 -0430 isdst=0 gmtoff=-16200 America/Caracas Sun May 1 07:00:00 2016 UT = Sun May 1 03:00:00 2016 -04 isdst=0 gmtoff=-14400
Lo que interesa es demostrar que MySQL está preparado para el cambio del día domingo 1ro de Mayo de 2016 a las 2:30 de la madrugada. Para lo cuál utilizaré la función CONVERT_TZ
en la siguiente instrucción:
SELECT CONVERT_TZ('2016-05-01 02:30:00', 'America/Caracas', 'America/Caracas') AS time1, CONVERT_TZ('2016-05-01 03:00:00', 'America/Caracas', 'America/Caracas') AS time2; +---------------------+---------------------+ | time1 | time2 | +---------------------+---------------------+ | 2016-05-01 03:00:00 | 2016-05-01 03:00:00 | +---------------------+---------------------+
El resultado debe ser el mismo para que la comprobación sea exitosa.
Pasada esa fecha ya no hay más ajuste de hora legal por lo tanto la hora debe cambiar porque son momentos diferentes, por ejemplo:
SELECT CONVERT_TZ('2016-05-01 03:30:00', 'America/Caracas', 'America/Caracas') AS time1, CONVERT_TZ('2016-05-01 04:00:00', 'America/Caracas', 'America/Caracas') AS time2; +---------------------+---------------------+ | time1 | time2 | +---------------------+---------------------+ | 2016-05-01 03:30:00 | 2016-05-01 04:00:00 | +---------------------+---------------------+
Comprobar un cambio DST
Verificaremos que MySQL está preparado para hacer el cambio de la hora para ello haremos un ejemplo cuando de inicio el horario de verano en España:
SELECT CONVERT_TZ('2019-03-31 02:00:00', 'Europe/Madrid', 'Europe/Madrid') AS time1, CONVERT_TZ('2019-03-31 03:00:00', 'Europe/Madrid', 'Europe/Madrid') AS time2; +---------------------+---------------------+ | time1 | time2 | +---------------------+---------------------+ | 2019-03-31 03:00:00 | 2019-03-31 03:00:00 | +---------------------+---------------------+
Observa que no hay diferencia entre la hora a las 2:00 que a las 3:00.
Mantener actualizada la información de las zonas
Tu sistema operativo debe proporcionar una actualización o service pack para mantener la hora de tu sistema actualizada de forma regular.
En linux, debes hacerlo actualizando el paquete tzdata:
sudo apt-get update
sudo apt-get upgrade tzdata
Este paquete se encarga de descargar las actualizaciones que tiene la base de datos zoneinfo
.
Cada vez que tengas necesidad de actualizar las zoneinfo también es necesario que vuelvas a repetir el procedimiento de carga de la información de las zonas horarias de MySQL para que se mantenga sincronizada con la de tu sistema operativo.
Espero que este post te haya proporcionado suficiente información para resolver el problema de mantener actualizada la hora del reloj de tu servidor MySQL ante los cambios de hora legal y DST, pero si estás interesado en profundizar aún más tus conocimientos sobre el manejo de SQL te recomiendo que veas nuestro libro Aprende SQL de Styde donde encontrarás unos 20 capítulos que aumentarán tu confianza al momento que tengas que afrontar proyectos que requieran del manejo de base de datos.
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.