如何正确计算两个日期之间的差异 php

How to calculate the difference between 2 dates properly php

我正在尝试计算 php 项目的两个日期之间的差异。

例如: 4 月 2 日和 6 月 1 日有什么区别?

第一种计算差值的方法
从 4 月 2 日到 5 月 2 日 = 1 个月。从 5 月 2 日到 6 月 1 日 = 30 天。 => 4 月 2 日至 6 月 1 日 = 1 个月零 30 天

计算差值的第二种方法
我们可以算作 1 个月。然后加上从 4 月 2 日到 30 日的天数(28 天)和从 6 月开始的天数(1 天)=> 1 个月零 29 天。

我认为第一种方法是正确的,因为我认为大多数人都是这样计算的。

所以一开始我尝试使用DateTime::diff()函数

function dateDiff($date1, $date2 = false) {
if (!$date2)
    $date2 = date('Y-m-d');

$datetime1 = new DateTime($date1 , new DateTimeZone('EUROPE/Sofia'));
$datetime2 = new DateTime($date2 , new DateTimeZone('EUROPE/Sofia'));

$interval = $datetime1->diff($datetime2);

$y = $interval->format('%y');
$m = $interval->format('%m');
$d = $interval->format('%d');

return $y . " " . $m . " " . $d;

}

但我注意到它没有正确计算差异。 '2015-02-03'和'2015-04-02'之间的差异应该是1个月零30天,(02-03到03-03 = 1个月。那么我们把剩下的天数算到 04-02,也就是 30 天),但是 差异计算结果是 1 个月又 27 天(我猜它是通过我上面提到的第二种方法计算差异)。所以不是计算错误就是第二种方法是正确的计算方式

但是 让我们检查这个例子: 2015-05-01 和 2015-03-31(这次我们倒退)。 diff returns 1个月的差异,我认为应该是1个月零1天

此外,2015-05-01 和 2015-02-28 之间的差异应该是 2 个月和 1 天,但是 diff 函数 returns 2个月零3天.

那么,计算两个日期之间的差异的正确方法是什么? DateTime::diff() 计算正确吗?有没有办法通过第一种方法计算两个日期之间的差异。

Php DateInterval. For now you can try use external implementations like Moment 库存在错误,或者关注错误状态并等待修复。

举个小例子,希望对你有帮助

$date1 = strtotime("2015-01-01"); //yyyy-mm-dd
$date2 = strtotime("2015-01-08");
$datediff = $date2 - $date1;
echo floor($datediff/(60*60*24));

这应该可以正确计算差异。

function monthDiff($m1, $m2) {
    if($m1 > $m2) {
        return 12 - $m1 + $m2;
    }
    return $m2 - $m1;
}

function yearDiff($y1, $y2) {
    return $y2 - $y1;
}


function checkLeapYear($year){
    $year = (int)$year;
    return ( ( ($year % 4 == 0 && ($year % 100) != 0 ) || ( ($year % 100) == 0 && ($year % 400) == 0 ) ) ? 1 : 0);
}


function dateDiff($date1, $date2 = false) {
    if (!$date2)
        $date2 = date('Y-m-d');

    $datetime1 = new DateTime($date1 , new DateTimeZone('EUROPE/Sofia'));
    $datetime2 = new DateTime($date2 , new DateTimeZone('EUROPE/Sofia'));

    if($datetime1 > $datetime2){ //always go from smaller to bigger date
        $temp = $datetime1;
        $datetime1 = $datetime2;
        $datetime2 = $temp; 
    }

    $d1 = (int)$datetime1->format('d');
    $d2 = (int)$datetime2->format('d');

    $m1 = (int)$datetime1->format('m');
    $m2 = (int)$datetime2->format('m');

    $y1 = (int)$datetime1->format('Y');
    $y2 = (int)$datetime2->format('Y');


    $leapYear = checkLeapYear($y1); 
    $daysInMonth1 = [1 => 31, 28 + $leapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // the number of days in the months

    $leapYear = checkLeapYear($y2);
    $daysInMonth2 = [1 => 31, 28 + $leapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];


    $monthCorrection = 0;


    if ($d1 < $d2) {
        $d = $d2 - $d1; 
    }

    if ($d1 > $d2){
        if ($daysInMonth2[$m2] >= $d1){ 
            $d = $daysInMonth1[$m1] - $d1 + $d2;;
        }
        else {
            $d = $daysInMonth1[$m1] - $d1 + $d2;
        }
        $monthCorrection = -1;
    }

    if ($d1 == $d2 ){
        $d = 0;
    }

    $m = monthDiff($m1, $m2) + $monthCorrection;

    $y = yearDiff($y1, $y2);
    if ($m1 > $m2){
        $y--;
    }

    return $y . " years " . $m . " months " . $d . " days";

}