Bug #69044 [Com]: time_sleep_until() starts to early
| From: | phpbugs at canavan dot de | Date: | Wed, 02 Oct 2019 15:46:56 +0000 |
| Subject: | Bug #69044 [Com]: time_sleep_until() starts to early | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-222991@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=69044&edit=1
ID: 69044
Comment by: phpbugs at canavan dot de
Reported by: marc at gutt dot it
Summary: time_sleep_until() starts to early
Status: Closed
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:
The behaviour of the following code has changed with this fix. It used to produce different
timestamps for the two test files. With the fix for this bug, the timestamps are always the same,
which is kind of unexpected.
We have worked around this (or implemented this properly, depending on how one sees this) by waiting
for fstat($f)['mtime'] on a freshly modified file to change, instead of waiting for time()
to change.
<?php
$f = tmpfile();
$start = time();
print('old time: '.fstat($f)['mtime']. "\n");
fclose($f);
/* wait for the next second */
do { } while ($start == time());
$f = tmpfile();
$start = time();
print('new time: '.fstat($f)['mtime']. "\n");
fclose($f);
Previous Comments:
------------------------------------------------------------------------
[2019-06-19 07:08:02] krakjoe@php.net
The fix for this bug has been committed.
Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
For Windows:
http://windows.php.net/snapshots/
Thank you for the report, and for helping us make PHP better.
------------------------------------------------------------------------
[2019-06-17 13:57:41] nikic@php.net
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.
------------------------------------------------------------------------
[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);
?>
------------------------------------------------------------------------
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