Categories: PHPTips

Cálculos con fechas en PHP

Estoy realmente cansado de ver por ahí cálculos con fechas que están mal hechos.

Tradicionalmente si se quiere añadir un día a una fecha dada se hace lo siguiente:

 $date2 = $date1 + 86400;

Básicamente a una fecha en formato UNIX ($date1) añadimos los 86400 segundos que tiene un día. Esto es correcto salvo que estemos en una zona horaria con cambio de hora (DST), por eso ES INCORRECTO.

Para añadir un intervalo cualquiera a una fecha lo CORRECTO es hacer lo siguiente:

$date2 = strtotime('+1day', $date1);

Utilizamos la función strtotime que convierte cualquier cadena de texto en un timestamp (tiempo UNIX). La única pega es que sólo entiende cadenas en inglés, por lo demás es muy útil:

ini_set('date.timezone', 'Europe/Madrid');

$dst1 = strtotime('last sunday of march');
$dst2 = strtotime('last sunday of october');

En el ejemplo que antecede estas líneas he definido la zona horaria de Madrid que se rige por DST que comienza el último domingo de marzo y termina el último domingo de octubre, después calculo dichas fechas diciéndole precisamente eso a strtotime.

Para calcular la diferencia entre dos fechas puede tentarnos hallar directamente la diferencia entre sus timestamps, por lo que tendríamos los segundos entre una fecha y otra… otra vez INCORRECTO. Para calcular diferencias entre fechas tenemos la función date_diff que es un alias de DateTime::diff.

Un ejemplo completo:

<?php
 ini_set('date.timezone', 'Europe/Madrid');

 define('HT', "\x09"); // \x09 \t Horizontal Tab
 define('LF', "\x0A"); // \x0A \n Line feed

 // Calculamos el inicio del DST: último domingo de marzo (2015-03-29 00:00:00 para 2015).
 $date10 = strtotime('last sunday of march');
 echo strftime('$date10 = strtotime("last sunday of march");   => %Y-%m-%d %H:%M:%S', $date10), LF;
 // Añadimos un día a $date10 de la manera correcta       (2015-03-30 00:00:00 para 2015).
 $date11 = strtotime('+1day', $date10);
 echo strftime('$date11 = strtotime("+1day", $date10);         => %Y-%m-%d %H:%M:%S', $date11), LF;
 // Añadimos un día a $date10 de la manera incorrecta     (2015-03-30 01:00:00 para 2015).
 $date12 = $date10 + 86400;
 echo strftime('$date12 = $date10 + 86400;                     => %Y-%m-%d %H:%M:%S', $date12), LF;

 echo LF;

 // Calculamos el final del DST: último domingo de octubre (2015-10-25 00:00:00 para 2015).
 $date20 = strtotime('last sunday of october');
 echo strftime('$date20 = strtotime("last sunday of october"); => %Y-%m-%d %H:%M:%S', $date20), LF;
 // Añadimos un día a $date20 de la manera correcta        (2015-10-26 00:00:00 para 2015).
 $date21 = strtotime('+1day', $date20);
 echo strftime('$date21 = strtotime("+1day", $date20);         => %Y-%m-%d %H:%M:%S', $date21), LF;
 // Añadimos un día a $date20 de la manera incorrecta      (2015-10-25 23:00:00 para 2015).
 $date22 = $date20 + 86400;
 echo strftime('$date22 = $date20 + 86400;                     => %Y-%m-%d %H:%M:%S', $date22), LF;

 echo LF;

 // Calculamos la diferencia entre fechas de manera incorrecta, nos dará 82800 segundos (23 horas) para el inicio del DST.
 $date_diff12 = $date11 - $date10;
 echo '$date_diff12 = $date11 - $date10;                                                                                 => ', $date_diff12, ' segundos = ' , $date_diff12 / 3600, ' horas', LF;
 // Calculamos la diferencia entre fechas de manera correcta, nos dará un día exacto.
 $date_diff11 = date_diff(new DateTime(date('Y-m-d H:i:s', $date10)), new DateTime(date('Y-m-d H:i:s', $date11)))->format('%R %y años, %m meses, %d días, %h horas, %i minutos, %s segundos');
 echo '$date_diff11 = date_diff(new DateTime(date("Y-m-d H:i:s", $date10)), new DateTime(date("Y-m-d H:i:s", $date11))); => ', $date_diff11, LF;

 echo LF;

 // Calculamos la diferencia entre fechas de manera incorrecta, nos dará 90000 segundos (25 horas) para el final del DST.
 $date_diff22 = $date21 - $date20;
 echo '$date_diff22 = $date21 - $date20;                                                                                 => ', $date_diff22, ' segundos = ' , $date_diff22 / 3600, ' horas', LF;
 // Calculamos la diferencia entre fechas de manera correcta, nos dará un día exacto.
 $date_diff21 = date_diff(new DateTime(date('Y-m-d H:i:s', $date20)), new DateTime(date('Y-m-d H:i:s', $date21)))->format('%R %y años, %m meses, %d días, %h horas, %i minutos, %s segundos');
 echo '$date_diff21 = date_diff(new DateTime(date("Y-m-d H:i:s", $date20)), new DateTime(date("Y-m-d H:i:s", $date21))); => ', $date_diff21, LF;

Y para ver el resultado: https://lab.fawno.com/code/dates.php

alpha

Share
Published by
alpha
Tags: PHP

Recent Posts

Apuntes de electrónica: Condensador y Bobina en alterna

Hace ya tiempo de mi última entrada de apuntes de electrónica. Fue la entrada sobre…

4 años ago

Análisis: Multímetro Zoyi ZT-300AB

Buscando multímetros económicos encontré el Zoyi ZT-300AB, por unos 20€ tenemos un aparato más que…

4 años ago

Multímetros Zoyi, cortesía de Zotek Instruments

En mi búsqueda de multímetros interesantes encontré a un fabricante cuyos multímetros vendían varios distribuidores…

4 años ago

Los productos remarcados

Desde que la industria empezó a deslocalizar sus fabricas llevando gran parte del peso de…

4 años ago

Análisis: Pinza amperimétrica Mestek CM83C

Desde que vi por primera vez una pinza amperimétrica quise tener una. Con la aparición…

4 años ago

Silencio

De lejos nos agobia, la distancia se hace notar con el silencio, de cerca es…

4 años ago