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 years ago

Review: Zoyi ZT-300AB Multimeter

Looking for cheap multimeters I found the Zoyi ZT-300AB, for about €20 we have a…

4 years ago

Zoyi multimeters, courtesy of Zotek Instruments

In my search for interesting multimeters I came across a manufacturer whose multimeters were sold…

4 years ago

Los productos remarcados

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

4 years 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 years ago

Silencio

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

4 years ago