[php] PHP find difference between two datetimes

I'm trying to get the difference between two datetimes and return it as a datetime. I've found examples using diff but I can't seem to get it right.

$timein = date("Y-m-d H:i:s");
$timeout = date("Y-m-d 20:00:00");
$totaltime = $timein->diff($timeout);

However $totaltime logs 0000-00-00 00:00:00 to my DB. Is this because I'm not formatting my totaltime variable?

This question is related to php datetime date-math

The answer is


John Conde does all the right procedures in his method but doesn't satisfy the final step in your question which is to format the result to your specifications.

This code (Demo) will display the raw difference, expose the trouble with trying to immediately format the raw difference, display my preparation steps, and finally present the correctly formatted result:

$datetime1 = new DateTime('2017-04-26 18:13:06');
$datetime2 = new DateTime('2011-01-17 17:13:00');  // change the millenium to see output difference
$diff = $datetime1->diff($datetime2);

// this will get you very close, but it will not pad the digits to conform with your expected format
echo "Raw Difference: ",$diff->format('%y years %m months %d days %h hours %i minutes %s seconds'),"\n";

// Notice the impact when you change $datetime2's millenium from '1' to '2'
echo "Invalid format: ",$diff->format('%Y-%m-%d %H:%i:%s'),"\n";  // only H does it right

$details=array_intersect_key((array)$diff,array_flip(['y','m','d','h','i','s']));

echo '$detail array: ';
var_export($details);
echo "\n";

array_map(function($v,$k)
    use(&$r)
    {
        $r.=($k=='y'?str_pad($v,4,"0",STR_PAD_LEFT):str_pad($v,2,"0",STR_PAD_LEFT));
        if($k=='y' || $k=='m'){$r.="-";}
        elseif($k=='d'){$r.=" ";}
        elseif($k=='h' || $k=='i'){$r.=":";}
    },$details,array_keys($details)
);
echo "Valid format: ",$r; // now all components of datetime are properly padded

Output:

Raw Difference: 6 years 3 months 9 days 1 hours 0 minutes 6 seconds
Invalid format: 06-3-9 01:0:6
$detail array: array (
  'y' => 6,
  'm' => 3,
  'd' => 9,
  'h' => 1,
  'i' => 0,
  's' => 6,
)
Valid format: 0006-03-09 01:00:06

Now to explain my datetime value preparation:

$details takes the diff object and casts it as an array. array_flip(['y','m','d','h','i','s']) creates an array of keys which will be used to remove all irrelevant keys from (array)$diff using array_intersect_key().

Then using array_map() my method iterates each value and key in $details, pads its left side to the appropriate length with 0's, and concatenates the $r (result) string with the necessary separators to conform with requested datetime format.


The code below will show difference for found values only, i.e., if years = 0, then it will not show years.


$diffs = [
    'years' => 'y',
    'months' => 'm',
    'days' => 'd',
    'hours' => 'h',
    'minutes' => 'i',
    'seconds' => 's'
];

$interval = $timeout->diff($timein);
$diffArr = [];
foreach ($diffs as $k => $v) {
    $d = $interval->format('%' . $v);
    if ($d > 0) {
        $diffArr[] = $d . ' ' . $k;
    }
}    
$diffStr = implode(', ', $diffArr);
echo 'Difference: ' . ($diffStr == '' ? '0' : $diffStr) . PHP_EOL;

You can simply use datetime diff and format for calculating difference.

<?php
$datetime1 = new DateTime('2009-10-11 12:12:00');
$datetime2 = new DateTime('2009-10-13 10:12:00');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%Y-%m-%d %H:%i:%s');
?>

For more information OF DATETIME format, refer: here
You can change the interval format in the way,you want.

Here is the working example

P.S. These features( diff() and format()) work with >=PHP 5.3.0 only


I collected many topics to make universal function with many outputs (years, months, days, hours, minutes, seconds) with string or parse to int and direction +- if you need to know what side is direction of the difference.

Use example:



    $date1='2016-05-27 02:00:00';
    $format='Y-m-d H:i:s';

    echo timeDifference($date1, $format, '2017-08-30 00:01:59', $format); 
    #1 years 3 months 2 days 22 hours 1 minutes 59 seconds (string)

    echo timeDifference($date1, $format, '2017-08-30 00:01:59', $format,false, '%a days %h hours');
    #459 days 22 hours (string)

    echo timeDifference('2016-05-27 00:00:00', $format, '2017-08-30 00:01:59', $format,true, '%d days -> %H:%I:%S', true);
    #-3 days -> 00:01:59 (string)

    echo timeDifference($date1, $format, '2016-05-27 00:05:51', $format, false, 'seconds');
    #9 (string)

    echo timeDifference($date1, $format, '2016-05-27 07:00:00', $format, false, 'hours');
    #5 (string)

    echo timeDifference($date1, $format, '2016-05-27 07:00:00', $format, true, 'hours');
    #-5 (string)

    echo timeDifference($date1, $format, '2016-05-27 07:00:00', $format, true, 'hours',true);
    #-5 (int)

Function



    function timeDifference($date1_pm_checked, $date1_format,$date2, $date2_format, $plus_minus=false, $return='all', $parseInt=false)
    {
        $strtotime1=strtotime($date1_pm_checked);
        $strtotime2=strtotime($date2);
        $date1 = new DateTime(date($date1_format, $strtotime1));
        $date2 = new DateTime(date($date2_format, $strtotime2));
        $interval=$date1->diff($date2);

        $plus_minus=(empty($plus_minus)) ? '' : ( ($strtotime1 > $strtotime2) ? '+' : '-'); # +/-/no_sign before value 

        switch($return)
        {
            case 'y';
            case 'year';
            case 'years';
                $elapsed = $interval->format($plus_minus.'%y');
                break;

            case 'm';
            case 'month';
            case 'months';
                $elapsed = $interval->format($plus_minus.'%m');
                break;

            case 'a';
            case 'day';
            case 'days';
                $elapsed = $interval->format($plus_minus.'%a');
                break;

            case 'd';
                $elapsed = $interval->format($plus_minus.'%d');
                break;

            case 'h';       
            case 'hour';        
            case 'hours';       
                $elapsed = $interval->format($plus_minus.'%h');
                break;

            case 'i';
            case 'minute';
            case 'minutes';
                $elapsed = $interval->format($plus_minus.'%i');
                break;

            case 's';
            case 'second';
            case 'seconds';
                $elapsed = $interval->format($plus_minus.'%s');
                break;

            case 'all':
                $parseInt=false;
                $elapsed = $plus_minus.$interval->format('%y years %m months %d days %h hours %i minutes %s seconds');
                break;

            default:
                $parseInt=false;
                $elapsed = $plus_minus.$interval->format($return);
        }

        if($parseInt)
            return (int) $elapsed;
        else
            return $elapsed;

    }


Sorry my previous answer was wrong. If you are trying to take total elapsed time between time and timeout in the format Y-m-d H:i:s format, take diff between timeout and time in using DateTime object and format it as '%y-%m-%d %H:%i:%s'.


Here is my full post with topic: PHP find difference between two datetimes

USAGE EXAMPLE


    echo timeDifference('2016-05-27 02:00:00', 'Y-m-d H:i:s', '2017-08-30 00:01:59', 'Y-m-d H:i:s', false, '%a days %h hours');
    #459 days 22 hours (string)

    echo timeDifference('2016-05-27 02:00:00', 'Y-m-d H:i:s', '2016-05-27 07:00:00', 'Y-m-d H:i:s', true, 'hours',true);
    #-5 (int)