ScotlandPHP

DateTime::diff

DateTimeImmutable::diff

DateTimeInterface::diff

date_diff

(PHP 5 >= 5.3.0, PHP 7)

DateTime::diff -- DateTimeImmutable::diff -- DateTimeInterface::diff -- date_diffReturns the difference between two DateTime objects

Description

Object oriented style

public DateInterval DateTime::diff ( DateTimeInterface $datetime2 [, bool $absolute = false ] )
public DateInterval DateTimeImmutable::diff ( DateTimeInterface $datetime2 [, bool $absolute = false ] )
public DateInterval DateTimeInterface::diff ( DateTimeInterface $datetime2 [, bool $absolute = false ] )

Procedural style

DateInterval date_diff ( DateTimeInterface $datetime1 , DateTimeInterface $datetime2 [, bool $absolute = false ] )

Returns the difference between two DateTimeInterface objects.

Parameters

datetime

The date to compare to.

absolute

Should the interval be forced to be positive?

Return Values

The DateInterval object representing the difference between the two dates or FALSE on failure.

Examples

Example #1 DateTime::diff() example

Object oriented style

<?php
$datetime1 
= new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval $datetime1->diff($datetime2);
echo 
$interval->format('%R%a days');
?>

Procedural style

<?php
$datetime1 
date_create('2009-10-11');
$datetime2 date_create('2009-10-13');
$interval date_diff($datetime1$datetime2);
echo 
$interval->format('%R%a days');
?>

The above examples will output:

+2 days

Example #2 DateTime object comparison

Note:

As of PHP 5.2.2, DateTime objects can be compared using comparison operators.

<?php
$date1 
= new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2);
var_dump($date1 $date2);
var_dump($date1 $date2);
?>

The above example will output:

bool(false)
bool(true)
bool(false)

See Also

  • DateInterval::format() - Formats the interval
  • DateTime::add() - Adds an amount of days, months, years, hours, minutes and seconds to a DateTime object
  • DateTime::sub() - Subtracts an amount of days, months, years, hours, minutes and seconds from a DateTime object
add a note add a note

User Contributed Notes 25 notes

up
99
ianlenmac at gmail dot com
4 years ago
It is worth noting, IMO, and it is implied in the docs but not explicitly stated, that the object on which diff is called is subtracted from the object that is passed to diff.

i.e. $now->diff($tomorrow) is positive.
up
27
php at jcouture dot net
4 years ago
After wrestling with DateTime::diff for a while it finally dawned on me the problem was both in the formatting of the input string and the formatting of the output.

The task was to calculate the duration between two date/times.

### Calculating Duration

1. Make sure you have a valid date variable.  Both of these strings are valid:

<?php

// Example

  
$strStart = '2013-06-19 18:25';
  
$strEnd   = '06/19/13 21:47';

?>

2. Next convert the string to a date variable
~~~
<?php

   $dteStart
= new DateTime($strStart);
  
$dteEnd   = new DateTime($strEnd);

?>
~~~

3. Calculate the difference
~~~
<?php

   $dteDiff 
= $dteStart->diff($dteEnd);

?>
~~~

4. Format the output
~~~
<?php

  
print $dteDiff->format("%H:%I:%S");

/*
    Outputs
   
    03:22:00
*/

?>
~~~

[Modified by moderator for clarify]
up
18
crayonviolent at phpfreaks dot com
3 years ago
It seems that while DateTime in general does preserve microseconds, DateTime::diff doesn't appear to account for it when comparing. 

Example:

<?php
$val1
= '2014-03-18 10:34:09.939';
$val2 = '2014-03-18 10:34:09.940';

$datetime1 = new DateTime($val1);
$datetime2 = new DateTime($val2);
echo
"<pre>";
var_dump($datetime1->diff($datetime2));

if(
$datetime1 > $datetime2)
  echo
"1 is bigger";
else
  echo
"2 is bigger";
?>

The var_dump shows that there is no "u" element, and "2 is bigger" is echoed.

To work around this apparent limitation/oversight, you have to additionally compare using DateTime::format. 

Example:

<?php
if($datetime1 > $datetime2)
  echo
"1 is bigger";
else if (
$datetime1->format('u') > $datetime2->format('u'))
  echo
"1 is bigger";
else
  echo
"2 is bigger";
?>
up
19
acrion at gmail dot com
7 years ago
If you want to quickly scan through the resulting intervals, you can use the undocumented properties of DateInterval.

The function below returns a single number of years, months, days, hours, minutes or seconds between the current date and the provided date.  If the date occurs in the past (is negative/inverted), it suffixes it with 'ago'.

<?php
function pluralize( $count, $text )
{
    return
$count . ( ( $count == 1 ) ? ( " $text" ) : ( " ${text}s" ) );
}

function
ago( $datetime )
{
   
$interval = date_create('now')->diff( $datetime );
   
$suffix = ( $interval->invert ? ' ago' : '' );
    if (
$v = $interval->y >= 1 ) return pluralize( $interval->y, 'year' ) . $suffix;
    if (
$v = $interval->m >= 1 ) return pluralize( $interval->m, 'month' ) . $suffix;
    if (
$v = $interval->d >= 1 ) return pluralize( $interval->d, 'day' ) . $suffix;
    if (
$v = $interval->h >= 1 ) return pluralize( $interval->h, 'hour' ) . $suffix;
    if (
$v = $interval->i >= 1 ) return pluralize( $interval->i, 'minute' ) . $suffix;
    return
pluralize( $interval->s, 'second' ) . $suffix;
}
?>
up
11
Grgoire Marchal
6 years ago
Warning, there's a bug on windows platforms: the result is always 6015 days (and not 42...)

http://bugs.php.net/bug.php?id=51184
up
12
nospam at oece dot me
3 years ago
Using the identical (===) comparision operator in different but equal objects will return false

<?php
$c
= new DateTime( '2014-04-20' );
$d = new DateTime( '2014-04-20' );
var_dump( $d === $d ); #true
var_dump( $d === $c ); #false
var_dump( $d == $c ); #true
?>
up
1
Anonymous
7 months ago
<?php
$datetime1
= new DateTime('2016-11-30');
$datetime2 = new DateTime('2017-03-01');
$interval = $datetime1->diff($datetime2);
var_dump($interval->days / 30.4375);
$month = $interval->m + $interval->y * 12;
var_dump($month);

Result:
float(2.9897330595483)
int(2) <-- Where is the third month? February has 28/29 days total.

For
<?
php
$datetime1
= new DateTime('2016-11-30');
$datetime2 = new DateTime('2017-03-02');

Result:
float(3.0225872689938)
int(3)
up
15
sgmurphy19
5 years ago
Though I found a number of people who ran into the issue of 5.2 and lower not supporting this function, I was unable to find any solid examples to get around it. Therefore I hope this can help some others:

<?php
function get_timespan_string($older, $newer) {
 
$Y1 = $older->format('Y');
 
$Y2 = $newer->format('Y');
 
$Y = $Y2 - $Y1;

 
$m1 = $older->format('m');
 
$m2 = $newer->format('m');
 
$m = $m2 - $m1;

 
$d1 = $older->format('d');
 
$d2 = $newer->format('d');
 
$d = $d2 - $d1;

 
$H1 = $older->format('H');
 
$H2 = $newer->format('H');
 
$H = $H2 - $H1;

 
$i1 = $older->format('i');
 
$i2 = $newer->format('i');
 
$i = $i2 - $i1;

 
$s1 = $older->format('s');
 
$s2 = $newer->format('s');
 
$s = $s2 - $s1;

  if(
$s < 0) {
   
$i = $i -1;
   
$s = $s + 60;
  }
  if(
$i < 0) {
   
$H = $H - 1;
   
$i = $i + 60;
  }
  if(
$H < 0) {
   
$d = $d - 1;
   
$H = $H + 24;
  }
  if(
$d < 0) {
   
$m = $m - 1;
   
$d = $d + get_days_for_previous_month($m2, $Y2);
  }
  if(
$m < 0) {
   
$Y = $Y - 1;
   
$m = $m + 12;
  }
 
$timespan_string = create_timespan_string($Y, $m, $d, $H, $i, $s);
  return
$timespan_string;
}

function
get_days_for_previous_month($current_month, $current_year) {
 
$previous_month = $current_month - 1;
  if(
$current_month == 1) {
   
$current_year = $current_year - 1; //going from January to previous December
   
$previous_month = 12;
  }
  if(
$previous_month == 11 || $previous_month == 9 || $previous_month == 6 || $previous_month == 4) {
    return
30;
  }
  else if(
$previous_month == 2) {
    if((
$current_year % 4) == 0) { //remainder 0 for leap years
     
return 29;
    }
    else {
      return
28;
    }
  }
  else {
    return
31;
  }
}

function
create_timespan_string($Y, $m, $d, $H, $i, $s)
{
 
$timespan_string = '';
 
$found_first_diff = false;
  if(
$Y >= 1) {
   
$found_first_diff = true;
   
$timespan_string .= pluralize($Y, 'year').' ';
  }
  if(
$m >= 1 || $found_first_diff) {
   
$found_first_diff = true;
   
$timespan_string .= pluralize($m, 'month').' ';
  }
  if(
$d >= 1 || $found_first_diff) {
   
$found_first_diff = true;
   
$timespan_string .= pluralize($d, 'day').' ';
  }
  if(
$H >= 1 || $found_first_diff) {
   
$found_first_diff = true;
   
$timespan_string .= pluralize($H, 'hour').' ';
  }
  if(
$i >= 1 || $found_first_diff) {
   
$found_first_diff = true;
   
$timespan_string .= pluralize($i, 'minute').' ';
  }
  if(
$found_first_diff) {
   
$timespan_string .= 'and ';
  }
 
$timespan_string .= pluralize($s, 'second');
  return
$timespan_string;
}

function
pluralize( $count, $text )
{
  return
$count . ( ( $count == 1 ) ? ( " $text" ) : ( " ${text}s" ) );
}
?>
up
11
astagl at gmail dot com
5 years ago
I needed to get the exact number of days between 2 dates and was relying on the this diff function, but found that I was getting a peculiar result with:

<?php
    $today
= new DateTime(date('2011-11-09'));
   
$appt  = new DateTime(date('2011-12-09'));
   
$days_until_appt = $appt->diff($today)->d;
?>

This was returning 0 because it was exactly one month.

I had to end up using :

<?php
    $days_until_appt
= $appt->diff($today)->days;
?>

to get 30.
up
3
toreskobba at gmail dot com
5 years ago
When using datediff make sure your time zone is correct, for me on Windows 7 64 bit it behaved very strange when timezone was wrong (I was comparing now against time in database and exif metadata in photos). For example: date_default_timezone_set('Europe/Oslo');
up
2
milespickens+php at gmail dot com
6 years ago
I was looking for a way to output X number of days from a given date and didn't find exactly what I was looking for.  But I got this working.  I hope this helps you.

This will output the number of days,months, or years difference between NOW and a April 1st, 2011. 

<?php
    $date1
= new DateTime('2011-04-01');
   
$date2 = new DateTime("now");
   
$interval = $date1->diff($date2);
   
$years = $interval->format('%y');
   
$months = $interval->format('%m');
   
$days = $interval->format('%d');
    if(
$years!=0){
       
$ago = $years.' year(s) ago';
    }else{
       
$ago = ($months == 0 ? $days.' day(s) ago' : $months.' month(s) ago');
    }
    echo
$ago;
?>

If I used today, 2011-05-16 as $date1, I could return all 0's in the format.  For example....

<?php
        $date1
= new DateTime('2011-05-161');
   
$date2 = new DateTime("now");
   
$interval = $date1->diff($date2);
   
$diff = $interval->format('%y-%m-%d');
    echo
$diff//Today, this will output 0-0-0
?>
up
2
amons dot 360 at gmail dot com
4 years ago
So this function is not available for my server's PHP. I created an alternative.

Convert the datetime into time-stamps, then subtract normally, then convert the seconds to whatever you want.

<?

$date1
= new DateTime('now');
$date1->modify("-3 hours");

$date2 = new DateTime('now');

$number1 = (int)$date1->format('U');
$number2 = (int)$date2->format('U');

echo (
$number2 - $number1)/60/60; // will print 3

?>

-Suleiman ALAQEL
up
1
starsniper at in dot com
3 years ago
Another Method to compare dates:
<?php       
    $d1
= new DateTime('2014-06-07 20:56:00');
   
$d2 = new DateTime('2014-06-09 21:09:00');
    echo
'The DateTimes are: <br /> d1: '.$d1->format("d-M-y, h:i A").'<br /> d2: '.$d2->format("d-M-y, h:i A");
   
   
$date_diff = $d1->diff($d2);            // difference of dates =  ($d2 - $d1)
   
   
if ( (int)$date_diff->format('%R%a')  >= 0 ){
        echo
'<br /><br />The recent date is: '.$d2->format("d-M-y, h:i A");
        echo
'<br /> The older date is: '.$d1->format("d-M-y, h:i A");
    }else{
        echo
'<br /><br />The recent date is: '.$d1->format("d-M-y, h:i A");
        echo
'<br /> The older date is: '.$d2->format("d-M-y, h:i A");
    }
?>

Output:
The DateTimes are:
d1: 07-Jun-14, 08:56 PM
d2: 09-Jun-14, 09:09 PM

The recent date is: 09-Jun-14, 09:09 PM
The older date is: 07-Jun-14, 08:56 PM
up
4
Dennis C
7 years ago
For those like me who don't yet have PHP 5.3 installed on their host, here's a simple alternative to get the number of days between two dates in the format '2010-3-23' or similar acceptable to strtotime().  You need PHP 5.2.

<?php
function date_diff($date1, $date2) {
   
$current = $date1;
   
$datetime2 = date_create($datespan>= new DateTime<">Da+rd">=v class="phpcode"> For those like me who don't yet have PHP 5.3 installed on ;= <"defaulspan>$datrd">);
  }
 ss="defaulpan class="string">'%R%a'' year(s) ago'$date2) {
   gmew
DateTimeformatDateTimeformatDateTime$da)reate($d++an>., $="default">DateTime  return>(<?php
= new ir hspan>datepluralizeDateTime(\M-y,DateTime"d-M-y, PM
PM

The recent date is: 09-Jun-14, 09:09 PM
Th10199der date is: 07-Jun-14, 08:56 PM
10199deriff&vote=up" title="Vote up!" class="199d"104001">
199de"v class="tally" id="V97810" title="55% lischindhelm2
milespickens+php at gmail dot 1-21/em><8strong>
6 years ago:: gapn't yet hrrectps yobirth PM Igot:/>  returGass=" was ghisan>
<?php
= nnow agaBerlinpan>formateTime$d2"d$birth-06-07 20:56:00');
   
$d2 = n1966t 1-21pan>format/span>"d$ was getting a peculiar result with:

<?php
    $today /span>"d$);
   
    $date_diff = $d1->;; return>"d$    if ( (int)$date_diff->ault">60/default45eTime"d$birth-06-07 20:56:00');
   
$d2 = n1966t 1-23pan>format/span>"d$ was getting a peculiar result with:

<?php
    $today /span>"d$);
   
    $date_diff = $d1->;; return>"d$    if ( (int)$date_diff->ault">60/default45ure yolyeTime"d$birth-06-07 20:56:00');
   
$d2 = n1966t 1-24gt;ault">60"d$ was getting a peculiar result with:

<?php
    $today /span>"d$);
   
    $date_diff = $d1->;; return>"d$    if ( (int)$date_diff->ault">60/default44 -64">     echo ifConvert t Fo invoiciv clasxt" i 2 a quickc )=zonen two dThankss;
Th121062er date is: 07-Jun-14, 08:56 PM
121062eriff&vote=up" title="Vote up!" class=21062"104001">
21062evv class="tally" id="V97810" title="55% liDaniel Kleindiv> milespickens+php at gmail d7/span<9strong>
5 years ago
OutAlronughConveCANn>< /r thnonintuitml">betwees06fSo thtrong>obj<?php
    $today /span>"d$trong_phpco class="keyword">);
   
    $difft/span>/span>"dv i_dump$d1);
  }
 strong_phpct;
n clas($d2/span>"dv i_dump$d1);
  }
 strong_phpct;
n clas($d2("d-M-y, h:i A"::n class=tut:/dnl gbe i );/be span );
   
$d2 = nyes="syword">(format(recetting a peculiar result with:

<?php
    $today /span>"d$trong_phpco class="keyword">);
   
    $difft/span>/span>"dv i_dump$d1$date_diff = $d1$d2/span>"dv i_dump$d1$date_diff = $d1cret;$d2("d-M-y, h:i A"d/be 106fSo thnative6 PM
;
Th120108er date is: 07-Jun-14, 08:56 PM
120108eriff&vote=up" title="Vote up!" class=20108"104001">
20108e"v class="tally" id="V97810" title="55% licsV97o"> halmaiiv> hudiv> milespickens+php at gmail d6">(
5 years ago// differencen $timespa/spaD>= $d1zt;"d-M-y/span>"d$<?php       
    $d1
= il d5/span1format<?php      &nbsZom1$d1zt;("d$<4-06-07 20:56:00');
   
$d2 = il d5/s7an1format<?php      &nbsZom1$d1zt;("d$);
   
   
$date_diff = $d1->(spa
   
if ( (int)$date_diffformat    (= $d1format(= $d1modifyspan>"d-M-y, h:i A"
ThYear: 00 M; ThYear: 00 M; ;
?><865n class="default">?>
=865n vv class="tally" id="V97810" title="55% liarunajamadiet yahoo1
865n cl"user">milespickens+php at gmail d6"01-15 04:32strong> ¶
4 years ago mthrm ctpans cobr n0400 get class="d(ss="defau1, ss="defaul)nionequivale t <"r my servess="defau1b ;
?><8382er date is: 07-Jun-14, 08:56 PM 1<8382eriff&vote=up" title="Vote up!" class="8382"115174">
=8382e"v class="tally" id="V97810" title="55% licagatay2 devp; kis..."ninefv>
8382er "user">milespickens+php at gmail d5">(<25/em><0strong> ¶
5 years ago
Th, then lass="sp; &nbs(new formatformatformattv cl,=lets sayspan>
ThNow:-14,00pm, 01.01.l d5>/s don0ho dstvalueo dowspan>
Thpan><: 00,00am, 01.01.l d5>/s d "ofSc;mom ct=e tofacepalmtext"selfockco cl,= neestd">/t thn"taho d!="defau;
?>92692er date is: 07-Jun-14, 08:56 PM
92692erdiff&vote=up" title="Vote up!" class2692id="97810">
e2692e"v class="tally" id="V97810" title="55% liAnonymous.."> 4
milespickens+php at gmail 09-08-04 05:17strong>
5 years ago
This was returning 0 because it was exlar acwas wrong (I was comparinefault"><?php
= nnow agaMadrispan>formatpan>
Thispan>"d$<?php       
    $d1
= '1492"01-n>DateTimeThispan>"d$<4-06-07 20:56:00');
   
$d2 = '1492"12-3>DateTimeThispan>/span>"dv i_dump$d1);
  }
 ss->
"dv i_dump$d1);
  }
 ss->
"dv i_dump$d1= ss->"d-M-y, h:i A""defau;
?><2368er date is: 07-Jun-14, 08:56 PM
1<2368eriff&vote=up" title="Vote up!" class="2368"115174">
2368evv class="tally" id="V97810" title="55% ligusarovea mukr.ninefv>
2368er ss="user">amons dot 360 at gmail dot pan><01:16strong>
5 years ago< id=hpcod">5.3lass=" the format '2010-3-23' or simrmally, then convert the seconds to whatever>span>"dive to ge/span>DateTimeDateTime= ssclass="string">"-3 hours"= o ge/span>Dapan classpan>= ssub?php class="keyword">);
   
    );

echo (/span>date_can classpan>= s getting a peculiar result with:<$d1)/)/)/);

echo (/getting a peculiar result with:<$d1
)/)/);

echo (h-06-07 20:56:00'
)/)/);

echo (m-06-07 20:56:00'
)/)/modip; echo DateTimedatep  
    formatmodip; echo DateTimedatep  
    modi; return>"d$t;modi; return>"d$d;modi; return>"d$han>$datpd1modi; return>"d$man>$datpd1modi; retur>span>"d-M-y, "defau;
?><7663er date is: 07-Jun-14, 08:56 PM
1<7663eriff&vote=up" title="Vote up!" class="7663"115174">
7663evv class="tally" id="V97810" title="55% lidevegpat 2
milespickens+php at gmail d5" 7-17/em>53strong> ¶
5 years ago< the format '2010-3-23' or PHPTime$d2span>"dwas wrong (I was comparinefault"><?php
= nAsia/kolkatt;ftpan>
Thispan>"d$gapn class="keyword">);
   
    )/
"d$gass=phpco class="keyword">);
   
 word">= n7-9-l d5;
f>formatspan>"d$gass=phpco class="keyword">);
   
 tring">"dexpl24"efault"><?php
= n-pan>datepluralize"d$gass=phpcftpan>
Thispan>"d$!" co d // differencep;  
    [  
    )/
"d$!" cp; // differencep;  
    [  
    formatformatspan>"d$!" ca cln clas([  
    <->
"d$);
   
$d2 DateTimedatep  
    DateTime)/)/)/)/    <$!" ca clord">)/= ssclass="string">"-3 hours");
   
$d2 DateTimedatespan classpan>= ss);
   
    );
&nbse_diff
= $d1span>date_cren classpan>= sscysbe yet h class="keyword">);
   
    );
&nbse_diff
$date_diff-t;ftpan>
Thn>"d$dcysbe yet ord">)/sysbe yet h class="keyword">);
&nbsrg">);
  }
 sgap
f(  }
 a/spa
$d1format  }
 sgap
p  
    )/
(  }
 a/spa
$d1format  }
 sstysbe yet ord">)/
"d-M-y, "defau;
Th1092lder date is: 07-Jun-14, 08:56 PM
1092lderiff&vote=up" title="Vote up!" class="92ld"104001">
92ldevv class="tally" id="V97810" title="55% liradu
092lder "user">milespickens+php at gmail d2t pa27-14, 0strong>
5 years ago/cod an ede>;
Th106018er date is: 07-Jun-14, 08:56 PM 106018eriff&vote=up" title="Vote up!" class="6018"104001">
6018e v class="tally" id="V97810" title="55% liAnonymous.."> 4
milespickens+php at gmail dotDenn3-14,12strong>
5 years ago<">spa?php lass="sp; &nbs(nl dot 8-01 00,00clas); return>spa?phpe_difs="d(ss="sp; &nbs(nl dotDenn1 00,00cl1'))span pan>format/;
?><6257er date is: 07-Jun-14, 08:56 PM 1<6257eriff&vote=up" title="Vote up!" class="6257"115174">
6257evv class="tally" id="V97810" title="55% liqrss=ld.ninefv>
6257er "user">milespickens+php at gmail d4"12-/2 02:31strong> ¶
5 years ago http://soft; http://soft; of i person specifys cob this f of birthspan>
Thn r tAge($birth PM;
;< #111741"> &pafoo>"dmp;vote=up" titleaddte up!" cls id PHP>addia nanutpd PHP>>rd">;tes-vode/span>