Akelos : Time Zones

Primero tenemos que tener en cuenta que debemos activar “getters” and “setters”, que son metodos con los cuales podemos procesar los atributos de un objeto, antes de grabarlos o llamarlos. Para activar getters and setters debe escribir la siguiente linea en config.php:

define(‘AK_ACTIVE_RECORD_ENABLE_AUTOMATIC_SETTERS_AND_GETTERS’, true);

Para manejar TimeZones, debemos tener un punto de referencia absoluto, por eso vamos a guardar todas las fechas en GMT y formato datetime (SQL), lo guardamos en formato datetime y no timestamp para aprovechar las funciones SQL (tipo DateAdd o Datediff dependiendo de la plataforma)  y para mayor entendimiento en caso de una revision visual de la base de datos.

Hay que tener en cuenta que la conversion de fechas solo lo haremos desde el servidor, osea no vamos a cambiar nada en la base de datos, solo definir campos datetimes.

Para convertir una fecha a GMT necesitamos 2 variables, la FECHA y el TIMEZONE del usuario y lo mismo si queremos convertir la fecha GMT (sacada de la base de datos) al Timezone del usuario. Akelos viene integrado con una clase muy util llamada AKTimeZone, esta clase nos ayudara a facilitar el proceso.

Entonces lo primero que tenemos que hacer es llamar a la clase AKTimeZone e inicializar un objeto AKTimezone que nos ayudara a hacer las conversiones.

Vamos al archivo shared_model.php y incluiremos la clase AKTimezone y para inicializar el objeto lo haremos dentro del metodo init(). Hay que tener en cuenta que cuando incluimos la clase AKTimezone automaticamente cambia el timezone del sistema a GMT.

require_once(AK_LIB_DIR.DS.’AkLocalize’.DS.’AkTimeZone.php’);
require_once(AK_LIB_DIR.DS.’AkActiveRecord.php’);

class ActiveRecord extends AkActiveRecord
{
var $my_timezone;

function init($attributes)
{

if(@empty($_SESSION[‘timezone’][‘name’])) $_SESSION[‘timezone’][‘name’] = ‘UTC’;
$_AkCurrentZone = new AkTimeZone();
$this->my_timezone =& $_AkCurrentZone->create($_SESSION[‘timezone’][‘name’]);

return parent::init($attributes);

}

Ten en cuenta que debes tener a la mano el Timezone del usuario en este caso yo lo tengo en la variable $_SESSION[‘timezone’][‘name’], con esto ya puedes crear el objeto que nos ayudara para las conversiones.

Dado que AKTimezone configura el sistema en GMT, no es necesario crear ningun metodo para guardar en GMT las fechas generadas por created_at o updated_at.

Lo que si tenemos que hacer es crear un Getter para cada fecha GMT que queremos mostrar con el Timezone del usuario actual. Aqui un ejemplo de mostrar created_at en el Timezone actual del usuario, fijate que el getter debe ser escrito de manera CamelCase.

function getCreatedAt(){
$var = $this->created_at;
$converted = gmmktime(substr($var,11,2),substr($var,14,2),substr($var,17,2),substr($var,5,2),substr($var,8,2),substr($var,0,4));
return gmdate(“Y-m-d H:i:s”,$this->my_timezone->adjust($converted));//my time
}

Para llamar un getter en el View hay 2 formas, presta atención que los getters and setters solo son ejecutados con este tipo de llamadas:

$sale->get(‘created_at’)
{sale.created_at?}

Este tipo de llamada NO activaran los getters and setters:

$sale->created_at

En el caso que tengamos un campo en un formulario, donde el usuario ingresa una fecha, tenemos que convertir la fecha ingresada a GMT y despues ajustarla usando el Timezone del usuario, pero esto lo haremos solo cuando vaya a ser grabado en la base de datos. Aqui un ejemplo suponiendo que el campo se llame “user_input_date” :

function beforeSave(){
$var = $this->user_input_date;
$converted = gmmktime(substr($var,11,2),substr($var,14,2),substr($var,17,2),substr($var,5,2),substr($var,8,2),substr($var,0,4));
 $this->user_input_date = gmdate(“M d Y H:i:s”,$this->my_timezone->unadjust($converted));
return true;
}

Y con esto cubrimos el manejo de zonas horarias (Time Zones) en akelos.

Extendido

1. Si estas preocupado por TimeZones con DST, no debes tener preocupaciones, la clase AKTimeZone deja que el sistema operativo se encargue de dar el “offset” correcto para el timezone usado, osea tu única preocupación es que el sistema operativo del servidor tenga sus librerias de zonas horarias actualizadas.

2. $_SESSION[‘timezone’][‘name’] contiene el nombre del timezone (ejm: America/Chicago, America/Costa Rica), eso significa que cada usuario debe tener un campo en la base de datos con su respectivo nombre de Timezone. Si  tienes un sistema de usuarios y solo tienes guardado el offset de cada usuario (ejm: -09:00,+05:00), esta información no es suficiente en el mundo real, ya que cada pais y region tiene sus propias reglas horarias y reglas DST, por lo cual es obsoleto guardar solo el offset, la manera correcta es guardar la zona horaria.

3. AKTimeZone viene con algunos metodos bastante utiles. por ejemplo toString() el cual imprimira : “(GMT+01:10) TimezoneActual”, si quieres usarlo con los ejemplos previos, puedes usarlo asi:

<div align=”right”>_{Current Time Zone} : <?php echo $my_timezone->toString() ?></div>

En caso quieras generar una lista “select” de TimeZones puedes usar el metodo getTimezones() que devolvera un array de los timezones. para generar el codigo akelos completo puedes hacerlo asi:

<? echo $form_options_helper->select(‘user’, ‘timezone’, array_keys($my_timezone->getTimezones())); ?>

4. Debes saber que la clase AKTimeZone ya viene con timezones definidos lo cual seria un problema si mas adelante aparece un timezone nuevo, por lo cual debes tomar las medidas necesarias para enfrentar estas situaciones como por ejemplo teniendo una tabla de timezones en la base de datos.

Comments

Hola, hay algun sitio en donde explique desde el principio:

.- Dokeos 1.8.5 y zonas horarias
.- Situaciones cuando el servidor esta en otra zona horaria a la del curso
.- Como solventar el ajuste horario para que el sistema se lleve y haga los registros con nuestra zona horaria
.- En caso de tener que “echar codigo” cuales son los archivos involucrados y que codigo insertar.
.- Gracias

Bueno, en realidad este tema no debería estar aqui, ya que aqui estamos hablando de Akelos. Te recomendo los foros de Dokeos para este tipo de pregunta.
Para no dejarte sin respuesta, Dokeos *no* maneja el tema de las zonas horarias. Para desarrollarlo, la idea sería de crear una función que se encarga de enseñar todos los tiempos, y de modificarlos según una diferencia horaria para cada usuario. La diferencia horaria, en un primer tiempo, podría ser grabada en un “campo extra” de la tabla usuarios, que se puede agregar en la interfaz de administración de Dokeos 1.8.5. Para el lado del código, no hay solución simple. Hay muchas cosas que cambiar.

No hay planes tampoco para integrar este tema de zonas horarias en 1.8.6 o en 1.8.7, pero creo que sería bueno de planearlo para Dokeos 2.0 (fines de 2009). Si te interesa este tema, recomendo lo escribes en el foro y tratas de motivar otras personas para que sea una pedida de grupo, no de solo una persona (en Inglés tendras más opiniones, pero puedes escribir en Español sin problema sino).