Micaela 4 de septiembre de 2009 a las 09.02
   Imprimir artículo
elWebmaster.com

PHP: Trabajando con fechas en base de datos


phpelefante1A la hora de trabajar con fechas en nuestras bases de datos, solemos complicarnos la vida cuando en realidad, las funciones integradas de PHP hacen que sea muy fácil validar y dar formato a todo tipo de fechas.

Bien implementado, el código PHP es capaz de realizar todo el trabajo pesado para nosotros. En esta nota, veremos de qué manera podemos utilizarlo para nuestro beneficio.

Almacenando la fecha y hora en una base de datos

Antes de cubrir la forma de manejar las fechas en PHP, es necesario hablar un poco acerca de cómo se deben almacenar fechas en una base de datos. En concreto hablaremos de MySQL.
Muchas personas improvisan su propia forma de almacenamiento de fechas en la base de datos, lo que inevitablemente les da algunos problemas más adelante. Pueden, por ejemplo, tener un tipo de campo VARCHAR y almacenar fechas en un formato DD/MM/AAAA. Esta es la manera equivocada de hacerlo.

Hay un gran número de maneras diferentes para almacenar fechas correctamente en una base de datos. Una forma es tener un campo entero y almacenar un timestamp de Unix. Pero este enfoque te hace incapaz de utilizar las funciones de tiempo y fecha MySQL, y estos son los problemas potenciales con el tema del problema Y2K38.

MySQL tiene un tipo de datos llamado TIMESTAMP. Esto muestra la fecha y la hora en un formato ISO 8601, es decir, desde la parte más significativa (año) a la parte menos significativa (segundo). Un ejemplo podría ser 2009-08-18 9:17:21. El formateo extra no es realmente necesario cuando se tipea, por lo que 2009081891721 sería la misma cosa.

Hay también un tipo de datos llamado DATETIME. Al principio, parece idéntico a la marca de tiempo, pero no es el caso. En primer lugar, TIMESTAMP todavía tiene problemas con el Y2K38, por lo que sólo puede almacenar las fechas que se pueden representar con un entero de 32 bits sin signo a partir de la época Unix (1970-01-01 00:00:00). Esto le da un límite superior 2038-01-19 03:14:07. DATETIME no tiene este problema, ya que puede almacenar fechas del 1000-01-01 al 9999-12-31. Por último, hay algunos tipos de datos llamados DATE y TIME. Son por si sólo necesitas o la fecha o la parte del tiempo.

Mi recomendación es utilizar DATETIME, DATE o TIME en función de sus necesidades. En realidad, hay un tipo YEAR también. Utilizar los tipos de datos de almacenamiento incorporados de MySQL para la fecha y hora nos permite utilizar sus funciones de fecha y hora.
No vamos a usar bases de datos para el resto de este tutorial. Los ejemplos suponen que ya tiene alguna cadena que contenga una fecha.

Las zonas horarias

Este es un problema muy frecuente. Cuando se utiliza la función Date () en PHP es utilizar siempre la hora del servidor para generar la fecha y hora. A menos que estés en una zona horaria diferente a tu servidor, este no es un problema. Pero si tengo un VPS (Virtual Private Server) en Inglaterra, y yo vivo en Dinamarca. esa es una diferencia de tiempo de una hora. ¿Cómo puedo lograr que PHP muestre la hora adecuada para mi? Como soy el administrador, simplemente puedo cambiar el reloj del servidor. Pero la mayoría de gente no puede hacer eso, así que tendremos que trabajar algunas alternativas de solución a este problema.

Si tienes acceso a php.ini (o puedes cambiar sus directrices usando un archivo .htaccess de Apache) se puede modificar la directiva date.timezone (en realidad, esto debe ser establecido en something si no desea errores de PHP ). De lo contrario, puedes utilizar la función date_default_timezone_set (). El manual tiene una lista de zonas horarias válidas que puede utilizar para estas dos cosas. Siguiendo con el ejemplo de Dinamarca, elegiría Europa / Copenhague.

Probémoslo:

  1. echo date('H:i:s');

El tiempo local de mi computadora es 09:34:08, por lo que eso también es lo que se muestra. Ahora intentemos cambiar la zona horaria:

  1. date_default_timezone_set('America/New_York');
  2. echo date('H:i:s');

Y obtendremos 03:34:08. Así que pareciera funcionar. Esta es una buena forma de lograrlo.

¿Qué pasa si necesitamos fechas múltiples pero en diferentes zonas horarias, en una misma página? Bueno, es bastante simple. Considera seguir este ejemplo:

  1. date_default_timezone_set('Europe/Copenhagen');
  2. echo 'The time in Copenhagen is: ' . date('H:i:s') . PHP_EOL;
  3.  
  4. date_default_timezone_set('America/New_York');
  5. echo 'The time in New York is: ' . date('H:i:s') . PHP_EOL;
  6.  
  7. date_default_timezone_set('Europe/Moscow');
  8. echo 'The time in Moscow is: ' . date('H:i:s') . PHP_EOL;

La exteriorización de eso sería:

  1. The time in Copenhagen is: 09:45:56
  2. The time in New York is: 03:45:56
  3. The time in Moscow is: 11:45:56

¿Qué pasa si tienes usuarios de múltiples zonas horarias? Sigue siendo fácil. Pregúntales cuál es su zona horaria y prográmala en función a esto. La función timezone_identifiers_list() te brinda una lista de todos los identificadores de zonas horarias, por lo que puedes usarla para generar una lista desplegable en la cual ellos puedan seleccionar su zona. También puedes probar la geolocalización, pero eso ya es otra cosa.

Finalmente, PHP posee una función llamada gmdate(), que siempre formatea la fecha en GMT. Si conoces el desplazamiento en segundos puedes hacer como:

  1. gmdate('H:i:s', time() + $offset);

Por lo que podrías hacer:

  1. gmdate('H:i:s', time() + 3600);

Para un desplazamiento de una hora. Sin embargo, esto requiere que tomes DST en consideración. No todos los países observan DST, y algunos lo hacen de forma diferente a los otros. Por eso es recomendable usar el soporte de zonas horarias PHP incorporado.

Convirtiendo de un formato al otro

“Tengo una fecha en DD/MM/AAAA pero la necesito en MM-DD-AAAA. ¡Ayuda!”

Analicemos la situación. Cada fecha posee tres componentes: el día, el mes y el año. Así que esencialmente sólo necesitamos reordenar estas partes y utilizar guiones en lugar de barras. Hay algunas maneras de lograr esto. Primero probemos dividiéndolas. Tenemos una función llamada explode() para esto.

  1. $oldDate = '18/08/2009'; // DD/MM/YYYY
  2.  
  3. $parts = explode('/', $oldDate);
  4.  
  5. /**
  6.  * Now we have:
  7.  *   $parts[0]: the day
  8.  *   $parts[1]: the month
  9.  *   $parts[2]: the year
  10.  * We could also have done:
  11.  *   list($day, $month, $year) = explode('/', $oldDate);
  12.  */
  13.  
  14. $newDate = "{$parts[1]}-{$parts[0]}-{$parts[2]}"; // MM-DD-YYYY
  15.  
  16. echo $newDate; // 08-18-2009

Esto parece funcionar bastante bien. También podemos usar algo llamado expresiones regulares. Será esencialmente una sola línea:

  1. $oldDate = '18/08/2009';
  2. $newDate = preg_replace('#^(\d{2})/(\d{2})/(\d{4})$#', '$2-$1-$3', $oldDate);

Como suele suceder con la programación, hay muchas maneras de hacer una misma cosa. Suponiendo que ya hemos dividido nuestra fecha en tres variables $ dia, $ mes y $ año podemos utilizar una función llamada mktime () para generar una marca de tiempo Unix y luego usar date () para darle formato de esta manera:

  1. $timestamp = mktime(0, 0, 0, $month, $day, $year);
  2. echo date('m-d-Y', $timestamp);

Otra forma es usar strtotime() para convertir un string formateado en un timestamp de Unix. Pero, strtotime() no reconoce DD/MM/AAAA como un formato válido, por lo que devuelve false. También hay problemas con la ambigüedad. Considera el string 07-08-2009. ¿Se trata del 7 de Agosto, o del 8 de Julio? Será la primera.

Validación de fecha

Si tomas una fecha como entrada (por ejemplo un cumpleaños), sería muy útil saber si en realidad es una fecha válida. Hay dos condiciones que deben cumplirse antes de que una fecha puede ser considerada válida:
1. Debe ajustarse a un formato especifico (puede que sólo deseemos AAAA-MM-DD, por ejemplo).
2. La fecha debe existir en concreto (2009-02-29 no existe, pero 2008-02-29 si).

La primera condición es bastante simple, y podemos lograrlo usando las expresiones regulares. El segundo es un poco más complicado. Tendremos que tomar la duración de un mes en consideración. ¿Tal vez es un año bisiesto, tal vez no lo es? Afortunadamente, no tenemos que preocuparnos de eso, PHP tiene una función llamada checkdate () que, precisamente, controla la fecha. Así, expresiones regulares y checkdate () es lo que necesitamos. Un pequeño ejemplo:

  1. <?php
  2. if ($_SERVER&#91;'REQUEST_METHOD'] == 'POST' && isset($_POST['date'])) {
  3.        if (preg_match('#^(\d{4})-(\d{2})-(\d{2})$#', $_POST&#91;'date'], $matches) && checkdate($matches[2], $matches[3], $matches[1])) {
  4.                echo '<p>The date is <strong>valid</strong>!</p>';
  5.         }
  6.         else {
  7.                 echo '<p>The date is <strong>invalid</strong>!</p>';
  8.         }
  9.        
  10.         echo '<hr>';
  11. }
  12. ?>
  13.  
  14. <form action="<?php echo $_SERVER['PHP_SELF'] ?>" method="post">
  15.         <label for="date">Enter an ISO 8601 date:</label>
  16.         <input type="text" name="date" id="date"<?php if (!empty($_POST&#91;'date'])): ?> value="<?php echo htmlentities($_POST['date']) ?>"<?php endif ?>>
  17.         <button type="submit">Check validity</button>
  18. </form>

Este ejemplo debería ser bastante sencillo. Primero, comprobar el formato de la cadena mediante preg_match () donde también se extrae el mes, día y año en backreferences. preg_match () devuelve true si la cadena coincide con el patrón. Por lógica, preg_match () se evalúa en primer lugar, y el checkdate () sólo se evalúa si el primer operando es verdadero (si el operando de la izquierda es false, la expresión regular no podría devolver true, por lo que evaluar el operando de la derecha sería redundante, he ahí la razón por la que no lo es).
Si has hecho campos separados para el día, mes y año es aún más sencillo y se puede omitir la comprobación del formato.

Puedes programar condiciones adicionales que deben cumplirse antes de considerar una fecha válida. Puedes pedir un intervalo de fecha, lo que quiere decir que la primera debe ser anterior a la última. Puede que sólo quieras fechas en el pasado o en el futuro, o que estén dentro de un intervalo predeterminado en particular. La forma más sencilla de hacerlo sería convertir las fechas a las marcas de tiempo Unix. De aquí en adelante se trata de comparación integer rudimentaria.

Como esperamos que hayan notado, las fechas no son tan difíciles de tratar como parece. ¿O no?

Fuente: PHP Freaks


Enviar a Del.icio.us Enviar a Meneame Enviar a Digg Enviar a Fresqui Enviar a Enchilame

Comentarios (8)

  1. ignacio campuzano flores dice:

    En mi humilde opinion de un programador dinosaurio es un EXcelente articulo que los que trabajamos con bitacoras de control y procesos agradeceremos el poder utilizar en su momento, gracias

  2. Leonardo dice:

    Buenos dias me parece muy bueno el articulo, agrego que tambien estan las funciones de fecha hora de la base de datos tales como CURRENT_TIMESTAMP para obtener la fecha y hora actual sin tener que ponerla el usuario tambien podemos trabajar con la fecha de la siguiente manera:
    (2009-year(empleado.fecha_ingreso)) AS años esta nos sirve para sacar los años que tenga un empleado en nuestra empresa o simplemente si queremos sacar por separado el dia mes y el año
    (year(empleado.fecha_ingreso)) AS año,
    (month(empleado.fecha_ingreso)) AS mes,
    (day(empleado.fecha_ingreso)) AS dia
    alli ya tienes para buscar por campos select de otro formulario con las variables
    $dia, $mes, $anio
    ejemplo en el where de sql
    where
    (year(empleado.fecha_ingreso))=$anio and
    (month(empleado.fecha_ingreso))=$mes and
    (day(empleado.fecha_ingreso))=$dia

    Saludos espero aportatrles otras ideas a los campos fecha para php y mysql.

  3. roberto dice:

    impresionante man ! im pre sio nan te
    la verdad que el tema de als fechas es todo un tema y lo acabas de excplicar de una manera muy sencilla y didactica.
    gracias !

  4. Andrés dice:

    Para mi la manera más fácil de trabajar con fechas es:
    $fecha = 15/09/2009;
    $formateada = date(‘Y-m-d’, strtotime($fecha));

    De esta forma puede pasarla a cualquier formato y no necesitas trabajar con arrays.
    Un saludo.

  5. eduardo dice:

    PErfecto el articulo justo lo que quería, dado que tengo un VPS en EEUU y vivo en España, me viene bien dado que obtenemos la fecha según donde uno vive…

    Gracias..

  6. Alejandro dice:

    Lo explicaste sencillo y grandioso a la vez muchas gracias por el aporte

  7. Juan Carlos dice:

    Simplemente excelente, de gran ayuda!…Muchas gracias por el aporte.

  8. Daniel dice:

    Muchas gracias por tu aporte de validacion de fechas,me has salvado

Deja tu opinión

© 2007 - 2008 elWebmaster.com | Powered by Wordpress | Diseño CSS y XHTML válido. | Algunos íconos basados en FamFamFam Mini
Acceder