[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.

>    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).

> 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.

[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)

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.
_______________________________________________
Tutor maillist  -  [EMAIL PROTECTED]
http://mail.python.org/mailman/listinfo/tutor

Reply via email to