[Tutor] Could I have used time or datetime modules here?

Brian van den Broek bvande at po-box.mcgill.ca
Mon Dec 6 01:53:01 CET 2004


Dick Moores said unto the world upon 2004-12-05 15:03:
> Thanks, Brian. I looked at your code a long time, and also read the 
> 11/26 thread you started. I can see how I could use datetime() and your 
> t2 - t1 to get the seconds for time.sleep(), but  the resulting code I 
> have in mind is more convoluted than the heart of my timer3.py, which I 
> quote below.  (I don't need the alarm time to be more than 24 hours from 
> current time--therefore I want to ignore the year, month, and day.)
> 
> =======================================
> import time
> 
> alarm = raw_input("Enter alarm time as hhmm: ")
> 
> now = time.strftime("%X")  # produces current time in format  hh:mm:ss
> nowSecond = int(now[6:])
> nowMinute = int(now[3:5])
> nowHour = int(now[0:2])
> 
> alarmMinute = int(alarm[2:4])
> alarmHour = int(alarm[0:2])
> 
> hoursDiff = alarmHour - nowHour
> minutesDiff = alarmMinute - nowMinute
> 
> if hoursDiff < 0 or (hoursDiff == 0 and minutesDiff <= 0):
>     hoursDiff = hoursDiff + 24 # add a day
> 
> sleepSeconds = hoursDiff*3600 + minutesDiff*60 - nowSecond
> 
> time.sleep(sleepSeconds)
> ====================================
> If I'm wrong, could someone please set me right?
> 
> Dick
> 

Hi Dick and all,

sorry I was too lazy to follow your link before, Dick. Thanks for 
posting the relevant portions.

I took another run, but my code is a lot longer as I put in some error 
checking on the input request -- hope you don't mind ;-) (I might have 
gone overboard -- I did it to learn how as much as anything else.)

I suspect that my way is easier than yours. (I don't know about Liam's. 
His came in as I was writing mine, and I've not read his closely yet.)

In mine, the key bit is that if you have two datetime objects, d1 and 
d2, d1 - d2 gives a timedelta object expressing the time difference 
between them in the form (days, seconds, microseconds). So, the datetime 
module seems to do the work you want -- just make the current time a 
datetime object, use the user input to get a datetime object in the 
future and then find their timedelta and ask it for its seconds 
attribute. This disregards any difference in days and gives only the 
hour + minute + seconds difference expressed in seconds.

That logic is near the bottom, though, as first you've got to read 
through my error checking code ;-)

I tested it pretty well, but as always, undetected errors entitle you to 
a full refund of purchase price. (Minus a reasonable handling fee, of 
course.)

I hope this is of some use to you.

Best to all,

Brian vdB

CODE:

import datetime
import time

def get_alarm_time():
     '''Asks user for a time in the form 'hh:mm' and return tuple of ints.

     Includes error checking to make sure user input really is of form
     'hh:mm' where the values of 'hh' and 'mm' are appropriate.
     '''
     while True:
         alarm_time = raw_input("Enter alarm time as hh:mm")
         er_msg = '''
         An alarm time must be entered in the format 'hh:mm' where 'hh'
         is a number between 0 and 23 inclusive and mm is a number
         between 0 and 59 inclusive.
         You entered: '%s', which is not of that form.
         Please try again.
         ''' %alarm_time
         alarm_time_list = alarm_time.split(':')
         # yields a list with first element the characters from before
	# the ':' and second from after.

         try:
             alarm_hour, alarm_minute = (int(alarm_time_list[0]),
                                         int(alarm_time_list[1]) )
         except ValueError:
             # raised if the user entered something like "silly:input"
             print er_msg
             continue
         if len(str(alarm_minute)) == 1:
             alarm_minute_string = '0' + str(alarm_minute)
             # if the user entered, say, 12:05, str(alarm_minute) would
             # give '5' rather than the needed '05'.
         else:
             alarm_minute_string = str(alarm_minute)
         if ( (alarm_hour > 24 or alarm_hour < 0)
              or (alarm_minute > 59 or alarm_minute < 0)
              or str(alarm_hour) + ':' + alarm_minute_string != alarm_time):
             # The first two clauses check that minutes and hours are
             # within the expected ranges. The final clause checks that
             # the inputs were string representations of integers.
             # (Without it, the user could have entered something like
             # 16.845:57.0000343.)
             print er_msg
         else:
             return alarm_hour, alarm_minute

alarm_hour, alarm_minute = get_alarm_time()
now = datetime.datetime.now()
alarm_datetime = datetime.datetime(now.year + 4, now.month, now.day,
                                    alarm_hour, alarm_minute)
# now.year + 4 to ensure that the alarm_datetime represents a time in
# the future. I used a multiple of 4 to avoid leap year issues. + 44
# would work equally well. (This ignores the additional correction every
# 100 or 400 years -- I forget which. But what do you want for free ;-)

alarm_in_seconds = (alarm_datetime - now).seconds
# a_datetime_object - another_datetime_object gives a_timedelta_object.
# a_timedelta_object.seconds returns only the hour and minute difference
# (discarding days) expressed in seconds. It has to be the future time
# minus the current time for the .seconds to give the wanted result.

print "I should wake up in %d seconds" %alarm_in_seconds
time.sleep(alarm_in_seconds)
print "I'm awake!"


More information about the Tutor mailing list