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

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *