sábado, 8 de marzo de 2008

PHP y las zonas horarias

Abstract
Debido a la modificación del cambio de horario en Chile para este año 2008 que traslada el término de horario de verano desde la noche del 8 de marzo hacia la noche del 29 de marzo, nos hemos topado con la necesidad de corregir nuestros sistemas para que se adapten a este cambio.

En LINUX, la solución más apropiada es la actualización manual de la definición de la zona horaria America/Santiago o (idealmente) la actualización del paquete tzdata (una vez que hayan publicado la actualización correspondiente).

Sin embargo, algunos software como por ejemplo PHP y JAVA mantienen su propia información de zona horaria (zoneinfo) por lo que ingnorarán las reglas que tenga definido el sistema operativo. Esto significa que -aunque yamos parchado nuestro sistema operativo- mantendrán el problema del cambio de hora.


Solución para PHP
PHP desde la versión 5.1 mantiene su propia base de datos de zona horaria por lo que ignorará las reglas de zona horaria definidas en el Sistema Operativo. La solución a este problema es la actualización del módulo timezonedb incluido con PHP. Lamentablemente al 8 de marzo de 2008 la versión más reciente de timezonedb no incluye la actualización a la zona horaria America/Santiago por lo tanto tendremos que parchar el módulo antes de instalarlo.

Gestión de módulos en PHP mediante PECL
PHP está compuesto por un core llamado Zend Engine y un subconjunto de módulos que le agregan funcionalidades como manejo de strings, manejo de fechas, soporte a sesiones, etc. El conjunto de módulos adicionales de PHP se llama PECL.

Es posible agregar módulos PECL adicionales que no vienen incluidos en la distribución original mediante el comando pecl el cual viene en el paquete php-devel.

En las distribuciones RedHat y sus derivados (Fedora Core, CentOS, etc.) la instalación de paquetes se puede realizar con el comando yum, el cual utilizaré como ejemplo en este artículo. En otras distribuciones existen otros gestores de paquetes y los nombres de los paquetes podrían variar.

En caso que no tengamos el paquete php-devel, lo instalamos con el comando:
yum install php-devel
Ahora que contamos con el comando phpize, el procedimiento para instalar cualquier módulo PECL es el siguiente:
pecl instal nombre_paquete
Por lo tanto, para instalar el módulo timezonedb se ejecutaría el siguiente comando
pecl install timezonedb
Sin embargo, tal como indiqué al principio, esto no resolverá el problema porque en este momento (8 de marzo de 2008), este módulo aún no incorpora la actualización para America/Santiago.

Actualizado: Hace algunos días publiqué un bug en el sitio de PHP y se acaba de liberar la versión de timezonedb que actualiza la zona horaria para America/Santiago, por lo que desde ahora ya no es necesario realizar los pasos que indico en "Instalar módulo timezonedb parchado" sino que simplemente se debe ejecutar el comando indicado a continuación y luego seguir con los pasos indicados más abajo en "Habilitando extensión":
pecl install timezonedb


Instalar módulo timezonedb parchado
El procedimiento a seguir es descargar los fuentes de timezonedb (que están en lenguaje C), modificar la definición de la zona America/Santiago y luego agregar el módulo a PHP. Este procedimiento requiere de conocimientos básicos del lenguaje C.

En primer lugar descargamos los fuentes mediante:
pecl download timezonedb
Esto descargará un archivo con la versión más reciente del módulo que en mi caso fue timezonedb-2007.11.tgz. Lo descomprimimos y entramos al directorio recien creado:
tar xfz timezonedb-2007.11.tgz
cd timezonedb-2007.11
El archivo timezonedb.h es el que contiene la información de las zonas horarias. He publicado una versión parchada que contiene la información actualizada para America/Santiago en base a la versión timezonedb-2007.11. A contnuación descargamos y descompriminos el archivo.
wget http://www.joserodriguez.cl/blog/2008/03/timezonedb.h.gz
gunzip timezonedb.h.gz
Luego, estamos en condiciones de compilar el módulo ejecutando los siguientes comandos:
phpize
./configure
make
Luego, como usuario root, instalamos el módulo.
make install


Habilitando extensión

Habilitamos la extensión en el archivo php.ini el cual usualmente se encuentra en /etc/php.ini. En algunas distribuciones tales como UBUNTU existen dos archivos php.ini, ambos deben ser actualizados.
echo "extension=timezonedb.so" >> /etc/php.ini


Validando instalación
Para verificar que la actualización funcione correctamente podemos ejecutar el siguiente script:
<?php

f(1204988400);
f(1205074800);
f(1206802800);
f(1206889200);

function f($time) {
echo date("Y-m-d G:i:s O e I\n", $time);
}

?>
Cuya salida debería ser la siguiente:
2008-03-08 12:00:00 -0300 America/Santiago 1
2008-03-09 12:00:00 -0300 America/Santiago 1
2008-03-29 12:00:00 -0300 America/Santiago 1
2008-03-30 11:00:00 -0400 America/Santiago 0
En caso que ocurra algún error fatal al ejecutar PHP, como por ejemplo segmentation fault, se puede deshabilitar la extensión eliminando la línea recien agregada a php.ini.

Actualizado el 16 de marzo de 2008.

3 comentarios:

Anónimo dijo...

Sabes como corregir este problema en Java?

Alejandro Garcia dijo...

muy bueno amigo pero sabe como lo hago para windows

Javier Reinoso dijo...

Una pregunta que quizas te parecera tonta, pero yo tengo un hosting, y en ese hosting me fallan algunas zonas horarias, por ejemplo:

http://www.astrodreams.com/testphp/gettzwithtzname.php?zonename=Asia/Ho_Chi_Minh

Pero en casi todas me va bien, como en esta:

http://www.astrodreams.com/testphp/gettzwithtzname.php?zonename=Asia/Hong_Kong

Ese error se soluciona instalando las

http://pecl.php.net/package/timezonedb

???

Y una pregunta que em harias un gran favor si me la contestas:

Ese cambio lo debe de hacer la empresa de hosting o yo propiamente en mi propio hosting???

Yo soy spanish, pero vivi 4 años en chile, y tengo un excelente recuerdo de alli!!!

Un saludo sincero...