In this article we are going to look at how we can see time in milliseconds, i.e. one thousandth (1000th) of a second, using Python. This could be for pure curiosity, benchmarking code or to get a very, very accurate time of day – whatever the reason, the focus of the article is how to get the time in milliseconds, rather than what it’s to be used for once we have it.
Method 1: Milliseconds and Fixed Time
The first method we are going to look at is based on measuring how much time has passed since a fixed point in time, which we call the ‘epoch’. For Python, and computing in general, the epoch is the point where time starts and the passage of time is therefore measured against this. Whilst the epoch can vary depending on operating system, for Unix and Windows it is midnight on January 1st 1970 in UTC time (Greenwich Mean Time without Daylight Savings time adjustments). If you want to find out what the epoch time is on a given platform you can use:
import time time.gmtime(0) # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
As I am using a Windows 10 machine the above output just confirms that the start time, or the epoch for Python on my machine is January 1, 1970, 00:00:00.
Using time.time()
The time Python Standard Library can be used to return the time in seconds since the epoch as a floating point number:
import time time.time() # 1613649533.180575
This essentially gives us the number of seconds that have passed since the epoch, so to get the time in milliseconds we have to multiply the value returned by 1000. For aesthetics we can round the number and convert to an integer:
import time int(round(time.time()*1000)) # 1613649588303
Whilst this is a good, basic way of getting time, if you are measuring time in milliseconds you are probably looking for a level of precision this does not provide. Unfortunately, the time.time is designed to get time in seconds, so can not guarantee that the system you are using will return a time with a precision greater than that i.e 1 second.
time.time_ns()
Appreciating this need for more accuracy, Python versions 3.7 and later incorporate an additional time function that measures time to the nanosecond – a thousand -millionth of a second. You may, like me, just need a moment to think about that – a thousand-millionth of a second…
So, whilst this method clearly has the precision we are looking for, to get the time in milliseconds we still need to divide the number returned by 1,000,000 (i.e convert nanoseconds to milliseconds):
import time time.time_ns() // 1000000 # 1613649695449
As the function automatically returns an integer we do not need to worry about rounding or converting.
Method 2: Milliseconds and Relative Time
If our aim is to measure speed in milliseconds, for benchmarking code for example, Python has multiple functions in the time library that can specifically help with this. We are going to look at two, in particular, which can be used to measure time in nanoseconds so give us the precision we require.
Unlike the examples in Method 1, neither of these functions have a defined relationship to the real-world time – the epoch, they look at what we call relative time. The value they return is not defined against any starting point, but can be used to measure time intervals – such as how long it takes to run a task or specific piece of code. .
time.monotonic_ns()
This function is used to get the value of a monotonic clock, a clock that can not go backwards and is not affected by system clock updates. As the return value is undefined, i.e we don’t know what starting point it relates to, it has limited use on it’s own. However, we can sandwich some code between consecutive calls to measure the time between the calls and therefore how long it took to execute our code.
In the example below, we will print the start monotonic time and the finish monotonic time for illustration purposes as they have no value on their own. We can however use them to measure the time between the two calls to see how long it took for Python to perform the print function. As the return value is in nanoseconds, we have to divide by 1,000,000 to get our millisecond response time
import time start = time.monotonic_ns() print(start) x=1 while(x<=100): print(x) x +=1 finish=time.monotonic_ns() duration = finish - start print(f"That took {duration//1000000}ms")
The output is:
176278031000000 1 2 3 .. 98 99 100 176278046000000 That took 15ms
time.perf_counter_ns()
This method is similar to the time.monotonic
function previously outlined but, as the name suggests, is a performance counter. It does not include time elapsed during sleep and is system-wide. This returns the absolute value of the counter but as this return is undefined, as with the time.monotonic function, it has limited use on it’s own.
So, as with the time.monotonic function we can use consecutive calls to measure time between the calls, and as the return is in nanoseconds we have to divide by 1,000,000 to get milliseconds:
import time start = time.perf_counter_ns() print(start) x=1 while(x<=100): print(x) x +=1 finish = time.perf_counter_ns() print(finish) duration = finish - start print(f"That took {duration//1000000}ms")
The output is:
80058697360400 1 2 3 .. 98 99 100 80058701461500 That took 4ms
With both the time.perf_counter
and time.monotonic
functions, the start and finish times we have printed are irrelevant on their own, because we do not know what they relate to. Their only use is to show us the time elapsed between the calls.
Method 3: Milliseconds and Time of Day
Finally, we are going to look at how we can get Python to tell us the time of day in milliseconds, and to do this we will be using the Python Standard Library datetime
.
datetime.datetime.now()
This function returns the current system date and time with the following attributes:
year, month, day, hour, minute, second, microsecond
If we just call the function by itself it will show us the current date and time at my location, down to the microsecond (one millionth of a second) :
import datetime datetime.datetime.now() # datetime.datetime(2021,2,18,12,21,7,163392)
The above output tells me current local time is
- Year: 2021
- Month: 2 (February)
- Day: 18
- Hour: 12
- Minutes: 21
- Seconds: 7
- Microseconds: 163392
The thing to bear is that the micorsecond
attribute being returned is always in relation to the seconds attribute.
Now if we want to convert the microseconds to milliseconds we have to divide by 1000, we can also use a print statement to help format the function for readability:
import datetime dt = datetime.datetime.now() print(dt) dt.microsecond / 1000
The output is:
2021-02-18 12:21:59.889660 889.66
The first line of the output prints the current date and time, the second line prints the number of milliseconds at this point.
datetime.datetime.utcnow()
A slight variation on the previous example is using utcnow()
instead of just now()
. UTC refers to time in Coordinated Universal Time or Greenwich Mean Time(GMT) and is useful to calculate absolute time differences without the confusion of time zones. As I live in London, there is no difference in my code between now()
and utcnow()
but we will see it in action anyway.
If we call the function without any formatting we get a similar output to what we saw before, so the attributes are the same :
import datetime datetime.datetime.utcnow() # datetime.datetime(2021, 2, 18, 12, 22, 45, 343352)
We could get our milliseconds as we did with the now()
function, and it would work just as well, but let’s have a look at another method. In this example we are going to use the strftime()
method to convert our datetime
object into a string:
import datetime datetime.datetime.utcnow().strftime('%Y-%m-%d-%H:%M:%S:%f') # ‘2021-02-18-12:23:34:474314'
As the last number represents microseconds if we want to display the current time in milliseconds we can disregard the last 3 digits, by slicing. This has the same effect as dividing by 1000 thus converting or time to microseconds:
import datetime print(datetime.datetime.utcnow().strftime('%Y-%m-%d-%H:%M:%S:%f')[:-3]) # 2021-02-18-12:24:28:401
Summary
We have looked at several ways of using Python to show us time in milliseconds. Whilst the update from the simple time.time
to time.time_ns
definitely helps with our precision, it is difficult to provide recommendations on best practice. All the methods we have seen provide an answer, but whether it’s the right answer really depends on the question we are asking.
The key is finding the right method to fit your particular requirements, factors like level of precision required, geographical location(s) and level of complexity will all determine the right approach. Luckily Python has a number of ways to help us get milliseconds, so it could come down to personal preference.