PHP ofrece dos clases para trabajar con fechas en orientación a objetos: DateTime y DateTimeImmutable. La diferencia entre ellas no es trivial y elegir la equivocada puede provocar bugs difíciles de detectar. La regla es simple: DateTime muta el objeto cuando lo modificas; DateTimeImmutable devuelve una nueva instancia y deja el original intacto.
Crear instancias
<?php
// Fecha actual
$ahora = new DateTimeImmutable();
$hoy = new DateTime();
// Fecha concreta en formato ISO 8601
$fecha = new DateTimeImmutable('2026-07-21 11:00:00');
// Formato personalizado con createFromFormat()
$dt = DateTimeImmutable::createFromFormat('d/m/Y H:i', '21/07/2026 11:00');
if ($dt === false) {
// createFromFormat devuelve false si el formato no coincide
echo 'Formato de fecha incorrecto';
}
// Desde un timestamp Unix
$ts = 1750000000;
$desde = new DateTimeImmutable('@' . $ts);
?>
Formatear fechas con format()
El método format() acepta los mismos caracteres que la función date():
<?php
$dt = new DateTimeImmutable('2026-07-21 11:00:00');
echo $dt->format('Y-m-d'); // 2026-07-21
echo $dt->format('d/m/Y H:i:s'); // 21/07/2026 11:00:00
echo $dt->format('D, d M Y'); // Tue, 21 Jul 2026
echo $dt->format('U'); // timestamp Unix
echo $dt->format('c'); // ISO 8601 completo con timezone
echo $dt->format('r'); // RFC 2822
?>
Modificar fechas
Con DateTime, los métodos modify(), add() y sub() mutan el objeto. Con DateTimeImmutable, devuelven una nueva instancia:
<?php
$original = new DateTimeImmutable('2026-07-21');
// Estos métodos devuelven una NUEVA instancia; $original no cambia
$manana = $original->modify('+1 day');
$semana = $original->modify('+1 week');
$intervalo = new DateInterval('P1M'); // 1 mes
$mesmas = $original->add($intervalo);
$mesmenos = $original->sub($intervalo);
echo $original->format('d/m/Y'); // 21/07/2026 ? sin cambios
echo $manana->format('d/m/Y'); // 22/07/2026
echo $semana->format('d/m/Y'); // 28/07/2026
echo $mesmas->format('d/m/Y'); // 21/08/2026
?>
El bug clásico de la mutación con DateTime
Cuando pasas un DateTime a una función y esa función lo modifica, el objeto original también cambia. Este bug es especialmente traicionero porque el código parece correcto:
<?php
// BUG con DateTime
function añadirUnMes(DateTime $dt): DateTime
{
return $dt->modify('+1 month'); // muta $dt
}
$reserva = new DateTime('2026-07-21');
$finReserva = añadirUnMes($reserva);
echo $reserva->format('d/m/Y'); // 21/08/2026 ? $reserva fue mutado
echo $finReserva->format('d/m/Y'); // 21/08/2026
// CORRECTO con DateTimeImmutable
function añadirUnMesSeguro(DateTimeImmutable $dt): DateTimeImmutable
{
return $dt->modify('+1 month'); // devuelve nueva instancia
}
$reserva2 = new DateTimeImmutable('2026-07-21');
$finReserva2 = añadirUnMesSeguro($reserva2);
echo $reserva2->format('d/m/Y'); // 21/07/2026 ? intacto
echo $finReserva2->format('d/m/Y'); // 21/08/2026
?>
Comparar fechas
Ambas clases implementan DateTimeInterface, lo que permite comparar instancias con los operadores estándar de PHP:
<?php
$a = new DateTimeImmutable('2026-07-21');
$b = new DateTimeImmutable('2026-08-01');
var_dump($a < $b); // bool(true)
var_dump($a > $b); // bool(false)
var_dump($a == $b); // bool(false)
// diff() devuelve un DateInterval con la diferencia
$diff = $a->diff($b);
echo $diff->days . ' días de diferencia'; // 11 días de diferencia
?>
Convertir entre DateTime y DateTimeImmutable
<?php
$mutable = new DateTime('2026-07-21');
$inmutable = DateTimeImmutable::createFromMutable($mutable);
$mutable2 = DateTime::createFromImmutable($inmutable);
?>
Cuándo usar cada una
- Usa DateTimeImmutable por defecto: es más segura en funciones, pipelines de transformación y cualquier contexto donde el valor original no debe cambiar.
- Usa DateTime solo cuando necesites mutar el objeto de forma explícita y controlada, o al trabajar con librerías que lo requieran.
- Si tienes que tipar en interfaces o funciones, usa DateTimeInterface para aceptar ambas.
La documentación oficial de DateTimeImmutable incluye todos los métodos disponibles y ejemplos de uso con zonas horarias y formatos personalizados.
