在 PHP 中获取两个日期间的间隔秒数?

2009年10月5日18:11:08

2009-10-0518:07:13

这个应该生成235,怎么做呢?

126079 次浏览

You can use strtotime() to do that:

$diff = strtotime('2009-10-05 18:11:08') - strtotime('2009-10-05 18:07:13')

A similar approach is possible with DateTime objects, e.g.

$date = new DateTime( '2009-10-05 18:07:13' );
$date2 = new DateTime( '2009-10-05 18:11:08' );


$diff = $date2->getTimestamp() - $date->getTimestamp();
strtotime("2009-10-05 18:11:08") - strtotime("2009-10-05 18:07:13")

PHP Date Time reference is helpful for things like this: PHP Date Time Functions

strtotime() is probably the best way.

$seconds = strtotime('2009-10-05 18:11:08') - strtotime('2009-10-05 18:07:13')

With DateTime objects, you can do it like this:

$date = new DateTime( '2009-10-05 18:07:13' );
$date2 = new DateTime( '2009-10-05 18:11:08' );


$diffInSeconds = $date2->getTimestamp() - $date->getTimestamp();

Because of unix epoch limitations, you could have problems compairing dates before 1970 and after 2038. I choose to loose precision (=don't look at the single second) but avoid to pass trough unix epoch conversions (getTimestamp). It depends on what you are doing to do...

In my case, using 365 instead (12*30) and "30" as mean month lenght, reduced the error in an usable output.

function DateIntervalToSec($start,$end){ // as datetime object returns difference in seconds
$diff = $end->diff($start);
$diff_sec = $diff->format('%r').( // prepend the sign - if negative, change it to R if you want the +, too
($diff->s)+ // seconds (no errors)
(60*($diff->i))+ // minutes (no errors)
(60*60*($diff->h))+ // hours (no errors)
(24*60*60*($diff->d))+ // days (no errors)
(30*24*60*60*($diff->m))+ // months (???)
(365*24*60*60*($diff->y)) // years (???)
);
return $diff_sec;
}

Note that the error could be 0, if "mean" quantities are intended for diff. The PHP docs don't speaks about this... In a bad case, error could be:

  • 0 seconds if diff is applied to time gaps < 1 month
  • 0 to 3 days if diff is applied to time gaps > 1 month
  • 0 to 14 days if diff is applied to time gaps > 1 year

I prefer to suppose that somebody decided to consider "m" as 30 days and "y" as 365, charging "d" with the difference when "diff" walk trough non-30-days months...

If somebody knows something more about this and can provide official documentation, is welcome!

A simple and exact solution (exemplifying Nilz11's comment):

$hiDate = new DateTime("2310-05-22 08:33:26");
$loDate = new DateTime("1910-11-03 13:00:01");
$diff = $hiDate->diff($loDate);
$secs = ((($diff->format("%a") * 24) + $diff->format("%H")) * 60 +
$diff->format("%i")) * 60 + $diff->format("%s");

If you need the real local time difference and want to work with getTimestamp, you must take DST switches during the calculated period into account. Therefore, the local offset to UTC must be included in the equation.

Take, for instance, the following dates:

$tz = new \DateTimeZone("Europe/Berlin");
$start = new \DateTime("2018-02-01 12:00:00", $tz);
$end = new \DateTime("2018-04-01 12:00:00", $tz);

$start is "2018-02-01 11:00:00" in UTC, while $end is "2018-04-01 10:00:00" in UTC. Note that, while the time of day is the same in the Berlin timezone, it is different in UTC. The UTC offset is one hour in $start and 2 hours in $end.

Keep in mind that getTimestamp always returns UTC! Therefore you must subtract the offset from the timestamp when looking for the actual local difference.

// WRONG! returns 5094000, one hour too much due to DST in the local TZ
echo $end->getTimestamp() - $start->getTimestamp();


// CORRECT: returns 5090400
echo ($end->getTimestamp() - $end->getOffset()) - ($start->getTimestamp() - $start->getOffset());

For those worrying about the limitations of using timestamps (i.e. using dates before 1970 and beyond 2038), you can simply calculate the difference in seconds like so:

$start = new DateTime('2009-10-05 18:11:08');
$end = new DateTime('2009-10-05 18:07:13');
$diff = $end->diff($start);


$daysInSecs = $diff->format('%r%a') * 24 * 60 * 60;
$hoursInSecs = $diff->h * 60 * 60;
$minsInSecs = $diff->i * 60;


$seconds = $daysInSecs + $hoursInSecs + $minsInSecs + $diff->s;


echo $seconds; // output: 235

Wrote a blog post for those interested in reading more.

The solution proposed by @designcise is wrong when "end date" is before "start date". Here is the corrected calculation

$diff = $start->diff($end);


$daysInSecs = $diff->format('%r%a') * 24 * 60 * 60;
$hoursInSecs = $diff->format('%r%h') * 60 * 60;
$minsInSecs = $diff->format('%r%i') * 60;


$seconds = $daysInSecs + $hoursInSecs + $minsInSecs + $diff->format('%r%s');