time library in python
4 min read

time library in python

The time library is one of the first libraries everyone learns about when learning python, usually for the time() or sleep() function. In this article, I'll go over those functions and a couple of other functions, native to this library.

For the rest of the article, suppose we imported the time library before each line of code:
import time

Getting the date and time

time() and time_ns()

Let's start with the most used function and its variant: the time() and time_ns() functions.
The time() function returns the seconds since the Unix epoch. This epoch is the Jan 1st 1970 00:00:00 UTC. At the time I write this article, it is the 1st of September 2022, around midday. So if I run the code, I'll get:

print(time.time())
Output: 1662028168.0563478
Given that there are 31536000 seconds in a normal year, we can calculate:

1662028168/31536000 = 52.7 which means that we are 52.7 years after the Unix epoch started, which coincides with 1970.

time.time_ns() returns the exact same thing but in nanoseconds instead of seconds, for example:

print("time in seconds:", time.time())
print("time in nanoseconds:", time.time_ns())

Output:

time in seconds: 1662028564.7729084
time in nanoseconds: 1662028564772957118

These functions can also be used to measure the duration of a process:

t_start = time.time()
i = 0
while i < 100000:
	i += 1
t_end = time.time()
print("elapsed time:", t_end-t_start)

Output:

elapsed time: 0.01086282730102539

However, as we'll see towards the end, there are more suited functions to measure the time performance.

localtime()

This function takes an argument of time expressed as seconds after the Unix epoch (basically like the time() function) and returns a struc_time type object. If there are no arguments, it takes time.time() by default (current time).
The struct_time has several pieces of information :

  • tm_year: year
  • tm_mon: current month (1 is January, 2 is February, etc...)
  • tm_mday: day of the month (1 to 28, 29, 30, or 31 depending on the month)
  • tm_hour: the hour of the day
  • tm_min: minute in the current hour
  • tm_sec: second in the current minute
  • tm_wday: day of the week (1 to 7)
  • tm_yday: day of the year (1 to 365 or 366)

Here are some examples:

print("without argument:", time.localtime())
print("with argument :", time.localtime(now))
print("Unix epoch:", time.localtime(0))
print("One year after epoch:", time.localtime(one_year))
print("current year:", time.localtime().tm_year)

Output:

without argument: time.struct_time(tm_year=2022, tm_mon=9, tm_mday=1, tm_hour=12, tm_min=56, tm_sec=19, tm_wday=3, tm_yday=244, tm_isdst=1)
with argument : time.struct_time(tm_year=2022, tm_mon=9, tm_mday=1, tm_hour=12, tm_min=56, tm_sec=19, tm_wday=3, tm_yday=244, tm_isdst=1)
Unix epoch: time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=1, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
One year after epoch: time.struct_time(tm_year=1971, tm_mon=1, tm_mday=1, tm_hour=1, tm_min=0, tm_sec=0, tm_wday=4, tm_yday=1, tm_isdst=0)
current year: 2022

ctime()

This function takes an argument in the time.time() format, just like the previous function, but returns a 'readable' date and time format:
W_DAY MONTH DAY HH:MM:SS YEAR
W_DAY is the name of the day and DAY is the number. If the number is only one digit, it is padded with a space. Using the same code as previously, but only changing the function, here are the results:

now = time.time()
one_year = 60*60*24*365 #One year in seconds

print("without argument:", time.ctime())
print("with argument :", time.ctime(now))
print("Unix epoch:", time.ctime(0))
print("One year after epoch:", time.ctime(one_year))

Output:

without argument: Thu Sep  1 13:02:08 2022
with argument : Thu Sep  1 13:02:08 2022
Unix epoch: Thu Jan  1 01:00:00 1970
One year after epoch: Fri Jan  1 01:00:00 1971

Measuring time

monotonic() and monotonic_ns()

The official description of the monotonic function is: Monotonic clock, cannot go backward. This is because the time.time() uses the system clock and can be nonlinear (leap seconds, external calibrations, etc...) furthermore, the system clock can actually go backward if a system clock reset happened between two calls.
This is where the time.monotonic() function comes in. This function uses a clock with no reference point (unlike the time.time() function which has the Unix epoch as its reference), this means that the only meaningful use of this function is calculating the difference between two different points in time:

print("referenced time:", time.time())
print("no reference:", time.monotonic())

Output:

referenced time: 1662055531.2217774
no reference: 100209.906

The referenced time returned by the time.time() function has a meaning, while the value returned by the time.monotonic() function has no meaning on its own.

For the reasons listed above, however, it is a very good function to use to measure time performance:

t_start = time.monotonic()
i = 0
while i<100000:
    i+=1
t_end = time.monotonic()
print("elapsed time:", t_end-t_start)

Output:

elapsed time: 0.014999999999417923


The time.monotonic_ns() is the same function but returns values in nanoseconds instead of seconds.

perf_counter() and perf_counter_ns()

Finally, the real king of the time-measuring functions. time.perf_counter() is the to-go function to measure time performances. Why's that? Well, just like monotonic(), the clock has no reference so the only meaningful use is the difference between two measures of time. However, it runs on the highest resolution clock available, way higher than time() or monotonic(). I'll write an article to show this difference in performance but for now, you'll have to take my word for it!
Here is an example of it measuring a very small duration:

t_start = time.perf_counter()
i = 0
while i<100:
    i+=1
t_end = time.perf_counter()
print("elapsed time:", t_end-t_start)

Output:

elapsed time: 9.400013368576765e-06

Use perf_counter_ns() to get the result in nanoseconds.

sleep()

Finally, a function a majority of people are familiar with, I'll still go quickly over it.
This function takes an amount of seconds as an argument and suspends the current thread for that amount of seconds (it can take fractional values).
Here is an example:

t_start = time.perf_counter()
time.sleep(3)
t_end = time.perf_counter()
print("paused time:", t_end-t_start)

Output:

paused time: 3.0006820000126027

Thanks for reading this article and consider subscribing to my newsletter! It's free and keeps me motivated.