In PHP we usually use the DateTime functions for most of the date operations. The PHP DateTime are Mutable dates. The Mutable dates can be a source of confusion and they make unexpected bugs in your code. In this blog, we discuss mutable date issues and possible solutions.
Issue with DateTime
Below example, we going to display the today & tomorrow date using the DateTime object.
<?php$today_date = new DateTime();
$tomorrow_date = $today_date->modify('+1 day');
echo "Today: " . $today_date->format('Y-m-d');
echo "<br>";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>
If you execute the above code you will get the same date for both today & tomorrow. Because of the modify return updated instance of DateTime. Due to mutability, it will change the $today_date object to $tomorrow_date. so echo statement return same date.
Try Medium new feature of a code block with Syntax highlighter
Syntax highlighter on Medium
balajidharma.medium.com
Maybe issue with modify function on DateTime. Let's try other DateTime functions. Next example we try the DateTime->add() method.
<?php$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>
The above example also returns the same date. So you will get the same instance if you use mutable DateTime.
How to find the number of days between two dates in PHP
Get the Number of Days Between Two Dates
blog.devgenius.io
How to fix this issue
Photo by James Kovin on Unsplash
A simple fix is to move the $today_date echo statement before <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>0, <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>1 methods.
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>
But all the time we can't use the above fix. Because sometimes we need to assign the values to views. That time both will have the same date.
PHP object cloning
We can fix the issue by using PHP object cloning. Now try the clone keyword to clone the DateTime object. Then modify or add your changes.
<?php$today_date = new DateTime();
$tomorrow_date = (clone $today_date)->modify('+1 day');
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>
Object cloning makes your code more complex and introduces unnecessary noise. Also difficult to call clones on all the time. This issue is not only for <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>0 and <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>1 functions. You will face the same issue on the below <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>4 functions.
- <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>5 - <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>6 - <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>7 - <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>8 - <?php
$today_date = new DateTime();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>9 - modify
- <?php
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>1
DateTimeImmutable
The <?php
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>2 class behaves the same as DateTime except new objects are returned when modification methods such as DateTime::modify() are called. In PHP 5.5 the DateTimeImmutable class was introduced.
Immutable objects create copies of objects each time an object is modified
The DateTime and DateTimeImmutable are implemented from <?php
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>3 interface.
Let's try <?php
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>2 our examples.
$today_date = new DateTimeImmutable();
$tomorrow_date = $today_date->modify('+1 day');
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>
The above code will print the correct today and tomorrow dates. Instead of cloning, this DateTimeImmutable instance is the easy and perfect solution for our issue.
Another example with add() function
<?php$today_date = new DateTimeImmutable();
$tomorrow_date = $today_date->add(new DateInterval('P1D'));
echo "Today: " . $today_date->format('Y-m-d')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>
DateTime libraries
PHP Carbon is one of the best DateTime libraries. The carbon also provides the <?php
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>5 object. So use the immutable object if you using the carbon library.
$mutable = Carbon::now();
$modifiedMutable = $mutable->add(1, 'day');
echo $mutable->isoFormat('Y-M-D')."\n";
echo $modifiedMutable->isoFormat('Y m D')."\n";
$immutable = CarbonImmutable::now();
$modifiedImmutable = CarbonImmutable::now()->add(1, 'day');
echo $immutable->isoFormat('Y-M-D')."\n";
echo $modifiedImmutable->isoFormat('Y m D')."\n";
?>
Conclusion
So consider using the immutable DateTime object to avoid certain types of errors with a mutable DateTime. If any specific requirements use the mutable object, otherwise use the <?php
$today_date = new DateTime();
echo "Today: " . $today_date->format('Y-m-d');
$tomorrow_date = $today_date->modify('+1 day')."\n";
echo "Tomorrow: " . $tomorrow_date->format('Y-m-d');
?>2