DateTime
在线手册:中文 英文
PHP手册

DateTime::diff

date_diff

(PHP 5 >= 5.3.0)

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

说明

面向对象风格

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

过程化风格

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

Returns the difference between two DateTime objects.

参数

datetime

The date to compare to.

absolute

Whether to return absolute difference.

返回值

The DateInterval object representing the difference between the two dates 或者在失败时返回 FALSE.

范例

Example #1 DateTime::diff() example

面向对象风格

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

过程化风格

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

以上例程会输出:

+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);
?>

以上例程会输出:

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

参见


DateTime
在线手册:中文 英文
PHP手册
PHP手册 - N: Returns the difference between two DateTime objects

用户评论:

sgmurphy19 (09-Feb-2012 07:00)

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:
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" ) );
}

toreskobba at gmail dot com (10-Nov-2011 11:24)

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');

astagl at gmail dot com (10-Nov-2011 04:21)

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.

Anonymous (03-Oct-2011 04:12)

$dateTime = new DateTime('2011-08-01 00:00:00');
echo $dateTime->diff(new DateTime('2011-10-01 00:00:01'))->format('%m');

will return 1, instead of 2 ...

milespickens+php at gmail dot com (16-May-2011 11:00)

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
?>

Grgoire Marchal (18-Feb-2011 10:22)

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

schindhelm at gmail dot com (21-Jan-2011 08:48)

I found that DateTime::diff isn't as accurate as I thought. I calculated the age gap between now and a birthdate from before 1970 (unix epoch). Here's what I got:

Given today is January 21st, 2011:

<?php
date_default_timezone_set
('Europe/Berlin');

// birthdate format is YYYY-MM-DD
$birth = new DateTime('1966-01-21');
$today = new DateTime();
$diff = $birth->diff($today);
echo
$diff->format('%y'); // will output 45

$birth = new DateTime('1966-01-23');
$today = new DateTime();
$diff = $birth->diff($today);
echo
$diff->format('%y'); // will output 45 wrongly

$birth = new DateTime('1966-01-24'); // three days difference!
$today = new DateTime();
$diff = $birth->diff($today);
echo
$diff->format('%y'); // will output 44 - correct
?>

When calculating with the date() function it was more accurate (didn't use seconds/hours for comparison).

Note that 3 days may be a lot if you want to create invoices and have to check against a given age to determine if the customer is chargable for taxes and so on.

If someone also found this behaviour I'd like to hear about it - give me a quick mail at schindhelm (at) gmail (dot) com.
Thanks.

Umair Ashraf (22-Nov-2010 07:49)

for PHP version 5.3

<?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;
}
?>

for PHP version 5.2

<?php
public function ago($dt)
{
   
$dt = date_parse($dt);
   
$now = date_parse(date("Y-m-d H:i:s"));
       
   
$suffix = " ago";
       
    if (
$now['year'] != $dt['year']) return $this->pluralize($now['year'] - $dt['year'], "year") . $suffix;
    if (
$now['month'] != $dt['month']) return $this->pluralize($now['month'] - $dt['month'], "month") . $suffix;
    if (
$now['day'] != $dt['day']) return $this->pluralize($now['day'] - $dt['day'], "day") . $suffix;
    if (
$now['hour'] != $dt['hour']) return $this->pluralize($now['hour'] - $dt['hour'], "hour") . $suffix;
    if (
$now['minute'] != $dt['minute']) return $this->pluralize($now['minute'] - $dt['minute'], "minute") . $suffix;
    if (
$now['second'] != $dt['second']) return $this->pluralize($now['second'] - $dt['second'], "second") . $suffix;
        return
"just now";
}

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

acrion at gmail dot com (13-May-2010 04:52)

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;
}
?>

Dennis C (10-May-2010 07:24)

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($date2);
   
$count = 0;
    while(
date_create($current) < $datetime2){
       
$current = gmdate("Y-m-d", strtotime("+1 day", strtotime($current)));
       
$count++;
    }
    return
$count;
}

echo (
date_diff('2010-3-9', '2011-4-10')." days <br \>");
?>

Anonymous (04-Aug-2009 01:17)

You don't need to calculate the exact difference if you just want to know what date comes earlier:

<?php

date_default_timezone_set
('Europe/Madrid');

$d1 = new DateTime('1492-01-01');
$d2 = new DateTime('1492-12-31');

var_dump($d1 < $d2);
var_dump($d1 > $d2);
var_dump($d1 == $d2);

?>

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