Edit report at https://bugs.php.net/bug.php?id=69044&edit=1
ID: 69044
Updated by: nikic@php.net
Reported by: marc at gutt dot it
Summary: time_sleep_until() starts to early
Status: Assigned
Type: Bug
Package: Date/time related
Operating System: Debian
PHP Version: 5.4.37
Assigned To: selim61
Block user comment: N
Private report: N
New Comment:
Here is the reason for the discrepancy: https://stackoverflow.com/questions/22917318/time-and-gettimeofday-return-different-seconds
TLDR We use two different APIs for time() and microtime() and the latter is not just more precise
when it comes to sub-second resolution, it also calculates the seconds more precisely.
Previous Comments:
------------------------------------------------------------------------
[2015-02-14 13:32:55] marc at gutt dot it
Yes, date() seems to have a bug:
<?php
function udate($format, $timestamp=null) {
if (!isset($timestamp)) $timestamp = microtime();
// microtime(true)
if (count($t = explode(" ", $timestamp)) == 1) {
list($timestamp, $usec) = explode(".", $timestamp);
$usec = "." . $usec;
}
// microtime() is more precise
else {
$usec = $t[0];
$timestamp = $t[1];
}
// 7 decimal places for "u" is maximum
$usec = substr(sprintf('%.7f', $usec), 1);
$date = new DateTime(date('Y-m-d H:i:s' . $usec, $timestamp));
return $date->format($format);
}
echo "### first test ###\n";
$sleep_until = round(microtime(true)) + 3.002;
echo "sleep: " . udate("Y-m-d\TH:i:s.u", $sleep_until) . "\n";
time_sleep_until($sleep_until);
echo "udate: " . udate("Y-m-d\TH:i:s.u", microtime(true)) . "\n";
echo "date : " . date("Y-m-d\TH:i:s") . "\n";
echo "### second test ###\n";
$sleep_until = round(microtime(true)) + 3.003;
echo "sleep: " . udate("Y-m-d\TH:i:s.u", $sleep_until) . "\n";
time_sleep_until($sleep_until);
echo "udate: " . udate("Y-m-d\TH:i:s.u", microtime(true)) . "\n";
echo "date : " . date("Y-m-d\TH:i:s") . "\n";
/* results:
### first test ###
sleep: 2015-02-14T14:29:51.002000
udate: 2015-02-14T14:29:51.002100
date : 2015-02-14T14:29:50
### second test ###
sleep: 2015-02-14T14:29:54.003000
udate: 2015-02-14T14:29:54.003100
date : 2015-02-14T14:29:54
*/
?>
------------------------------------------------------------------------
[2015-02-14 02:00:02] requinix@php.net
By the way, the code works fine on Windows: time() - $sleep_until = 0 consistently. Tried the same
code on Ubuntu 14.04 and would get -1 consistently.
------------------------------------------------------------------------
[2015-02-14 01:44:44] yohgaki@php.net
You can see it's sleeping as it supposed by replacing date() to microtime()
<?php
$sleep_until = microtime(true) + 1;
echo "sleep until " . $sleep_until ."\n";
time_sleep_until($sleep_until);
echo "woke up at " . microtime(true);
?>
------------------------------------------------------------------------
[2015-02-14 01:39:34] yohgaki@php.net
My previous analysis is wrong.
time_sleep_until() sleeps as it supposed. It seems date() is doing something wrong.
------------------------------------------------------------------------
[2015-02-14 00:47:54] yohgaki@php.net
Oops. Round margin should be something like 0.99. Or use ceil() to be precise.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=69044
--
Edit this bug report at https://bugs.php.net/bug.php?id=69044&edit=1