# Ways to improve this clock algorithm?

Discussion in 'Python' started by Jacob H, Sep 15, 2003.

1. ### Jacob HGuest

Hello all,

I'm close to being a novice programmer and I never was good at math.
So I'm curious to know ways in which this following code can be made
more efficient, more elegant. The code just calculates and displays
elapsed wall clock seconds since initialization.

class ExampleTimer:
def __init__(self):
self.start = time.clock()

def run(self):
while 1:
now = time.clock()
allseconds = int(now) = int(self.start)
seconds = 0
minutes = 0
hours = 0
for n in range(1, (allseconds + 1)):
seconds += 1
if n % 60 == 0:
minutes += 1
seconds = 0
if n % 3600 == 0:
hours += 1
minutes = 0
print "%s hrs %s min %s sec" % (hours, minutes, seconds)
time.sleep(1)

app = ExampleTimer()
app.run()

I am grateful for any suggestions and advice.

Jake

Jacob H, Sep 15, 2003

2. ### Paul RubinGuest

(Jacob H) writes:

> Hello all,
>
> I'm close to being a novice programmer and I never was good at math.
> So I'm curious to know ways in which this following code can be made
> more efficient, more elegant. The code just calculates and displays
> elapsed wall clock seconds since initialization.
>
> class ExampleTimer:
> def __init__(self):
> self.start = time.clock()
>
> def run(self):
> while 1:
> now = time.clock()
> allseconds = int(now) = int(self.start)

I think you mean

allseconds = int(now) - int(self.start)

Now you can say

hours = allseconds // 3600
minutes = (allseconds // 60) % 60
seconds = allseconds % 60

instead of counting up to allseconds. You could also use the divmod
function for a fancier way to do the same thing, but the above is
straightforward enough.

Paul Rubin, Sep 15, 2003

3. ### Valentino Volonghi aka DialtoneGuest

(Jacob H) writes:

> I am grateful for any suggestions and advice.

import time
class ExampleTimer(object):
def __init__(self):
print "This is my super clock"
self.run()

def run(self):
while 1:
self.update_time()
print "%s hrs %s min %s sec" % (self.hours, self.mins, self.secs)
time.sleep(1)

def update_time(self):
# I would use time.localtime() to update the time because doing this I am
# sure that it is always syncd with my pc time. I think this is the only
# improvement . It also removes the need for all that math.
self.secs = time.localtime()[5]
self.mins = time.localtime()[4]
self.hours = time.localtime()[3]

app = ExampleTimer()
app.run()

--
Valentino Volonghi, Regia SpA, Milan

Linux User #310274, Debian Sid Proud User

Valentino Volonghi aka Dialtone, Sep 15, 2003
4. ### Jeff EplerGuest

Well, this doesn't run on my system. First, I had to change this line:
> now = time.clock()

- allseconds = int(now) = int(self.start)
+ allseconds = int(now) - int(self.start)
> seconds = 0

[In all the excerpts, "-" is a line changed/removed from your version,
and "+" is a line changed/added in my version]

Then, I had to insert an 'import':
+ import time
+
> class ExampleTimer:
> def __init__(self):

Then, this program kept printing "0 hrs 0 min 0 sec", because clock()
returns CPU time (not wall time) on Unix computers. time.time() returns
seconds on all systems Python supports, according to the online
documentation. ("import time; help(time.time)")

> def __init__(self):

- self.start = time.clock()
+ self.start = time.time()

> while 1:

- now = time.clock()
+ now = time.time()

Finally, I'm not sure what your 'for n in range ...' code is intended to
do. You can convert the number of seconds into the
hours/minutes/seconds more easily:
# (Replacing the whole 'for' loop and the three asignments above it)
# Take whole minutes and leave the seconds corresponding to the
# fraction of minutes in seconds
minutes = allseconds / 60
seconds = allseconds % 60

# Take whole hours and leave the minutes corresponding to the
# fraction of the hour in minutes
hours = minutes / 60
minutes = minutes % 60
You could do this with the built-in function divmod(), as well:
# (Replacing the whole 'for' loop and the three asignments above it)
minutes, seconds = divmod(allseconds, 60)
hours, minutes = divmod(minutes, 60)

You could test starting at different times by changing init:
- def __init__(self):
- self.start = time.clock()
+ def __init__(self, offset=0):
+ self.start = time.clock() - offset

Now, you can easily see whether the "rollover" to 1 hour works right:
- app = ExampleTimer()
+ app = ExampleTimer(60*60 - 1)
> app.run()

Jeff

Jeff Epler, Sep 15, 2003
5. ### Andy JewellGuest

On Monday 15 Sep 2003 10:02 pm, Jacob H wrote:
> Hello all,
>
> I'm close to being a novice programmer and I never was good at math.
> So I'm curious to know ways in which this following code can be made
> more efficient, more elegant. The code just calculates and displays
> elapsed wall clock seconds since initialization.
>
> class ExampleTimer:
> def __init__(self):
> self.start = time.clock()
>
> def run(self):
> while 1:
> now = time.clock()
> allseconds = int(now) = int(self.start)
> seconds = 0
> minutes = 0
> hours = 0
> for n in range(1, (allseconds + 1)):
> seconds += 1
> if n % 60 == 0:
> minutes += 1
> seconds = 0
> if n % 3600 == 0:
> hours += 1
> minutes = 0
> print "%s hrs %s min %s sec" % (hours, minutes, seconds)
> time.sleep(1)
>
> app = ExampleTimer()
> app.run()
>
> I am grateful for any suggestions and advice.
>
> Jake

Jake,

Maybe this'll help:
>>> import time
>>> start=time.time()
>>> # waste some time...
>>> now=time.time()-start
>>> now

266.24996101856232
>>> secs=int(now % 60)
>>> secs

26
>>> mins=int((now-secs) /60)
>>> mins

4
>>> hrs=int((now-secs-mins) /(60*60))
>>> hrs

0
>>>

-andyj

Andy Jewell, Sep 15, 2003
6. ### Jacob HGuest

Thanks to all for the replies. They did indeed improve my clock algorithm.

Jake

Jacob H, Sep 19, 2003
7. ### Bengt RichterGuest

On Mon, 15 Sep 2003 23:45:55 +0200, Valentino Volonghi aka Dialtone <dialtone#NOSPAM#> wrote:

> (Jacob H) writes:
>
>> I am grateful for any suggestions and advice.

>
>import time
>class ExampleTimer(object):
> def __init__(self):
> print "This is my super clock"
> self.run()
>
> def run(self):
> while 1:
> self.update_time()
> print "%s hrs %s min %s sec" % (self.hours, self.mins, self.secs)
> time.sleep(1)
>
> def update_time(self):
> # I would use time.localtime() to update the time because doing this I am
> # sure that it is always syncd with my pc time. I think this is the only
> # improvement . It also removes the need for all that math.
> self.secs = time.localtime()[5]
> self.mins = time.localtime()[4]
> self.hours = time.localtime()[3]

Sooner or later a second will tick between the above statements and give inconsistent h,m,s.
Better to get the tuple, slice it and unpack it, e.g., (untested)

self.hours, self.mins, self.secs = time.localtime()[3:6]

Also, time.sleep(1) will probably span an epsilon more than one second sometime, and
when that hits the second updates right you will get a 2-second hiccup in apparent time
output. As to when it will happen, it's only a matter of time ;-) (Unless you are running
on some platform that has some underlying synchronization with wall clock seconds going on).

One way to get around that might be to sync up with the seconds turnover, either with a
busy wait or with a minimal sleep interval, then sleep say .99 seconds and wait again in
a minimal sleep loop until the second-value changes (if it has not done so already due
to extraneous delays). You can fine tune various aspects of this (as an exercise ;-)

<rant>
This kind of ugliness results if there's no way to tell the OS a precise wall clock time
to ready your process/thread after a wait and/or if timers don't have a way of specifying
accurate intervals that work to the nearest tick and don't accumulate tick resolution errors.
Relatively simple to provide if you are coding the OS clock stuff, so why is application-level
timer expiration usually only relative to a precisely unpredictable "now" instead of a time
coordinate in some time coordinate system?
</rant>

>
>app = ExampleTimer()
>app.run()
>
>
>
>--
>Valentino Volonghi, Regia SpA, Milan
>
>Linux User #310274, Debian Sid Proud User

Regards,
Bengt Richter

Bengt Richter, Sep 20, 2003

## Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.