How to not leap in time using Python

How to not leap in time using Python

If you want to display the time to a user of your application, you request the time of the day. However, if your application needs to measure the elapsed time, you need a timer that will give the correct answer even if the user changes the time on the system clock.

The system clock that tells you the time of day is called a real-time clock or wall clock. The time on that clock can jump to the past and future. Laying on the wall clock to find out how much time has passed since a previous event is a bug waiting to happen.

For example, suppose that your application performs an operation in response to an event, but it only performs that operation once per hour, and in between, it does nothing. Maybe the operation is some sort of cleanup task. Suppose a user made a misprint and sets the system clock to the wrong month before running the application; the user can fix this later when your application is already running. Suppose that the date is now a month earlier than when your application was launched, that would be a whole month until your application decides that it needs to perform its cleanup operations again!

To safely measure the elapsed time in your application, you need a clock that measures the time continuously, without jumps when the user sets the system clock. These clocks are called monotonic. On Python 3.3, the time.monotonic() function was introduced to provide a basic monotonic clock. Before Python 3.3, there was a PyPI module called [monotonic](https://pypi.org/project/monotonic/) that provides similar functionality.

import time

start = time.monotonic()
time.sleep(0.2)
end = time.monotonic()

print("start: {:>9.2f}".format(start))
print("end: {:>9.2f}".format(end))
print("span: {:>9.2f}".format(end - start))
start:   4601.77
end:   4601.97
span:      0.20

To measure performance, it is important to have monotonic timers with high accuracy. Such a timer Python provides in time.perf_counter():

import time

start = time.perf_counter()
i = 0
while i < 100000:
    i = i + 1

elapsed_time = time.perf_counter() - start
print("Elapsed time: {}".format(elapsed_time))
Elapsed time: 0.012327131999882113

From Python 3.8 time.clock() function will be deleted and time.perf_counter() will be used.


Buy me a coffee