(PHP 5 >= 5.3.0, PHP 7, PHP 8)
Represents a date interval.
A date interval stores either a fixed amount of time (in years, months, days, hours etc) or a relative time string in the format that DateTimeImmutable 's and DateTime 's constructors support.
More specifically, the information in an object of the DateInterval class is an instruction to get from one date/time to another date/time. This process is not always reversible.
A common way to create a DateInterval object is by calculating the difference between two date/time objects through DateTimeInterface::diff() .
Since there is no well defined way to compare date intervals, DateInterval instances are incomparable.
The available properties listed below depend on PHP version, and should be considered as readonly.
Number of years.
Number of months.
Number of days.
Number of hours.
Number of minutes.
Number of seconds.
Number of microseconds, as a fraction of a second.
Is 1
if the interval
represents a negative time period and
0
otherwise.
See DateInterval::format() .
If the DateInterval object was created by
DateTimeImmutable::diff() or
DateTime::diff() , then this is the
total number of full days between the start and end dates. Otherwise,
days will be false
.
If the DateInterval object was created by
DateInterval::createFromDateString() , then
this property's value will be true
, and the
date_string property will be populated. Otherwise,
the value will be false
, and the y to
f, invert, and
days properties will be populated.
The string used as argument to DateInterval::createFromDateString() .
Version | Description |
---|---|
8.2.0 | The from_string and date_string properties were added for DateInterval instances that were created using the DateInterval::createFromDateString() method. |
8.2.0 |
Only the y to f ,
invert , and days will be visible.
|
7.4.0 | DateInterval instances are incomparable now; previously, all DateInterval instances were considered equal. |
7.1.0 | The f property was added. |
If you want to reverse a date interval use array_reverse and iterator_to_array. I've found using invert to be unreliable.
<?php
$start_date = date_create("2021-01-01");
$end_date = date_create("2021-01-05"); // If you want to include this date, add 1 day
$interval = DateInterval::createFromDateString('1 day');
$daterange = new DatePeriod($start_date, $interval ,$end_date);
function show_dates ($dr) {
foreach($dr as $date1){
echo $date1->format('Y-m-d').'<br>';
}
}
show_dates ($daterange);
echo '<br>';
// reverse the array
$daterange = array_reverse(iterator_to_array($daterange));
show_dates ($daterange);
?>
Gives
2021年01月01日
2021年01月02日
2021年01月03日
2021年01月04日
2021年01月04日
2021年01月03日
2021年01月02日
2021年01月01日
There is a handy way to compare intervals by adding them to 0 dates and comparing dates instead
<?php
function compare(DateInterval $first, DateInterval $second): int
{
$firstDate = (new DateTime())->setTimestamp(0)->add($first);
$secondDate = (new DateTime())->setTimestamp(0)->add($second);
return $firstDate <=> $secondDate;
}
echo compare(new DateInterval('P2D'), new DateInterval('PT48H')) . PHP_EOL;
echo compare(DateInterval::createFromDateString('2 days'), DateInterval::createFromDateString('48 hours')) . PHP_EOL;
echo compare(DateInterval::createFromDateString('2 days'), DateInterval::createFromDateString('49 hours')) . PHP_EOL;
echo compare(DateInterval::createFromDateString('2 days'), DateInterval::createFromDateString('47 hours')) . PHP_EOL;
?>
Outputs:
0
0
-1
1
More simple example i use to add or subtract.
<?php
$Datetime = new Datetime('NOW', new DateTimeZone('America/Bahia'));
$Datetime->add(DateInterval::createFromDateString('2 day'));
echo $Datetime->format("Y-m-d H:i:s");
?>
Subtracting months may not work as you might expect.
Code shows how subtracting 2 months from consecutive days produces potentially unexpected results.
<?php
$origin = date_create('2025-01-31T00:00:00');
$target = date_create('2024-11-26T00:00:00');
$interval = date_diff($origin, $target);
echo "interval total days: ".$interval->format('%a days');
echo "interval object years: ".$interval->format('%y years');
echo "interval object months: ".$interval->format('%m months');
echo "interval object days: ".$interval->format('%d days');
// create 3 dates that are consecutive, but in two months
$d1 = date_create('2025-01-31T00:00:00');
$d2 = date_create('2025-02-01T00:00:00');
$d3 = date_create('2025-02-02T00:00:00');
// add (negative) interval object to each date
$d1->add($interval);
$d2->add($interval);
$d3->add($interval);
echo "Add (negative) interval object to each date. Non-consecutive results: ";
echo($d1->format("Y-m-d\TH:i:s"));
echo($d2->format("Y-m-d\TH:i:s"));
echo($d3->format("Y-m-d\TH:i:s"));
// reset dates
$d1 = date_create('2025-01-31T00:00:00');
$d2 = date_create('2025-02-01T00:00:00');
$d3 = date_create('2025-02-02T00:00:00');
// Use same dates, but subtract total number of days instead of adding interval object: ";
$d1->sub(new DateInterval('P'.$interval->format('%a').'D'));
$d2->sub(new DateInterval('P'.$interval->format('%a').'D'));
$d3->sub(new DateInterval('P'.$interval->format('%a').'D'));
echo "Use same dates, but subtract total number of days instead of adding interval object. Results (consecutive): ";
echo($d1->format("Y-m-d\TH:i:s"));
echo($d2->format("Y-m-d\TH:i:s"));
echo($d3->format("Y-m-d\TH:i:s"));
$d1 = date_create('2025-01-31T00:00:00');
$d2 = date_create('2025-02-01T00:00:00');
$d3 = date_create('2025-02-02T00:00:00');
// do month separately for 2025年02月01日T00:00:00
echo "Do month separately (interesting): ";
echo ('Subtract '. $interval->format('%m').' months (might not expect this):');
echo ('Jan 31 - 2 months (61 days = Dec, 31 days + Nov, 30 days) ==> Dec 1');
echo ('Feb 1 - 2 months (62 days = Dec, 31 days + Jan, 31 days) ==> Dec 1');
$d1->sub(new DateInterval('P'.$interval->format('%m').'M'));
echo $d1->format("Y-m-d\TH:i:s");
$d2->sub(new DateInterval('P'.$interval->format('%m').'M'));
echo $d2->format("Y-m-d\TH:i:s");
$d3->sub(new DateInterval('P'.$interval->format('%m').'M'));
echo $d3->format("Y-m-d\TH:i:s");
?>
Output:
interval total days: 66 days
interval object years: 0 years
interval object months: 2 months
interval object days: 5 days
create 3 dates that are consecutive, but in two months:
$d1 = 2025年01月31日T00:00:00
$d2 = 2025年02月01日T00:00:00
$d3 = 2025年02月02日T00:00:00
Add (negative) interval object to each date. Non-consecutive results:
2024年11月26日T00:00:00
2024年11月26日T00:00:00
2024年11月27日T00:00:00
Use same dates, but subtract total number of days instead of adding interval object. Results (consecutive):
2024年11月26日T00:00:00
2024年11月27日T00:00:00
2024年11月28日T00:00:00
Do month separately (interesting):
Subtract 2 months (might not expect this):
Jan 31 - 2 months (61 days = Dec, 31 days + Nov, 30 days) ==> Dec 1
Feb 1 - 2 months (62 days = Dec, 31 days + Jan, 31 days) ==> Dec 1
2024年12月01日T00:00:00
2024年12月01日T00:00:00
2024年12月02日T00:00:00