views:

71

answers:

4

Basically, I want my script to pause between 4 and 5 AM. The only way to do this I've come up with so far is this:

seconds_into_day = time.time() % (60*60*24)
if 60*60*4 < seconds_into_day < 60*60*5:
    sleep(time_left_till_5am)

Any "proper" way to do this? Aka some built-in function/lib for calculating time; rather than just using seconds all the time?

+3  A: 

You want datetime

The datetime module supplies classes for manipulating dates and times in both simple and complex ways

If you use date.hour from datetime.now() you'll get the current hour:

datetimenow = datetime.now();
if datetimenow.hour in range(4, 5)
    sleep(time_left_till_5am)

You can calculate time_left_till_5am by taking 60 - datetimenow.minute multiplying by 60 and adding to 60 - datetimenow.second.

ChrisF
Yeah googled that before I posted my question, I still can't think of a way how to use it for my purpose though. Any chance for an example?
Robus
Sorry I can't accept both answers ;-(
Robus
@Robus - no problem.
ChrisF
+2  A: 

Python has a built-in datetime library: http://docs.python.org/library/datetime.html

This should probably get you what you're after:

import datetime as dt
from time import sleep

now = dt.datetime.now()

if now.hour >= 4 andnow.hour < 5:
    sleep((60 - now.minute)*60 + (60 - now.second))

OK, the above works, but here's the purer, less error-prone solution (and what I was originally thinking of but suddenly forgot how to do):

import datetime as dt
from time import sleep

now = dt.datetime.now()
pause = dt.datetime(now.year, now.month, now.day, 4)
start = dt.datetime(now.year, now.month, now.day, 5)

if now >= pause and now < start:
    sleep((start - now).seconds)

That's where my original "timedelta" comment came from -- what you get from subtracting two datetime objects is a timedelta object (which in this case we pull the 'seconds' attribute from).

Nicholas Knight
Are timedelta and datetime objects even comparable? :o
Robus
@Robus: Now that I've thought about it more, updated with what you probably actually want to do.
Nicholas Knight
@OP, @answerer, @upvoters: *FAIL*. Surely you jest; that will make it fall asleep if "now" is any time between midnight and 4 AM ... consider `if pause <= now < start:`
John Machin
@John: Good grief, chip on your shoulder much? A downvote and mass-"FAIL" for an accidentally inverted test is not my idea of civility.
Nicholas Knight
@Nicholas: you didn't check it, you didn't test it, ...
John Machin
@John: I also didn't deploy the code anywhere, I was just trying to help someone. You could have just pointed out the subtle error and earn everyone's thanks, but you chose to add insults and downvote an otherwise thoroughly helpful answer.
Nicholas Knight
@Nicholas: I'd call the error "blatant" -- it (screamingly obviously?) didn't fit the normal pattern `low <= test_value < high`. Interestingly, the OP didn't invert the test in his question. BTW there's another "subtle" error in your latest edit: `if now.hour >= 4 andnow.hour < 5:`.
John Machin
@John: Suggest you read the FAQ. Particularly the bit under "Be Nice".
Nicholas Knight
@John Machin*Shrug*, I obviously didn't copy-paste the example code into my project. I just wanted to see what the proper way would look like, so this answer was perfectly fine for me.
Robus
+1  A: 

The following code covers the more general case where a script needs to pause during any fixed window of less than 24 hours duration. Example: must sleep between 11:00 PM and 01:00 AM.

import datetime as dt

def sleep_duration(sleep_from, sleep_to, now=None):
    # sleep_* are datetime.time objects
    # now is a datetime.datetime object
    if now is None:
        now = dt.datetime.now()
    duration = 0
    lo = dt.datetime.combine(now, sleep_from)
    hi = dt.datetime.combine(now, sleep_to)
    if lo <= now < hi:
        duration = (hi - now).seconds
    elif hi < lo:
        if now >= lo:
            duration = (hi + dt.timedelta(hours=24) - now).seconds
        elif now < hi:
            duration = (hi - now).seconds
    return duration

tests = [
    (4, 5, 3, 30),
    (4, 5, 4, 0),
    (4, 5, 4, 30),
    (4, 5, 5, 0),
    (4, 5, 5, 30),
    (23, 1, 0, 0),
    (23, 1, 0, 30),
    (23, 1, 0, 59),
    (23, 1, 1, 0),
    (23, 1, 1, 30),
    (23, 1, 22, 30),
    (23, 1, 22, 59),
    (23, 1, 23, 0),
    (23, 1, 23, 1),
    (23, 1, 23, 59),
    ]

for hfrom, hto, hnow, mnow in tests:
    sfrom = dt.time(hfrom)
    sto = dt.time(hto)
    dnow = dt.datetime(2010, 7, 5, hnow, mnow)
    print sfrom, sto, dnow, sleep_duration(sfrom, sto, dnow)

and here's the output:

04:00:00 05:00:00 2010-07-05 03:30:00 0
04:00:00 05:00:00 2010-07-05 04:00:00 3600
04:00:00 05:00:00 2010-07-05 04:30:00 1800
04:00:00 05:00:00 2010-07-05 05:00:00 0
04:00:00 05:00:00 2010-07-05 05:30:00 0
23:00:00 01:00:00 2010-07-05 00:00:00 3600
23:00:00 01:00:00 2010-07-05 00:30:00 1800
23:00:00 01:00:00 2010-07-05 00:59:00 60
23:00:00 01:00:00 2010-07-05 01:00:00 0
23:00:00 01:00:00 2010-07-05 01:30:00 0
23:00:00 01:00:00 2010-07-05 22:30:00 0
23:00:00 01:00:00 2010-07-05 22:59:00 0
23:00:00 01:00:00 2010-07-05 23:00:00 7200
23:00:00 01:00:00 2010-07-05 23:01:00 7140
23:00:00 01:00:00 2010-07-05 23:59:00 3660
John Machin
A: 

When dealing with dates and times in Python I still prefer mxDateTime over Python's datetime module as although the built-in one has improved greatly over the years it's still rather awkward and lacking in comparison. So if interested go here: mxDateTime It's free to download and use. Makes life much easier when dealing with datetime math.

import mx.DateTime as dt
from time import sleep

now = dt.now()
if 4 <= now.hour < 5:
    stop = dt.RelativeDateTime(hour=5, minute=0, second=0)
    secs_remaining = ((now + stop) - now).seconds
    sleep(secs_remaining)
Khorkrak