An accurate stop watch using Python for logging minutes and hours worked. What's the best way to go about it?

Question:

I’ve tried a few solutions from here with no luck. My Python timers are 10-30 seconds behind my smartphone stop watch after 10 minutes. I’ve tried the following:

def background3():
    while True:
        second = 0    
        minute = 0    
        hours = 0

        while(True):       
            print('%d : %d : %d'%(hours,minute,second))       
            time.sleep(1)    
            second+=1    
            if(second == 60):    
                second = 0    
                minute+=1    
            if(minute == 60):    
                minute = 0    
                hour+=1;    

and I also tried this:

def showCounter(self):
# Check the value of startWatch variable to start or stop the Stop Watch
if self.startWatch:
# Increment counter by 1
self.counter += 1

    # Count and set the time counter value
    cnt = int((self.counter/10 - int(self.counter/10))*10)
    self.count = '0' + str(cnt)

    # Set the second value
    if int(self.counter/10) < 10 :
        self.second = '0' + str(int(self.counter / 10))
    else:
        self.second = str(int(self.counter / 10))
        # Set the minute value
        if self.counter / 10 == 60.0 :
            self.second == '00'
            self.counter = 0
            min = int(self.minute) + 1
            if min < 10 :
                self.minute = '0' + str(min)
            else:
                self.minute = str(min)

# Merge the mintue, second and count values
text = self.minute + ':' + self.second
# Display the stop watch values in the label
self.label.setText('<h1 style="color:white">' + text + '</h1>')

I’d like to be able to update a pyqt5 qlabel as time goes by every second, and I’d like to be able to display hours, minutes, and seconds in the qlabel. This has to be accurate as it is for work logging purposes. Eventually, I want to implement a qlabel that takes my overtime rate into consideration, and updates $ earned as time goes by. Does anybody have an example of what this may look like in pyqt5 using perhaps OS time ? Or is there some better way to do this?

EDIT:

This question is not a duplicate. The suggested articles were not helpful. I essentially need a way to count up from 0 using datetime. I tried replacing datetime.now but that did not work. The solutions suggested do not update my value in real time. They just take a stamp at the beginning, and subtract it from the end time. this is not what I am looking for. Does anybody know how I can watch seconds, minutes, and hours go by in real time through a pyqt5 qlabel?

def showCounter(self):
    if self.startWatch:
        text = str(datetime.now().strftime("%H:%M:%S"))
        self.label.setText('<h1 style="color:white">' + str(text) + '</h1>')
        
Asked By: nty51

||

Answers:

You should not expect a manufactured timer that relies on sleep() to be accurate for accrued time (stopwatch). Even if sleep() were 100% accurate, you are losing time outside of that in all of the function calls and other parts of the loop, which adds up over time (pun intended.)

The system time should be used. You can either use:

time.time()

or

datetime.now()

both have methods to peel out H:M:S.

As far as your "update loop"… well that is another story, you could use sleep there or whatever PyQt has to offer to refresh, but when you need to pull the time, do it as above.

If you want to use either as a "stopwatch" just capture the start time, do the subtraction. If you do this with datetime objects, the delta is a timedelta object that you can query. Do a little googling on timedelta and datetime.

Example:

In [1]: from datetime import datetime, timedelta

In [2]: tic = datetime.now()

In [3]: toc = datetime.now()

In [4]: td = toc - tic

In [5]: type(td)
Out[5]: datetime.timedelta

In [6]: td.seconds
Out[6]: 8
Answered By: AirSquid

Here’s some code that prints every passing second without accumulating any lag. Just check the built-in clock at least once per second and update if the second has changed.

from datetime import datetime
import time

def time_to_str(time):
    return str(time.hour) + ':' + str(time.minute) + ':' + str(time.second)

cur_time = datetime.now()
cur_str = time_to_str(cur_time)

while True:
    time.sleep(0.2) # 200 ms, arbitrary
    new_time = datetime.now()
    new_str = time_to_str(new_time)
    if new_str != cur_str:
        print(new_str)
        cur_str = new_str

The more often you check the time, the faster you can respond to the start of a new second. You’ll never accrue lag regardless because you only print the time immediately after getting it from the system.

Answered By: jgt9090
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.