16

I am trying to get the time passed between two datetime strings (including milliseconds)

example:

$pageTime = strtotime("2012-04-23T16:08:14.9-05:00");
$rowTime = strtotime("2012-04-23T16:08:16.1-05:00");
$timePassed = $rowTime - $pageTime;
echo $timePassed . "<br/><br/>";

What I want to see echoed is "1.2" but strtotime() ignores the millisecond part of the string. Also, apparently microtime() doesn't let you give it a datestring... Is there an alternative function for calculating this, or am I going to have to do some string parsing to extract the seconds and milliseconds and subtract?

slinkhi
  • 947
  • 4
  • 16
  • 32

2 Answers2

13

Try it with DateTime instead.

This needs a bit of a workaround because DateInterval (which is returned by DateTime::diff()) doesn't calculate the microseconds, so you need to this by hand

$pageTime = new DateTime("2012-04-23T16:08:14.1 - 5 hours");
$rowTime  = new DateTime("2012-04-23T16:08:16.9 - 5 hours");

// the difference through one million to get micro seconds
$uDiff = abs($pageTime->format('u')-$rowTime->format('u')) / (1000 * 1000);

$diff = $pageTime->diff($rowTime);

echo $diff->format('%s')-$uDiff;

I always recommend DateTime because of its flexibility, you should look into it

EDIT

For backwards compability to PHP 5.2 it takes the same approach as for the milliseconds:

$pageTime = new DateTime("2012-04-23T16:08:14.1 - 5 hours");
$rowTime  = new DateTime("2012-04-23T16:08:16.9 - 5 hours");

// the difference through one million to get micro seconds
$uDiff = abs($pageTime->format('u')-$rowTime->format('u')) / (1000 * 1000);


$pageTimeSeconds = $pageTime->format('s');
$rowTimeSeconds  = $rowTime->format('s');

if ($pageTimeSeconds + $rowTimeSeconds > 60) {
  $sDiff = ($rowTimeSeconds + $pageTimeSeconds)-60;
} else {
  $sDiff = $pageTimeSeconds - $rowTimeSeconds;
}


if ($sDiff < 0) {
  echo abs($sDiff) + $uDiff;
} else {
  // for the edge(?) case if $dt2 was smaller than $dt
  echo abs($sDiff - $uDiff);
}
dan-lee
  • 14,365
  • 5
  • 52
  • 77
  • darn...this looks promising but it requires 5.3+ and I'm on 5.2 and I have no control over upgrading :( +1 though – slinkhi Apr 23 '12 at 22:43
  • That is because of `DateTime::diff()`. This means you would need to do that substraction manually too, see my edit :). – dan-lee Apr 23 '12 at 22:50
  • I see...well in general, this looks like it helps extract the data easier (as opposed to using regex) but I think your math/logic is off. For instance if I have `$pageTime = new DateTime("2012-04-23T16:08:14.662-05:00"); $rowTime = new DateTime("2012-04-23T16:08:19.954-05:00");` I should be getting `5.292` but it is outputting `4.708`. Also, your code only addresses a difference in time between seconds and microseconds. What happens if you start with `2012-04-23T16:08:59.9-05:00` and end with `2012-04-23T16:09:00.1-05:00` you should get `0.2` but your code gives me `58.2`..(cont'd) – slinkhi Apr 23 '12 at 23:38
  • ..so yeah, I think this is a great start for parsing the parts but needs some more love. Thanks for pointing me in a good direction :) – slinkhi Apr 23 '12 at 23:39
  • sure! i just made another edit to cover your cases. i am not sure if it really covers all, but it may help you. please keep me up to date :) – dan-lee Apr 23 '12 at 23:57
  • okay i am sorry it doesnt really cover everything, it's just too much manual work. i'll look over it tomorrow again – dan-lee Apr 24 '12 at 00:02
  • Is it me or is that `abs(...)` call corrupting the output? – Niels Keurentjes Jul 27 '15 at 09:23
  • I believe the line `echo $diff->format('%s')-$uDiff;` should read `echo $diff->format('%s') + $uDiff;` ? – SeBsZ Aug 31 '18 at 13:36
1

Building on Dan Lee's answer, here's a universally working solution:

$pageTime = new DateTime("2012-04-23T16:08:14.9-05:00");
$rowTime  = new DateTime("2012-04-23T16:08:16.1-05:00");

$uDiff = ($rowTime->format('u') - $pageTime->format('u')) / (1000 * 1000);

$timePassed = $rowTime->getTimestamp() - $pageTime->getTimestamp() + $uDiff;

Complete explanations:

  • We store the signed microseconds difference between both dates in $uDiff and convert the result in seconds by dividing by 1000 * 1000
  • The order of the operands in $uDiff is important and has to be the same as in the $timePassed operation.
  • We compute the Unix timestamp (in full seconds) difference between both dates and we add the microseconds difference to get the wanted result
  • Using DateTime::getTimestamp() will give a correct answer even when the difference is greater than 60 seconds