DateTimeImmutable vs DateTime

4 minutos de lectura

avatar de usuario de hbengamra
bengamra

las 2 clases DateTime y DateTimeImmutable implementar la misma interfaz DateTimeInterface. Por eso quiero saber:

Cuál es la diferencia entre estas 2 clases DateTime y DateTimeImmutable?

Avatar de usuario de El_Vanja
El_Vanja

El núcleo de la diferencia se describe en el documentación del DateTime clase:

Esta clase se comporta igual que DateTimeImmutable excepto que los objetos se modifican cuando se llama a métodos de modificación como DateTime::modify().

Observemos esta diferencia en un ejemplo concreto:

$date = new DateTime();
$tomorrow = $date->modify('+1 day');
echo $date->format('Y-m-d');
echo $tomorrow->format('Y-m-d');

Esto generará:

2021-05-15
2021-05-15

Lo que pasó aquí es que el modify devolvió la misma instancia de la DateTime objeto. La variable $tomorrow no contiene un objeto diferente, contiene una referencia al original. La actualización de la nueva variable también modificó la original.

Si ejecutamos la misma modificación, pero en la versión inmutable:

$date = new DateTimeImmutable();
$tomorrow = $date->modify('+1 day');
echo $date->format('Y-m-d');
echo $tomorrow->format('Y-m-d');

Esto generará:

2021-05-14
2021-05-15

Porque en DateTimeImmutable, los métodos de modificación no devuelven la misma instancia, le brindan una nueva (también inmutable). Esto también significa que debes asignar su resultado a una variable (como en el ejemplo anterior) para la versión inmutable para poder usarlo:

$date = new DateTime('2021-05-14');
$date->modify('+1 day');
echo $date->format('Y-m-d'); // 2021-05-15

$date = new DateTimeImmutable('2021-05-14');
$date->modify('+1 day');
echo $date->format('Y-m-d'); // 2021-05-14; original is untouched

Debido a este comportamiento, la versión inmutable debe preferirse a la mutable prácticamente siempre. La modificación accidental de una instancia de una fecha que no tenía la intención de modificar es un error bastante común.

Es posible que prefiera la versión mutable para evitar el paso de la asignación en situaciones en las que puede determinar de manera confiable que no hay peligro de comprometer el estado de su aplicación, pero es mejor dejar que se estime una vez que tenga una comprensión firme de los conceptos.

Aparte de modifylos siguientes métodos también se consideran mutantes:

  • add
  • sub
  • setDate
  • setISODate
  • setTime
  • setTimezone

  • Está un poco escondido en el documentaciónasí que tal vez sea bueno tener en cuenta que Immutable->modify() devuelve un nuevo Inmutable objeto. Así que cada subsiguiente modify() en el nuevo objeto también tiene que ser asignado a una variable. Me tomó un tiempo averiguarlo.

    – Miguel

    21 de enero a las 9:42

  • @Michel Agregué explícitamente que devuelve una versión inmutable. Aunque si lo piensas bien, no tendría ningún sentido si fuera de otra manera. Si su instancia inmutable de repente se volviera mutable, entonces se perdería todo el propósito de la inmutabilidad.

    – El_Vanja

    22 de enero a las 11:43

  • Este señor, es una muy buena respuesta. ¡Gracias! Ahora me pregunto por qué no he estado usando esto todo este tiempo…

    – Naderio

    13 abr a las 18:53

  • ¡Muy buen artículo! ¡Gracias!

    – Tim K.

    15 de mayo a las 10:28

La diferencia está en la parte ‘inmutable’, lo que significa que una vez que se crea el objeto, nunca puede cambiar (wiki para más información). Lo que esto significa es que cada vez que modifique un DateTime se cambiará la misma instancia, pero cuando modifique una DateTimeImmutable en su lugar, se devolverá una nueva instancia modificada.

En general, un objeto inmutable nunca cambiará su estado después de haber sido creado. En cambio, cuando se necesita una modificación, devolverá una nueva instancia de la misma clase con el estado modificado.

El hecho de que ambos implementen el mismo Interfaz de fecha y hora es un poco confuso, pero puede explicarse por el hecho de que la interfaz no describe todas las funciones disponibles que el Fecha y hora y DateTimeImmutable oferta. Más precisamente, la interfaz no cubre métodos que permitan cambios de estado.

El caso de uso para elegir uno u otro depende principalmente de la preferencia, los estándares de codificación y, hasta cierto punto, la necesidad de calidad del código frente a la necesidad de velocidad de desarrollo.

Solo una nota rápida: si desea evitar el proceso de asignación, puede concatenar: echo $date->modify('+1 day')->format('Y-m-d'); asumiendo que $date es el DateTimeImmutable objeto.

Ejemplo:

$date = new DateTimeImmutable('2022-05-01');
$days = rand(2, 10);

echo "Date is: " . $date->format('d/m/Y')."\r\n";
echo "Now adding " .$days." days\r\n";
echo "Date now is: " . $date->modify('+'.$days.' day')->format('d/m/Y');

¿Ha sido útil esta solución?