The time library is one of the first libraries everyone learns about when learning python, usually for the
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:
Getting the date and time
time() and time_ns()
Let's start with the most used function and its variant: 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:
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())
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)
elapsed time: 0.01086282730102539
However, as we'll see towards the end, there are more suited functions to measure the time performance.
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)
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
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))
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
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())
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)
elapsed time: 0.014999999999417923
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
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)
elapsed time: 9.400013368576765e-06
perf_counter_ns() to get the result in nanoseconds.
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)
paused time: 3.0006820000126027
Thanks for reading this article and consider subscribing to my newsletter! It's free and keeps me motivated.