0

I successfully find (i think) how many microseconds have to pass till the beginning of the next hour but usleep() function shows warning

Number of microseconds must be greater than or equal to 0

$min = (integer)date('i');
$sec = (integer)date('s');
list($microsec, $tmp) = explode(' ', microtime());
$microsec = (integer)str_replace("0.", "", $microsec);
$min_dif = 59 - $min;
$sec_dif = 59 - $sec;
$microsec_dif = 100000000 - $microsec;
$dif_in_micro = $sec_dif * 100000000 + $min_dif * 6000000000 + 
$microsec_dif;
echo $dif_in_micro;
usleep($dif_in_micro);

Thanks a lot for your answers i ended up using the following

$seconds_to_wait = 3540 - (integer)date('i') * 60 + 59 - (integer)date('s');
list($microsec, $tmp) = explode(' ', microtime());
$microsec_to_wait = 1000000 - $microsec * 1000000;
sleep($seconds_to_wait);
usleep($microsec_to_wait);
$now = DateTime::createFromFormat('U.u', microtime(true));
file_put_contents("finish_time.txt", $now->format("m-d-Y H:i:s.u") . PHP_EOL, FILE_APPEND);
Professor Chaos
  • 447
  • 5
  • 11
  • _"I successfully find (i think) how many microseconds have to pass till the beginning of the next hour"_ - You "think"? That should be easy enough to test, right? Just dump the exact time and then see if the microseconds are correct? – M. Eriksson Jun 16 '19 at 11:49
  • 1
    My guess is that the number you have in $diff in micro is larger than what an integer can be and it rotates around to negative. – Andreas Jun 16 '19 at 11:55

2 Answers2

0

In your case your time base is not micro seconds, it is 10ns resolution.

microtime() delivers the time in seconds with 8 decimals. You are stripping the leading 0. and use the eight decimals. You considered this by writing $microsec_dif = 1E8 - $microsec;. You send the result to usleep(), without to compensate for the factor of 100. This gives you a timeout of 100 times of what you intended. And an integer overflow may comes on top.

usleep takes an integer for the time. The maximum is about 2E9 µs. With that limitation you cannot wait for longer than 2000 seconds for a single call.

Here my code:

$TimeNow=microtime(true);
$SecondsSinceLastFullHour = $TimeNow - 3600*floor($TimeNow/3600);
//echo ("Wait " .   (3600 - SecondsSinceLastFullHour) . " seconds.");
$Sleeptime=(3600.0 - $SecondsSinceLastFullHour); //as float
//Maximum of $Sleeptime is 3600    
//usleep(1e6*$Sleeptime); //worst case 3600E6 won't fit into integer.
//...  but 1800E6 does. So lets split the waiting time in to halfes.
usleep(500000*$Sleeptime);
usleep(500000*$Sleeptime);
user5329483
  • 1,260
  • 7
  • 11
  • My goal is to run some code then stop the execution till the beginning of the next hour but I want to have more precision than the seconds can give. That's why I want to use usleep with microseconds instead of sleep. Can you explain why my timebase is not micro seconds? – Professor Chaos Jun 16 '19 at 13:56
  • @Professor Chaos: Answer extended adapted to your request. – user5329483 Jun 16 '19 at 15:19
0

Since you need the higher precision than seconds gives then I think we need to use them both.
First we wait seconds until we are close then we calculate the microseconds and wait again.

$Seconds = (microtime(true) - 3600*floor(microtime(true)/3600))-2;
sleep(3600 - $Seconds);
//Code above should wait until xx:59:58
// Now your code should just work fine below here except we shouldn't need minutes

$sec = (integer)date('s');
list($microsec, $tmp) = explode(' ', microtime());
$microsec = (integer)str_replace("0.", "", $microsec);
$sec_dif = 59 - $sec;
$microsec_dif = 100000000 - $microsec;
$dif_in_micro = $sec_dif * 100000000  + $microsec_dif;
echo $dif_in_micro;
usleep($dif_in_micro);
Andreas
  • 23,610
  • 6
  • 30
  • 62