time
moduleIn Python, there are six main ‘formats’ that date and time data can be in and these six formats are provided by two different built-in modules: time and datetime:
time
module can be used when working with:
struct_time
objects (or ‘structs’)datetime
module can be used when working with:
time
objectsdate
objectsdatetime
objectstimedelta
objectsThe first two are simpler while the latter four are more powerful:
time
module for time stamping, ie if you care about when something happened relative to other things, not the actual calendar date or clock time when it happened. This is the module that is discussed on this page.datetime
module if you want to work with times and dates like you would see on a clock or on a calendar, or with durations. This module is discussed on its own page.Within the world of computing, it has been decided that midnight on 1 January 1970 is ‘time zero’. This is known as the Unix epoch. Usually, if you tell a computer to interpret a number as a time or date it will assume that the number in question represents the number of seconds after this epoch:
Note that this system ignores leap seconds, ie it assumes there are exactly 86,400 seconds in a day (60 × 60 × 24). This means that it stays in sync with our clocks - at midnight each night the Unix time will be a multiple of 86,400 - but it is not actually an accurate record of the number of seconds that have passed since the epoch. In fact, 27 more seconds have passed since the start of 1970 than Unix time would have you believe, due to the fact that there have been 27 leap seconds.
Unix time is the most useful format to use when time stamping events because, in practice, they are simply numbers (specifically, they are usually floating-point numbers or floats). They are thus easy to work with when writing code and you don’t actually care what clock time or calendar date they represent.
In Python, most of the functionality for working with Unix time is contained within the time
module, so let’s start by importing that:
import time
You can then get the current Unix time by using the time()
function:
# Current time in Unix time format
time_unix = time.time()
print(f'Number of seconds since 12:00am, 1 January 1970 (100 nanosecond precision): {time_unix}')
## Number of seconds since 12:00am, 1 January 1970 (100 nanosecond precision): 1640224616.5088046
One method of getting a time stamp into a more readable format is the ctime()
function which converts a Unix time (ie a number) into a string using the format defined in the C programming language:
# Convert a Unix time into a formatted string
time_ctime = time.ctime(10)
print(f'10 seconds after the epoch as a formatted string: {time_ctime}')
## 10 seconds after the epoch as a formatted string: Thu Jan 1 01:00:10 1970
If you don’t include an argument, ctime()
will default to using the current time:
# The current time as a formatted string
time_ctime = time.ctime()
print(f'The current time in ctime format: {time_ctime}')
## The current time in ctime format: Thu Dec 23 01:56:56 2021
The above two examples show the time in ‘C time’ format (a reference to the C programming language) which is a bit odd. You don’t usually see the time come in the middle of the date! Unfortunately, there is no way to do this differently: you cannot directly convert a Unix time (a number) into a formatted string using a custom format. You first need to convert it into a time structure, as is discussed in the “Converting Between the Two Formats” section below.
Get the time between two time stamps by subtracting them from each other (ie literally get the difference between the two times):
# Get the current time in Unix time
t2 = time.time()
# Get the time stamp of 22 November 2003 22:00 AEDT (UTC+11)
t1 = 1069498800
# Get the difference
tdiff = (t2 - t1) / 60 / 60 / 24
print(f'Days since England last won the Rugby World Cup: {tdiff}')
## Days since England last won the Rugby World Cup: 6605.622876647976
Whereas Unix time is just a single number, a time structure (a struct_time
object) is a sequence of 9 numbers. These correspond to the year, month, day, hour, minute, second, day of the week, day of the year and daylight savings information relevant to the moment in question (timezone and/or longitudinal offset information can also be stored). Note that each of these numbers needs to be an integer (as opposed to Unix time where floating-point numbers are okay) and therefore fractions of a second are ignored.
You can manually create a struct_time
object by specifying 9 integers in a “9-tuple”:
# Create a tuple
nine_tuple = (2009, 8, 7, 6, 5, 4, 4, 219, 1)
# Convert the tuple into a struct_time object
time_struct = time.struct_time(nine_tuple)
print(time_struct)
## time.struct_time(tm_year=2009, tm_mon=8, tm_mday=7, tm_hour=6, tm_min=5, tm_sec=4, tm_wday=4, tm_yday=219, tm_isdst=1)
Note that the above method of creating a time and date is tricky because the last three numbers are dependent on the first three:
The better way of manually creating a struct_time
object is to parse a string that is formatted as a time and date, using the strptime()
(string parse time) function:
# Create a string in C time format
st = 'Fri Aug 7 06:05:04 2009'
# Convert the string to a struct_time object
time_struct = time.strptime(st)
print(time_struct)
## time.struct_time(tm_year=2009, tm_mon=8, tm_mday=7, tm_hour=6, tm_min=5, tm_sec=4, tm_wday=4, tm_yday=219, tm_isdst=-1)
The format of the string in the above example is the ‘C time’ format that was discussed in the ‘Seconds Since the Unix Epoch’ section. This is an unusual format because the year is at the end and you have to specify the day of the week at the front. Fortunately, you can provide your own format constructed using the directives to represent time and date elements as a positional argument. Here’s an example that parses a date and time in ISO 8601 format:
# Create a string in ISO 8601 format
st = '2021-04-02T13:55:28+00:00'
# Convert the string to a struct_time object
time_struct = time.strptime(st, '%Y-%m-%dT%H:%M:%S%z')
print(time_struct)
## time.struct_time(tm_year=2021, tm_mon=4, tm_mday=2, tm_hour=13, tm_min=55, tm_sec=28, tm_wday=4, tm_yday=92, tm_isdst=-1)
Note that the last element (tm_isdst=-1
) indicates that the daylight savings information is unknown.
Some more examples to demonstrate using strptime()
with different formats:
time_struct = time.strptime('30 Nov 00', '%d %b %y')
time_struct = time.strptime('2018-10-04', '%Y-%m-%d')
time_struct = time.strptime('2018-10-04 10:11:12', '%Y-%m-%d %H:%M:%S')
If a given string does not contain complete time and date information (eg ‘2018-10-04’ is a date only and so does not contain any time information) then the missing elements are filled in from (1900, 1, 1, 0, 0, 0, 0, 1, -1)
. In other words, the ‘default’ time struct is midnight on 1 January 1900.
Alternatively, you can get your current local time in struct_time
format using the localtime()
function:
# The current local time in struct_time format
time_localtime = time.localtime()
print(time_localtime)
## time.struct_time(tm_year=2021, tm_mon=12, tm_mday=23, tm_hour=1, tm_min=56, tm_sec=56, tm_wday=3, tm_yday=357, tm_isdst=0)
For me, currently, daylight savings is in effect and so the struct_time
object above represents that. If I instead want the current UTC time (ie with no daylight sayings or time zone offsets) I can use the gmtime()
function to get Greenwich Mean Time:
# The current GMT in struct_time format
time_gmtime = time.gmtime()
print(time_gmtime)
## time.struct_time(tm_year=2021, tm_mon=12, tm_mday=23, tm_hour=1, tm_min=56, tm_sec=56, tm_wday=3, tm_yday=357, tm_isdst=0)
Of course, while the above representation of time and date is informative it’s not very readable. One method of getting stuct_time
objects into a more user-friendly format is the asctime()
function which represents the object as a C time:
# Manually create a tuple representing a time and date
nine_tuple = (2009, 8, 7, 6, 5, 4, 4, 219, 1)
# Convert a struct_time or tuple into a string in ctime format
time_asctime = time.asctime(nine_tuple)
print(time_asctime)
## Fri Aug 7 06:05:04 2009
Note that if you don’t specify any argument with the asctime()
function it will default to using the current time:
# Get the current time and date as a formatted string
time_asctime = time.asctime()
print(f"The current time and date as a 'C time'-formatted string: {time_asctime}")
## The current time and date as a 'C time'-formatted string: Thu Dec 23 01:56:56 2021
Unfortunately, the ‘C time’ format used by asctime()
is fixed. However, a second method that you can use to get a more readable format and which allows you to customise the format is the strftime()
(string format time) function. See here for all the available directives (variables that represent a part of a time or a date) that you can use to construct a format:
# Manually create a tuple representing a time and date
nine_tuple = (2009, 8, 7, 6, 5, 4, 4, 219, 1)
# Convert the tuple into a struct_time object
time_struct = time.struct_time(nine_tuple)
# Convert a struct_time into a string with a custom format
time_formatted = time.strftime('%Y-%m-%d %H:%M:%S', time_struct)
print(time_formatted)
## 2009-08-07 06:05:04
Again, omitting a time argument will cause the function to default to using the current date and time:
# Convert a struct_time into a string with a custom format
time_formatted = time.strftime('%Y-%m-%d %H:%M:%S')
print(f'The current time in a custom format: {time_formatted}')
## The current time in a custom format: 2021-12-23 01:56:56
To summarise:
strptime()
to parse a formatted string into a time struct (convert from a string into a stuct)
strftime()
to format a struct (convert from a struct into a string)
asctime()
(or ctime()
if you are working with Unix time) will do thisHere’s an example to demonstrate that strptime()
and strftime()
can be used as inverses of each other:
# Start with a string formatted in C time format
st1 = 'Fri Aug 07 06:05:04 2009'
# Parse the string to make a struct
time_struct = time.strptime(st1)
# Format the strict to make a string
st2 = time.strftime('%a %b %d %H:%M:%S %Y', time_struct)
# Check that what we ended with is the same as what we started with
print(st1)
print(st2)
## Fri Aug 07 06:05:04 2009
## Fri Aug 07 06:05:04 2009
There is no way to directly get the amount of time between two time stamps in struct_time
format. It could, however, be done by converting to Unix time, subtracting and then converting back to struct_time
. An example of this is shown in the next section…
The localtime()
and gmtime()
functions were introduced above as ways to create struct_time
objects using the current time and date:
# Get the current time and date as a struct
struct = time.localtime()
print(struct)
## time.struct_time(tm_year=2021, tm_mon=12, tm_mday=23, tm_hour=1, tm_min=56, tm_sec=56, tm_wday=3, tm_yday=357, tm_isdst=0)
However, if you give these functions a Unix time as an argument (as opposed to having no arguments as in the example above) they will convert them to struct_time
objects:
# Get the current time and date in Unix time and convert it to a struct
struct = time.localtime(time.time())
print(struct)
## time.struct_time(tm_year=2021, tm_mon=12, tm_mday=23, tm_hour=1, tm_min=56, tm_sec=56, tm_wday=3, tm_yday=357, tm_isdst=0)
Here’s another example where an explicit Unix time stamp is converted into a struct:
struct = time.localtime(1603997091)
print(f'Seconds-since-the-epoch as a struct: {struct}')
## Seconds-since-the-epoch as a struct: time.struct_time(tm_year=2020, tm_mon=10, tm_mday=29, tm_hour=18, tm_min=44, tm_sec=51, tm_wday=3, tm_yday=303, tm_isdst=0)
You can convert a struct_time
object into Unix time (ie to a float
object) using mktime()
which is the inverse of localtime()
:
time_mktime = time.mktime(struct)
print(f'Time in seconds-since-the-epoch format: {time_mktime}')
## Time in seconds-since-the-epoch format: 1603997091.0
The most useful way to get the difference in time between two time stamps is to:
Here’s how this is done:
# Get the date of the 2003 Rugby World Cup final as a struct
t1 = time.strptime('22 November 2003', '%d %B %Y')
# Get the current time and date as a struct
t2 = time.localtime()
# Convert structs to Unix time
t1 = time.mktime(t1)
t2 = time.mktime(t2)
# Calculate the difference between the two timestamps
tdiff = int((t2 - t1) / 60 / 60 / 24)
print(f'Days since England last won the Rugby World Cup: {tdiff}')
## Days since England last won the Rugby World Cup: 6606
Be careful not to convert this result (which is a number) into a time struct or interpret it as Unix time: doing so would cause it to be interpreted as a period of time after the epoch as opposed to since the event we are interested in which, in this example, is the 2003 Rugby World Cup final. In order to better handle differences in time we should use timedelta objects which are part of the datetime
module (see here for the page on that topic).