Tim Peters wrote:

First, thank you for such a brilliant answer :-)

[Dave S <[EMAIL PROTECTED]>]


OK I may be pushing it, ;-)



Yup <wink>.



I need a script to sleep from any point to 8:05AM when in needs to
re-start.

So I calculate the number of seconds with the following ....

def secs_till_805():
  # Returns the number of seconds till 8:05AM

  secs_5min=5*60
  secs_24hr=24*60*60
  secs_8hr=(8*60*60)+secs_5min
  secs_8hr_24hr=secs_24hr-secs_8hr

hours=int(strftime('%H'))
mins=int(strftime('%M'))
secs=int(strftime('%S'))



Ouch. Never try to pick apart the current time by computing it more than once. For example, if the time at the start of that block is just a fraction of a second before 9AM, it's quite possible you'll end up with hours==8 and mins==secs==0 (because the time is 8:59:59 at the time you do the "%H" business, and but it's 9:00:00 by the time you get to "%M"). That would throw you off by an hour. The same kind of thing can happen a little before the (any) minute changes too.



This is a possibility that had not enterd my mind, but also very true. Thanks for saving me from that particular black hole.

Its always that 1 in a thousand possibility that sends things south at the worst possible moment !

  sec_left=secs_24hr-((hours*60*60)+(mins*60)+secs)

  # If we are before 8:05, then ...
  if sec_left>secs_8hr_24hr:
      return sec_left-secs_8hr_24hr

# If we are after 8:05, then ...
return sec_left+secs_8hr



Here's a different way, computing current time only once, and using the datetime module to do all the fiddly work:

def seconds_until(h, m=0, s=0):
   from datetime import datetime, time, timedelta

   target_time = time(h, m, s)
   now = datetime.now()
   target = datetime.combine(now.date(), target_time)
   if target < now:
       target += timedelta(days=1)
   diff = target - now
   return diff.seconds + diff.microseconds / 1e6

This returns seconds as a float, which is good (Python's time.sleep()
can make sense of floats, and sleep for fractional seconds).



OK Im pydoc'ing & looking at datetime, a module I have not explored before. This is stretching me a bit but its a good way to learn.

Then I ...

sleep(secs_till_805())



With the above, you'd do

   time.sleep(seconds_until(8, 5))

instead.



I expected the script to re-start 2-3 seconds after 8:05, python
reloading after a long sleep etc, what I get is the script restarting at
08:04.55, earlier ???



You'll probably never know why for sure. Python calls platform C library gimmicks to sleep, which in turn invoke operating system facilities. Understanding the whole story would require that you understand everything all of those do.



If only I had the time ... (no pun intended)

[later]


It must be cummulative error over 10s of thousands of seconds.



Maybe.



Its a bodge (& cron or at are better) but I suppose I could calculate seconds
to 8:05 sleep(seconds*0.95), re calculate secs to 8:05 sleep(seconds)
which should reduce the error to almost zip.



That's also a good idea in order to avoid surprises due to crossing daylight time boundaries (assuming you mean 8:05 according to the local wall clock). Here's a function building on the above:

def sleep_until(h, m=0, s=0):
   from time import sleep

while True:
delay = seconds_until(h, m, s)
if delay < 10.0:
sleep(delay)
return
else:
sleep(delay / 2)



Thats neat, and more elegent than my hamfisted attempt, I err might borrow it for my code, on a tempory basis you understand ;-)


sleep_secs=secs_till_805()
log('II','ftsed','Sleeping for '+str(sleep_secs)+' Seconds')

# To compensate for the commulative error over 86,000 secs !
sleep(sleep_secs*0.95)
sleep(secs_till_805())

That is, it cuts the sleep time in half repeatedly, until less than 10
seconds remain.  It can sleep for hours at a time, but as the target
time approaches it wakes up more frequently.  This should keep the
program loaded in memory as the target time gets near.




Cheers
Dave
_______________________________________________
Tutor maillist  -  [EMAIL PROTECTED]
http://mail.python.org/mailman/listinfo/tutor

Reply via email to