关于datetime:如何使用PHP计算两个日期之间的差异?

How to calculate the difference between two dates using PHP?

我有两个表格日期:

1
2
Start Date: 2007-03-24
End Date: 2009-06-26

现在,我需要用以下形式找出这两者之间的区别:

1
2 years, 3 months and 2 days

如何在PHP中执行此操作?


我建议使用日期时间和日期间隔对象。

1
2
3
4
5
6
7
$date1 = new DateTime("2007-03-24");
$date2 = new DateTime("2009-06-26");
$interval = $date1->diff($date2);
echo"difference" . $interval->y ." years," . $interval->m." months,".$interval->d." days";

// shows the total amount of days (not divided into years, months and days like above)
echo"difference" . $interval->days ." days";

阅读更多php datetime::diff手册

从手册中:

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

1
2
3
4
5
6
$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2); // bool(false)
var_dump($date1 < $date2);  // bool(true)
var_dump($date1 > $date2);  // bool(false)


For PHP < 5.3 otherwise see jurka's answer below

您可以使用strtotime()将两个日期转换为unix时间,然后计算它们之间的秒数。由此可以很容易地计算出不同的时间段。

1
2
3
4
5
6
7
8
9
10
11
$date1 ="2007-03-24";
$date2 ="2009-06-26";

$diff = abs(strtotime($date2) - strtotime($date1));

$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));

printf("%d years, %d months, %d days
"
, $years, $months, $days);

编辑:显然,这样做的首选方式就像下面的Jurka所描述的那样。通常只有在没有php 5.3或更高版本时才建议使用我的代码。

评论中有几个人指出,上面的代码只是一个近似值。我仍然相信,在大多数情况下,这是很好的,因为使用范围更多的是提供一种感觉,多少时间已经过去或保持,而不是提供精度-如果你想这样做,只要输出日期。

尽管如此,我还是决定处理这些投诉。如果您确实需要一个精确的范围,但还没有访问php 5.3,请使用下面的代码(它也应该在php 4中工作)。这是PHP内部用于计算范围的代码的直接端口,但不考虑夏令时。这意味着它最多关闭一个小时,但除此之外,它应该是正确的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<?php

/**
 * Calculate differences between two dates with precise semantics. Based on PHPs DateTime::diff()
 * implementation by Derick Rethans. Ported to PHP by Emil H, 2011-05-02. No rights reserved.
 *
 * See here for original code:
 * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/tm2unixtime.c?revision=302890&view=markup
 * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/interval.c?revision=298973&view=markup
 */


function _date_range_limit($start, $end, $adj, $a, $b, $result)
{
    if ($result[$a] < $start) {
        $result[$b] -= intval(($start - $result[$a] - 1) / $adj) + 1;
        $result[$a] += $adj * intval(($start - $result[$a] - 1) / $adj + 1);
    }

    if ($result[$a] >= $end) {
        $result[$b] += intval($result[$a] / $adj);
        $result[$a] -= $adj * intval($result[$a] / $adj);
    }

    return $result;
}

function _date_range_limit_days($base, $result)
{
    $days_in_month_leap = array(31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $days_in_month = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    _date_range_limit(1, 13, 12,"m","y", &$base);

    $year = $base["y"];
    $month = $base["m"];

    if (!$result["invert"]) {
        while ($result["d"] < 0) {
            $month--;
            if ($month < 1) {
                $month += 12;
                $year--;
            }

            $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
            $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

            $result["d"] += $days;
            $result["m"]--;
        }
    } else {
        while ($result["d"] < 0) {
            $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
            $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

            $result["d"] += $days;
            $result["m"]--;

            $month++;
            if ($month > 12) {
                $month -= 12;
                $year++;
            }
        }
    }

    return $result;
}

function _date_normalize($base, $result)
{
    $result = _date_range_limit(0, 60, 60,"s","i", $result);
    $result = _date_range_limit(0, 60, 60,"i","h", $result);
    $result = _date_range_limit(0, 24, 24,"h","d", $result);
    $result = _date_range_limit(0, 12, 12,"m","y", $result);

    $result = _date_range_limit_days(&$base, &$result);

    $result = _date_range_limit(0, 12, 12,"m","y", $result);

    return $result;
}

/**
 * Accepts two unix timestamps.
 */

function _date_diff($one, $two)
{
    $invert = false;
    if ($one > $two) {
        list($one, $two) = array($two, $one);
        $invert = true;
    }

    $key = array("y","m","d","h","i","s");
    $a = array_combine($key, array_map("intval", explode("", date("Y m d H i s", $one))));
    $b = array_combine($key, array_map("intval", explode("", date("Y m d H i s", $two))));

    $result = array();
    $result["y"] = $b["y"] - $a["y"];
    $result["m"] = $b["m"] - $a["m"];
    $result["d"] = $b["d"] - $a["d"];
    $result["h"] = $b["h"] - $a["h"];
    $result["i"] = $b["i"] - $a["i"];
    $result["s"] = $b["s"] - $a["s"];
    $result["invert"] = $invert ? 1 : 0;
    $result["days"] = intval(abs(($one - $two)/86400));

    if ($invert) {
        _date_normalize(&$a, &$result);
    } else {
        _date_normalize(&$b, &$result);
    }

    return $result;
}

$date ="1986-11-10 19:37:22";

print_r(_date_diff(strtotime($date), time()));
print_r(_date_diff(time(), strtotime($date)));


最好的做法是使用PHP的DateTimeDateInterval对象。每个日期都封装在一个DateTime对象中,然后就可以区分这两个对象:

1
2
$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

DateTime对象将接受strtotime()将接受的任何格式。如果需要更具体的日期格式,可以使用DateTime::createFromFormat()创建DateTime对象。

在两个对象被实例化后,用DateTime::diff()从另一个对象中减去一个。

1
$difference = $first_date->diff($second_date);

$difference现在持有带有差异信息的DateInterval对象。一个var_dump()看起来像这样:

1
2
3
4
5
6
7
8
9
object(DateInterval)
  public 'y' => int 0
  public 'm' => int 0
  public 'd' => int 20
  public 'h' => int 6
  public 'i' => int 56
  public 's' => int 30
  public 'invert' => int 0
  public 'days' => int 20

要格式化DateInterval对象,我们需要检查每个值,如果为0,则排除它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Format an interval to show all existing components.
 * If the interval doesn't have a time component (years, months, etc)
 * That component won't be displayed.
 *
 * @param DateInterval $interval The interval
 *
 * @return string Formatted interval string.
 */

function format_interval(DateInterval $interval) {
    $result ="";
    if ($interval->y) { $result .= $interval->format("%y years"); }
    if ($interval->m) { $result .= $interval->format("%m months"); }
    if ($interval->d) { $result .= $interval->format("%d days"); }
    if ($interval->h) { $result .= $interval->format("%h hours"); }
    if ($interval->i) { $result .= $interval->format("%i minutes"); }
    if ($interval->s) { $result .= $interval->format("%s seconds"); }

    return $result;
}

现在只剩下调用$differenceDateInterval对象上的函数:

1
echo format_interval($difference);

我们得到了正确的结果:

20 days 6 hours 56 minutes 30 seconds

用于实现目标的完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * Format an interval to show all existing components.
 * If the interval doesn't have a time component (years, months, etc)
 * That component won't be displayed.
 *
 * @param DateInterval $interval The interval
 *
 * @return string Formatted interval string.
 */

function format_interval(DateInterval $interval) {
    $result ="";
    if ($interval->y) { $result .= $interval->format("%y years"); }
    if ($interval->m) { $result .= $interval->format("%m months"); }
    if ($interval->d) { $result .= $interval->format("%d days"); }
    if ($interval->h) { $result .= $interval->format("%h hours"); }
    if ($interval->i) { $result .= $interval->format("%i minutes"); }
    if ($interval->s) { $result .= $interval->format("%s seconds"); }

    return $result;
}

$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

$difference = $first_date->diff($second_date);

echo format_interval($difference);


查看小时、分钟和秒。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$date1 ="2008-11-01 22:45:00";

$date2 ="2009-12-04 13:44:01";

$diff = abs(strtotime($date2) - strtotime($date1));

$years   = floor($diff / (365*60*60*24));
$months  = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days    = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));

$hours   = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24)/ (60*60));

$minuts  = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60)/ 60);

$seconds = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60 - $minuts*60));

printf("%d years, %d months, %d days, %d hours, %d minuts
, %d seconds
"
, $years, $months, $days, $hours, $minuts, $seconds);


看看下面的链接。这是迄今为止我找到的最好的答案。:)

1
2
3
4
5
6
function dateDiff ($d1, $d2) {

    // Return the number of days between the two dates:    
    return round(abs(strtotime($d1) - strtotime($d2))/86400);

} // end function dateDiff

It doesn't matter which date is earlier or later when you pass in the
date parameters. The function uses the PHP ABS() absolute value to
always return a postive number as the number of days between the two
dates.

Keep in mind that the number of days between the two dates is NOT
inclusive of both dates. So if you are looking for the number of days
represented by all the dates between and including the dates entered,
you will need to add one (1) to the result of this function.

For example, the difference (as returned by the above function)
between 2013-02-09 and 2013-02-14 is 5. But the number of days or
dates represented by the date range 2013-02-09 - 2013-02-14 is 6.

http://www.bizinfosys.com/php/date-difference.html


我投票支持Jurka的答案,因为这是我最喜欢的,但我有一个php.5.3之前的版本…

我发现自己也在解决一个类似的问题——这就是我最初是如何解决这个问题的——但只需要几个小时的时间就可以了。但我的函数也很好地解决了这个问题,而且我自己的库中没有任何地方可以保存它,这样它就不会丢失和被遗忘,所以…希望这对某人有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 *
 * @param DateTime $oDate1
 * @param DateTime $oDate2
 * @return array
 */

function date_diff_array(DateTime $oDate1, DateTime $oDate2) {
    $aIntervals = array(
        'year'   => 0,
        'month'  => 0,
        'week'   => 0,
        'day'    => 0,
        'hour'   => 0,
        'minute' => 0,
        'second' => 0,
    );

    foreach($aIntervals as $sInterval => &$iInterval) {
        while($oDate1 <= $oDate2){
            $oDate1->modify('+1 ' . $sInterval);
            if ($oDate1 > $oDate2) {
                $oDate1->modify('-1 ' . $sInterval);
                break;
            } else {
                $iInterval++;
            }
        }
    }

    return $aIntervals;
}

测试:

1
2
3
4
$oDate = new DateTime();
$oDate->modify('+111402189 seconds');
var_dump($oDate);
var_dump(date_diff_array(new DateTime(), $oDate));

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
object(DateTime)[2]
  public 'date' => string '2014-04-29 18:52:51' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'America/New_York' (length=16)

array
  'year'   => int 3
  'month'  => int 6
  'week'   => int 1
  'day'    => int 4
  'hour'   => int 9
  'minute' => int 3
  'second' => int 8

我从这里得到了最初的想法,我对其进行了修改以供使用(我希望我的修改也会显示在那个页面上)。

通过从$aIntervals数组中删除它们,或者添加$aExclude参数,或者在输出字符串时过滤掉它们,可以非常容易地删除不需要的间隔(比如"周")。


1
2
3
4
5
<?php
    $today = strtotime("2011-02-03 00:00:00");
    $myBirthDate = strtotime("1964-10-30 00:00:00");
    printf("Days since my birthday:", ($today - $myBirthDate)/60/60/24);
?>


我不知道您是否在使用PHP框架,但许多PHP框架都有日期/时间库和帮助程序,以帮助您避免重新设计方向盘。

例如,codeigner具有timespan()功能。只需输入两个Unix时间戳,它就会自动生成这样的结果:

1
1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes

http://codeigner.com/user_-guide/helpers/date_-helper.html


使用实例:

1
2
echo time_diff_string('2013-05-01 00:22:35', 'now');
echo time_diff_string('2013-05-01 00:22:35', 'now', true);

输出:

1
2
4 months ago
4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago

功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function time_diff_string($from, $to, $full = false) {
    $from = new DateTime($from);
    $to = new DateTime($to);
    $diff = $to->diff($from);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;

    $string = array(
        'y' => 'year',
        'm' => 'month',
        'w' => 'week',
        'd' => 'day',
        'h' => 'hour',
        'i' => 'minute',
        's' => 'second',
    );
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
        } else {
            unset($string[$k]);
        }
    }

    if (!$full) $string = array_slice($string, 0, 1);
    return $string ? implode(', ', $string) . ' ago' : 'just now';
}


我有一些简单的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
    per_days_diff('2011-12-12','2011-12-29')
    function per_days_diff($start_date, $end_date) {
        $per_days = 0;
        $noOfWeek = 0;
        $noOfWeekEnd = 0;
        $highSeason=array("7","8");

        $current_date = strtotime($start_date);
        $current_date += (24 * 3600);
        $end_date = strtotime($end_date);

        $seassion = (in_array(date('m', $current_date), $highSeason))?"2":"1";

        $noOfdays = array('');

        while ($current_date <= $end_date) {
            if ($current_date <= $end_date) {
                $date = date('N', $current_date);
                array_push($noOfdays,$date);
                $current_date = strtotime('+1 day', $current_date);
            }
        }

        $finalDays = array_shift($noOfdays);
        //print_r($noOfdays);
        $weekFirst = array("week"=>array(),"weekEnd"=>array());
        for($i = 0; $i < count($noOfdays); $i++)
        {
            if ($noOfdays[$i] == 1)
            {
                //echo"This is week";
                //echo"<br/>";
                if($noOfdays[$i+6]==7)
                {
                    $noOfWeek++;
                    $i=$i+6;
                }
                else
                {
                    $per_days++;
                }
                //array_push($weekFirst["week"],$day);
            }
            else if($noOfdays[$i]==5)
            {
                //echo"This is weekend";
                //echo"<br/>";
                if($noOfdays[$i+2] ==7)
                {
                    $noOfWeekEnd++;
                    $i = $i+2;
                }
                else
                {
                    $per_days++;
                }
                //echo"After weekend value:-".$i;
                //echo"<br/>";
            }
            else
            {
                $per_days++;
            }
        }

        /*echo $noOfWeek;
          echo"<br/>";
          echo $noOfWeekEnd;
          echo"<br/>";
          print_r($per_days);
          echo"<br/>";
          print_r($weekFirst);
        */


        $duration = array("weeks"=>$noOfWeek,"weekends"=>$noOfWeekEnd,"perDay"=>$per_days,"seassion"=>$seassion);
        return $duration;
      ?>


这是我的职责。所需php>=5.3.4。它使用日期时间类。很快,很快,可以做两个日期之间的差异,甚至所谓的"时间从"。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
if(function_exists('grk_Datetime_Since') === FALSE){
    function grk_Datetime_Since($From, $To='', $Prefix='', $Suffix=' ago', $Words=array()){
        #   Est-ce qu'on calcul jusqu'à un moment précis ? Probablement pas, on utilise maintenant
       if(empty($To) === TRUE){
            $To = time();
        }

        #   On va s'assurer que $From est numérique
       if(is_int($From) === FALSE){
            $From = strtotime($From);
        };

        #   On va s'assurer que $To est numérique
       if(is_int($To) === FALSE){
            $To = strtotime($To);
        }

        #   On a une erreur ?
       if($From === FALSE OR $From === -1 OR $To === FALSE OR $To === -1){
            return FALSE;
        }

        #   On va créer deux objets de date
       $From = new DateTime(@date('Y-m-d H:i:s', $From), new DateTimeZone('GMT'));
        $To   = new DateTime(@date('Y-m-d H:i:s', $To), new DateTimeZone('GMT'));

        #   On va calculer la différence entre $From et $To
       if(($Diff = $From->diff($To)) === FALSE){
            return FALSE;
        }

        #   On va merger le tableau des noms (par défaut, anglais)
       $Words = array_merge(array(
            'year'      => 'year',
            'years'     => 'years',
            'month'     => 'month',
            'months'    => 'months',
            'week'      => 'week',
            'weeks'     => 'weeks',
            'day'       => 'day',
            'days'      => 'days',
            'hour'      => 'hour',
            'hours'     => 'hours',
            'minute'    => 'minute',
            'minutes'   => 'minutes',
            'second'    => 'second',
            'seconds'   => 'seconds'
        ), $Words);

        #   On va créer la cha?ne maintenant
       if($Diff->y > 1){
            $Text = $Diff->y.' '.$Words['years'];
        } elseif($Diff->y == 1){
            $Text = '1 '.$Words['year'];
        } elseif($Diff->m > 1){
            $Text = $Diff->m.' '.$Words['months'];
        } elseif($Diff->m == 1){
            $Text = '1 '.$Words['month'];
        } elseif($Diff->d > 7){
            $Text = ceil($Diff->d/7).' '.$Words['weeks'];
        } elseif($Diff->d == 7){
            $Text = '1 '.$Words['week'];
        } elseif($Diff->d > 1){
            $Text = $Diff->d.' '.$Words['days'];
        } elseif($Diff->d == 1){
            $Text = '1 '.$Words['day'];
        } elseif($Diff->h > 1){
            $Text = $Diff->h.' '.$Words['hours'];
        } elseif($Diff->h == 1){
            $Text = '1 '.$Words['hour'];
        } elseif($Diff->i > 1){
            $Text = $Diff->i.' '.$Words['minutes'];
        } elseif($Diff->i == 1){
            $Text = '1 '.$Words['minute'];
        } elseif($Diff->s > 1){
            $Text = $Diff->s.' '.$Words['seconds'];
        } else {
            $Text = '1 '.$Words['second'];
        }

        return $Prefix.$Text.$Suffix;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// If you just want to see the year difference then use this function.
// Using the logic I've created you may also create month and day difference
// which I did not provide here so you may have the efforts to use your brain.
// :)
$date1='2009-01-01';
$date2='2010-01-01';
echo getYearDifference ($date1,$date2);
function getYearDifference($date1=strtotime($date1),$date2=strtotime($date2)){
    $year = 0;
    while($date2 > $date1 = strtotime('+1 year', $date1)){
        ++$year;
    }
    return $year;
}


我更喜欢使用date_createdate_diff对象。

代码:

1
2
3
4
5
6
$date1 = date_create("2007-03-24");
$date2 = date_create("2009-06-26");

$dateDifference = date_diff($date1, $date2)->format('%y years, %m months and %d days');

echo $dateDifference;

输出:

1
2 years, 3 months and 2 days

更多信息,请阅读php date_diff手册。

According to manual date_diff is an alias of
DateTime::diff()


你可以使用

函数,返回包含所提供日期/时间的所有元素的数组:

1
2
3
$diff = abs($endDate - $startDate);
$my_t=getdate($diff);
print("$my_t[year] years, $my_t[month] months and $my_t[mday] days");

如果开始日期和结束日期是字符串格式,则使用

1
2
$startDate = strtotime($startDateStr);
$endDate = strtotime($endDateStr);

在上述代码之前


这将尝试检测是否提供了时间戳,并将以负值返回将来的日期/时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
<?php

function time_diff($start, $end = NULL, $convert_to_timestamp = FALSE) {
  // If $convert_to_timestamp is not explicitly set to TRUE,
  // check to see if it was accidental:
  if ($convert_to_timestamp || !is_numeric($start)) {
    // If $convert_to_timestamp is TRUE, convert to timestamp:
    $timestamp_start = strtotime($start);
  }
  else {
    // Otherwise, leave it as a timestamp:
    $timestamp_start = $start;
  }
  // Same as above, but make sure $end has actually been overridden with a non-null,
  // non-empty, non-numeric value:
  if (!is_null($end) && (!empty($end) && !is_numeric($end))) {
    $timestamp_end = strtotime($end);
  }
  else {
    // If $end is NULL or empty and non-numeric value, assume the end time desired
    // is the current time (useful for age, etc):
    $timestamp_end = time();
  }
  // Regardless, set the start and end times to an integer:
  $start_time = (int) $timestamp_start;
  $end_time = (int) $timestamp_end;

  // Assign these values as the params for $then and $now:
  $start_time_var = 'start_time';
  $end_time_var = 'end_time';
  // Use this to determine if the output is positive (time passed) or negative (future):
  $pos_neg = 1;

  // If the end time is at a later time than the start time, do the opposite:
  if ($end_time <= $start_time) {
    $start_time_var = 'end_time';
    $end_time_var = 'start_time';
    $pos_neg = -1;
  }

  // Convert everything to the proper format, and do some math:
  $then = new DateTime(date('Y-m-d H:i:s', $$start_time_var));
  $now = new DateTime(date('Y-m-d H:i:s', $$end_time_var));

  $years_then = $then->format('Y');
  $years_now = $now->format('Y');
  $years = $years_now - $years_then;

  $months_then = $then->format('m');
  $months_now = $now->format('m');
  $months = $months_now - $months_then;

  $days_then = $then->format('d');
  $days_now = $now->format('d');
  $days = $days_now - $days_then;

  $hours_then = $then->format('H');
  $hours_now = $now->format('H');
  $hours = $hours_now - $hours_then;

  $minutes_then = $then->format('i');
  $minutes_now = $now->format('i');
  $minutes = $minutes_now - $minutes_then;

  $seconds_then = $then->format('s');
  $seconds_now = $now->format('s');
  $seconds = $seconds_now - $seconds_then;

  if ($seconds < 0) {
    $minutes -= 1;
    $seconds += 60;
  }
  if ($minutes < 0) {
    $hours -= 1;
    $minutes += 60;
  }
  if ($hours < 0) {
    $days -= 1;
    $hours += 24;
  }
  $months_last = $months_now - 1;
  if ($months_now == 1) {
    $years_now -= 1;
    $months_last = 12;
  }

  //"Thirty days hath September, April, June, and November" ;)
  if ($months_last == 9 || $months_last == 4 || $months_last == 6 || $months_last == 11) {
    $days_last_month = 30;
  }
  else if ($months_last == 2) {
    // Factor in leap years:
    if (($years_now % 4) == 0) {
      $days_last_month = 29;
    }
    else {
      $days_last_month = 28;
    }
  }
  else {
    $days_last_month = 31;
  }
  if ($days < 0) {
    $months -= 1;
    $days += $days_last_month;
  }
  if ($months < 0) {
    $years -= 1;
    $months += 12;
  }

  // Finally, multiply each value by either 1 (in which case it will stay the same),
  // or by -1 (in which case it will become negative, for future dates).
  // Note: 0 * 1 == 0 * -1 == 0
  $out = new stdClass;
  $out->years = (int) $years * $pos_neg;
  $out->months = (int) $months * $pos_neg;
  $out->days = (int) $days * $pos_neg;
  $out->hours = (int) $hours * $pos_neg;
  $out->minutes = (int) $minutes * $pos_neg;
  $out->seconds = (int) $seconds * $pos_neg;
  return $out;
}

示例用法:

1
2
3
4
5
<?php
  $birthday = 'June 2, 1971';
  $check_age_for_this_date = 'June 3, 1999 8:53pm';
  $age = time_diff($birthday, $check_age_for_this_date)->years;
  print $age;// 28

或:

1
2
3
4
<?php
  $christmas_2020 = 'December 25, 2020';
  $countdown = time_diff($christmas_2020);
  print_r($countdown);

我在下面的页面上找到了您的文章,其中包含了一些PHP日期时间计算的参考资料。

使用PHP计算两个日期(和时间)之间的差异。下一页提供了一系列不同的方法(共7种),用于使用PHP执行日期/时间计算,以确定两个日期之间的时间差(小时、弹药)、天、月或年。

请参阅php date time–7方法来计算两个日期之间的差异。


如果日期存储在MySQL中,我发现在数据库级别进行差异计算更容易…然后根据天、小时、分钟、秒的输出,分析并显示适当的结果…

1
2
3
4
5
6
7
8
9
10
mysql> select firstName, convert_tz(loginDate, '+00:00', '-04:00') as loginDate, TIMESTAMPDIFF(DAY, loginDate, now()) as 'Day', TIMESTAMPDIFF(HOUR, loginDate, now())+4 as 'Hour', TIMESTAMPDIFF(MINUTE, loginDate, now())+(60*4) as 'Min', TIMESTAMPDIFF(SECOND, loginDate, now())+(60*60*4) as 'Sec' from User_ where userId != '10158' AND userId != '10198' group by emailAddress order by loginDate desc;
 +-----------+---------------------+------+------+------+--------+
 | firstName | loginDate           | Day  | Hour | Min  | Sec    |
 +-----------+---------------------+------+------+------+--------+
 | Peter     | 2014-03-30 18:54:40 |    0 |    4 |  244 |  14644 |
 | Keith     | 2014-03-30 18:54:11 |    0 |    4 |  244 |  14673 |
 | Andres    | 2014-03-28 09:20:10 |    2 |   61 | 3698 | 221914 |
 | Nadeem    | 2014-03-26 09:33:43 |    4 |  109 | 6565 | 393901 |
 +-----------+---------------------+------+------+------+--------+
 4 rows in set (0.00 sec)

您还可以使用以下代码按四舍五入法返回日期差异$date1=$dueDate;//指定到期日期echo$date2=日期("y-m-d");//当前日期$ts1=strtotime($date1);$ts2=strtotime($date2);$seconds_diff=$ts1-$ts2;echo$datediff=ceil(($seconds_diff/3600)/24);//以天为单位返回

如果使用PHP的floor方法而不是CEIL,它将返回舍入分数。请检查这里的差异,有时如果您的临时服务器时区与活动站点时区不同,在这种情况下,您可能会得到不同的结果,因此请相应地更改条件。


1
2
3
4
$date1 = date_create('2007-03-24');
$date2 = date_create('2009-06-26');
$interval = date_diff($date1, $date2);
echo"difference :" . $interval->y ." years," . $interval->m." months,".$interval->d." days";


您始终可以使用以下函数返回以年和月为单位的年龄(即1年4个月)

1
2
3
4
5
6
7
8
9
10
function getAge($dob, $age_at_date)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime($age_at_date);
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}

或者,如果希望在当前日期计算年龄,可以使用

1
2
3
4
5
6
7
8
9
10
function getAge($dob)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime(date());
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}

对于php版本>=5.3:创建两个日期对象,然后使用date_diff()函数。它将返回php-dateinterval对象。参见文档

1
2
3
4
$date1=date_create("2007-03-24");
$date2=date_create("2009-06-26");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");

前段时间我写了一个format_date函数,因为它提供了许多关于你想要约会的选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function format_date($date, $type, $seperator="-")
{
    if($date)
    {
        $day = date("j", strtotime($date));
        $month = date("n", strtotime($date));
        $year = date("Y", strtotime($date));
        $hour = date("H", strtotime($date));
        $min = date("i", strtotime($date));
        $sec = date("s", strtotime($date));

        switch($type)
        {
            case 0:  $date = date("Y".$seperator."m".$seperator."d",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 1:  $date = date("D, F j, Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 2:  $date = date("d".$seperator."m".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 3:  $date = date("d".$seperator."M".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 4:  $date = date("d".$seperator."M".$seperator."Y h:i A",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 5:  $date = date("m".$seperator."d".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 6:  $date = date("M",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 7:  $date = date("Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 8:  $date = date("j",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 9:  $date = date("n",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 10:
                     $diff = abs(strtotime($date) - strtotime(date("Y-m-d h:i:s")));
                     $years = floor($diff / (365*60*60*24));
                     $months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
                     $days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));
                     $date = $years ." years," . $months ." months," . $days ."days";
        }
    }
    return($date);
}


我和php 5.2有同样的问题,并用mysql解决了它。可能不是你想要的,但这将起到关键作用并返回天数:

1
2
3
4
$datediff_q = $dbh->prepare("SELECT DATEDIFF(:date2, :date1)");
$datediff_q->bindValue(':date1', '2007-03-24', PDO::PARAM_STR);
$datediff_q->bindValue(':date2', '2009-06-26', PDO::PARAM_STR);
$datediff = ($datediff_q->execute()) ? $datediff_q->fetchColumn(0) : false;

有关详细信息,请访问http://dev.mysql.com/doc/refman/5.5/en/date and time functions.html function datediff


因为每个人都在发布代码示例,这里是另一个版本。

我想要一个函数来显示从秒到年的差异(只有一个单位)。对于超过1天的时段,我希望它在午夜滚动(周一上午10点从周三上午9点看是2天前,而不是1)。在超过一个月的时间段内,我希望滚动到一个月的同一天(包括30/31天的月份和闰年)。

这就是我想到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * Returns how long ago something happened in the past, showing it
 * as n seconds / minutes / hours / days / weeks / months / years ago.
 *
 * For periods over a day, it rolls over at midnight (so doesn't depend
 * on current time of day), and it correctly accounts for month-lengths
 * and leap-years (months and years rollover on current day of month).
 *
 * $param string $timestamp in DateTime format
 * $return string description of interval
 */

function ago($timestamp)
{
    $then = date_create($timestamp);

    // for anything over 1 day, make it rollover on midnight
    $today = date_create('tomorrow'); // ie end of today
    $diff = date_diff($then, $today);

    if ($diff->y > 0) return $diff->y.' year'.($diff->y>1?'s':'').' ago';
    if ($diff->m > 0) return $diff->m.' month'.($diff->m>1?'s':'').' ago';
    $diffW = floor($diff->d / 7);
    if ($diffW > 0) return $diffW.' week'.($diffW>1?'s':'').' ago';
    if ($diff->d > 1) return $diff->d.' day'.($diff->d>1?'s':'').' ago';

    // for anything less than 1 day, base it off 'now'
    $now = date_create();
    $diff = date_diff($then, $now);

    if ($diff->d > 0) return 'yesterday';
    if ($diff->h > 0) return $diff->h.' hour'.($diff->h>1?'s':'').' ago';
    if ($diff->i > 0) return $diff->i.' minute'.($diff->i>1?'s':'').' ago';
    return $diff->s.' second'.($diff->s==1?'':'s').' ago';
}


非常简单:

1
2
3
4
5
6
7
8
    <?php
        $date1 = date_create("2007-03-24");
        echo"Start date:".$date1->format("Y-m-d")."";
        $date2 = date_create("2009-06-26");
        echo"End date:".$date2->format("Y-m-d")."";
        $diff = date_diff($date1,$date2);
        echo"Difference between start date and end date:".$diff->format("%y years, %m months and %d days")."";
    ?>

有关详细信息,请签出以下链接:

php:日期差异-手动

请注意,它适用于php 5.3.0或更高版本。


简单的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function time_difference($time_1, $time_2, $limit = null)
{

    $val_1 = new DateTime($time_1);
    $val_2 = new DateTime($time_2);

    $interval = $val_1->diff($val_2);

    $output = array(
       "year" => $interval->y,
       "month" => $interval->m,
       "day" => $interval->d,
       "hour" => $interval->h,
       "minute" => $interval->i,
       "second" => $interval->s
    );

    $return ="";
    foreach ($output AS $key => $value) {

        if ($value == 1)
            $return .= $value ."" . $key ."";
        elseif ($value >= 1)
            $return .= $value ."" . $key ."s";

        if ($key == $limit)
            return trim($return);
    }
    return trim($return);
}

类使用

echo time_difference ($time_1, $time_2,"day");

会像2 years 8 months 2 days一样回来


DateInterval很好,但它有几个警告:

  • 只适用于php 5.3+(但这已经不是一个好的借口了)
  • 仅支持年、月、日、小时、分钟和秒(无周)
  • 它计算上述所有+天的差额(您不能只在几个月内得到差额)
  • 为了克服这个问题,我编写了以下代码(从@enobrev answer改进而来):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    function date_dif($since, $until, $keys = 'year|month|week|day|hour|minute|second')
    {
        $date = array_map('strtotime', array($since, $until));

        if ((count($date = array_filter($date, 'is_int')) == 2) && (sort($date) === true))
        {
            $result = array_fill_keys(explode('|', $keys), 0);

            foreach (preg_grep('~^(?:year|month)~i', $result) as $key => $value)
            {
                while ($date[1] >= strtotime(sprintf('+%u %s', $value + 1, $key), $date[0]))
                {
                    ++$value;
                }

                $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);
            }

            foreach (preg_grep('~^(?:year|month)~i', $result, PREG_GREP_INVERT) as $key => $value)
            {
                if (($value = intval(abs($date[0] - $date[1]) / strtotime(sprintf('%u %s', 1, $key), 0))) > 0)
                {
                    $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);
                }
            }

            return $result;
        }

        return false;
    }

    它运行两个循环;第一个循环通过蛮力处理相对间隔(年和月),第二个循环使用简单的算法计算额外的绝对间隔(因此速度更快):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    echo humanize(date_dif('2007-03-24', '2009-07-31', 'second')); // 74300400 seconds
    echo humanize(date_dif('2007-03-24', '2009-07-31', 'minute|second')); // 1238400 minutes, 0 seconds
    echo humanize(date_dif('2007-03-24', '2009-07-31', 'hour|minute|second')); // 20640 hours, 0 minutes, 0 seconds
    echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|day')); // 2 years, 129 days
    echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week')); // 2 years, 18 weeks
    echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week|day')); // 2 years, 18 weeks, 3 days
    echo humanize(date_dif('2007-03-24', '2009-07-31')); // 2 years, 4 months, 1 week, 0 days, 0 hours, 0 minutes, 0 seconds

    function humanize($array)
    {
        $result = array();

        foreach ($array as $key => $value)
        {
            $result[$key] = $value . ' ' . $key;

            if ($value != 1)
            {
                $result[$key] .= 's';
            }
        }

        return implode(', ', $result);
    }


    一分钱换一英镑:我刚刚回顾了几个解决方案,所有这些解决方案都使用floor()提供了一个复杂的解决方案,然后汇总到26年12个月2天的解决方案,应该是25年11个月20天!!!!!

    这是我对这个问题的看法:可能不优雅,可能没有很好的编码,但如果不计算闰年,则提供了更接近答案的方法,显然,闰年可以编码成这个,但在这种情况下-正如其他人所说,也许您可以提供这个答案:我已经包含了所有测试条件和打印结果,以便您更清楚地看到结果的结构:这里,

    //设置输入日期/变量:

    1
    2
    $ISOstartDate   ="1987-06-22";
    $ISOtodaysDate ="2013-06-22";

    //我们需要将iso yyyy-mm-dd格式分解为yy-mm-dd,如下所示:

    $ydate[]=爆炸("-",$isoStartDate);打印($ydate);

    $zdate[]=爆炸("-",$isotodaysdate);打印($zdate);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    // Lets Sort of the Years!
    // Lets Sort out the difference in YEARS between startDate and todaysDate ::
    $years = $zDate[0][0] - $yDate[0][0];

    // We need to collaborate if the month = month = 0, is before or after the Years Anniversary ie 11 months 22 days or 0 months 10 days...
    if ($months == 0 and $zDate[0][1] > $ydate[0][1]) {
        $years = $years -1;
    }
    // TEST result
    echo"
    Current years =>"
    .$years;

    // Lets Sort out the difference in MONTHS between startDate and todaysDate ::
    $months = $zDate[0][1] - $yDate[0][1];

    // TEST result
    echo"
    Current months =>"
    .$months;

    // Now how many DAYS has there been - this assumes that there is NO LEAP years, so the calculation is APPROXIMATE not 100%
    // Lets cross reference the startDates Month = how many days are there in each month IF m-m = 0 which is a years anniversary
    // We will use a switch to check the number of days between each month so we can calculate days before and after the years anniversary

    switch ($yDate[0][1]){
        case 01:    $monthDays = '31';  break;  // Jan
        case 02:    $monthDays = '28';  break;  // Feb
        case 03:    $monthDays = '31';  break;  // Mar
        case 04:    $monthDays = '30';  break;  // Apr
        case 05:    $monthDays = '31';  break;  // May
        case 06:    $monthDays = '30';  break;  // Jun
        case 07:    $monthDays = '31';  break;  // Jul
        case 08:    $monthDays = '31';  break;  // Aug
        case 09:    $monthDays = '30';  break;  // Sept
        case 10:    $monthDays = '31';  break;  // Oct
        case 11:    $monthDays = '30';  break;  // Nov
        case 12:    $monthDays = '31';  break;  // Dec
    };
    // TEST return
    echo"
    Days in start month"
    .$yDate[0][1]." =>".$monthDays;


    // Lets correct the problem with 0 Months - is it 11 months + days, or 0 months +days???

    $days = $zDate[0][2] - $yDate[0][2] +$monthDays;
    echo"
    Current days =>"
    .$days."
    "
    ;

    // Lets now Correct the months to being either 11 or 0 Months, depending upon being + or - the years Anniversary date
    // At the same time build in error correction for Anniversary dates not being 1yr 0m 31d... see if ($days == $monthDays )
    if($days < $monthDays && $months == 0)
        {
        $months = 11;       // If Before the years anniversary date
        }
    else    {
        $months = 0;        // If After the years anniversary date
        $years = $years+1;  // Add +1 to year
        $days = $days-$monthDays;   // Need to correct days to how many days after anniversary date
        };
    // Day correction for Anniversary dates
    if ($days == $monthDays )   // if todays date = the Anniversary DATE! set days to ZERO
        {
        $days = 0;          // days set toZERO so 1 years 0 months 0 days
        };

        echo"
    Therefore, the number of years/ months/ days/
    between start and todays date::

    "
    ;

        printf("%d years, %d months, %d days
    "
    , $years, $months, $days);

    最终结果是:26年,0个月,0天

    这就是我在2013年6月22日经商的时间-哎呀!


    当php 5.3(分别是date_diff())不可用时,我正在使用我编写的以下函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
            function dateDifference($startDate, $endDate)
            {
                $startDate = strtotime($startDate);
                $endDate = strtotime($endDate);
                if ($startDate === false || $startDate < 0 || $endDate === false || $endDate < 0 || $startDate > $endDate)
                    return false;

                $years = date('Y', $endDate) - date('Y', $startDate);

                $endMonth = date('m', $endDate);
                $startMonth = date('m', $startDate);

                // Calculate months
                $months = $endMonth - $startMonth;
                if ($months <= 0)  {
                    $months += 12;
                    $years--;
                }
                if ($years < 0)
                    return false;

                // Calculate the days
                $measure = ($months == 1) ? 'month' : 'months';
                $days = $endDate - strtotime('+' . $months . ' ' . $measure, $startDate);
                $days = date('z', $days);  

                return array($years, $months, $days);
            }

    使用date_diff()尝试这个非常简单的答案,这是经过测试的。

    1
    2
    3
    4
    5
    6
    7
    8
    $date1 = date_create("2017-11-27");
    $date2 = date_create("2018-12-29");
    $diff=date_diff($date1,$date2);
    $months = $diff->format("%m months");
    $years = $diff->format("%y years");
    $days = $diff->format("%d days");

    echo $years .' '.$months.' '.$days;

    输出是:

    1
    1 years 1 months 2 days

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    $date = '2012.11.13';
    $dateOfReturn = '2017.10.31';

    $substract = str_replace('.', '-', $date);

    $substract2 = str_replace('.', '-', $dateOfReturn);



    $date1 = $substract;
    $date2 = $substract2;

    $ts1 = strtotime($date1);
    $ts2 = strtotime($date2);

    $year1 = date('Y', $ts1);
    $year2 = date('Y', $ts2);

    $month1 = date('m', $ts1);
    $month2 = date('m', $ts2);

    echo $diff = (($year2 - $year1) * 12) + ($month2 - $month1);

    这是可运行代码

    1
    2
    3
    4
    5
    $date1 = date_create('2007-03-24');
    $date2 = date_create('2009-06-26');
    $diff1 = date_diff($date1,$date2);
    $daysdiff = $diff1->format("%R%a");
    $daysdiff = abs($daysdiff);