32. Python Date and Time
By Bernd Klein. Last modified: 23 Nov 2021.
Python provides rich functionalities for dealing with date and time data. The standard libraries contains the modules
These modules supply classes for manipulating dates and times in both simple and complex ways.
Especially, the datetime class will be very important for the timeseries of Pandas.
Python Standard Modules for Time Data
The most important modules of Python dealing with time are the modules
The datetime module provides various classes, methods and functions to deal with dates, times, and time intervals.
The datetime module provides the following classes:
- The instances of the date class represent dates, whereas the year can range between 1 and 9999.
- The instances of the datetime class are made up both by a date and a time.
- The time class implements time objects.
- The timedelta class is used to hold the differences between two times or two date objects.
- The tzinfo class is used to implement timezone support for time and datetime objects.
Let's start with a date object.
The Date Class
from datetime import date x = date(1993, 12, 14) print(x)
We can instantiate dates in the range from January 1, 1 to December 31, 9999. This can be inquired from the attributes
from datetime import date print(date.min) print(date.max)
We can apply various methods to the date instance above. The method toordinal returns the proleptic Gregorian ordinal. The proleptic Gregorian calendar is produced by extending the Gregorian calendar backward to dates preceding its official introduction in 1582. January 1 of year 1 is day 1.
It is possible to calculate a date from a ordinal by using the class method "fromordinal":
datetime.date(1993, 12, 14)
If you want to know the weekday of a certain date, you can calculate it by using the method weekday:
datetime.date(2017, 4, 12)
We can access the day, month and year with attributes:
print(x.day) print(x.month) print(x.year)
14 12 1993
The time Class
The time class is similarly organized than the date class.
from datetime import time t = time(15, 6, 23) print(t)
The possible times range between:
Accessing 'hour', 'minute' and 'second':
t.hour, t.minute, t.second
(15, 6, 23)
Each component of a time instance can be changed by using 'replace':
t = t.replace(hour=11, minute=59) t
datetime.time(11, 59, 23)
We can render a date as a C-style like string, corresponding to the C ctime function:
'Tue Dec 14 00:00:00 1993'
The datetime Class
The datetime module provides us with functions and methods for manipulating dates and times. It supplies functionalities for date and time arithmetic, i.e. addition and subtraction. Another focus of the implementation is on attribute extraction for output manipulation and formatting.
There are two kinds of date and time objects:
If a time or date object is naive it doesn't contain information to compare or locate itself relative to other date or time objects. The semantics, if such a naive object belongs to a certain time zone, e.g. Coordinated Universal Time (UTC), local time, or some other timezone is contained in the logic of the program.
An aware object on the other hand possesses knowledge of the time zone it belongs to or the daylight saving time information. This way it can locate itself relative to other aware objects.
How can you tell if a datetime object t is aware?
t is aware if t.tzinfo is not None and t.tzinfo.utcoffset(t) is not None. Both conditions have to be fulfilled
On the other hand an object t is naive if t.tzinfo is None or t.tzinfo.utcoffset(t) is None
Let's create a datetime object:
from datetime import datetime t = datetime(2017, 4, 19, 16, 31, 0) t
datetime.datetime(2017, 4, 19, 16, 31)
t is naive, because the following is True:
t.tzinfo == None
We will create an aware datetime object from the current date. For this purpose we need the module pytz. pytz is a module, which brings the Olson tz database into Python. The Olson timezones are nearly completely supported by this module.
from datetime import datetime import pytz t = datetime.now(pytz.utc)
We can see that both t.tzinfo and t.tzinfo.utcoffset(t) are different from None, so t is an aware object:
from datetime import datetime, timedelta as delta ndays = 15 start = datetime(1991, 4, 30) dates = [start - delta(days=x) for x in range(0, ndays)] dates
[datetime.datetime(1991, 4, 30, 0, 0), datetime.datetime(1991, 4, 29, 0, 0), datetime.datetime(1991, 4, 28, 0, 0), datetime.datetime(1991, 4, 27, 0, 0), datetime.datetime(1991, 4, 26, 0, 0), datetime.datetime(1991, 4, 25, 0, 0), datetime.datetime(1991, 4, 24, 0, 0), datetime.datetime(1991, 4, 23, 0, 0), datetime.datetime(1991, 4, 22, 0, 0), datetime.datetime(1991, 4, 21, 0, 0), datetime.datetime(1991, 4, 20, 0, 0), datetime.datetime(1991, 4, 19, 0, 0), datetime.datetime(1991, 4, 18, 0, 0), datetime.datetime(1991, 4, 17, 0, 0), datetime.datetime(1991, 4, 16, 0, 0)]
Differences between Times
Let's see what happens, if we subtract to datetime objects:
from datetime import datetime delta = datetime(1993, 12, 14) - datetime(1991, 4, 30) delta, type(delta)
The result of the subtraction of the two datetime objects is a timedelta object, as we can see from the example above.
We can get information about the number of days elapsed by using the attribute 'days':
t1 = datetime(2017, 1, 31, 14, 17) t2 = datetime(2015, 12, 15, 16, 59) delta = t1 - t2 delta.days, delta.seconds
It is possible to add or subtract a timedelta to a datetime object to calculate a new datetime object by adding or subtracting the delta in days:
from datetime import datetime, timedelta d1 = datetime(1991, 4, 30) d2 = d1 + timedelta(10) print(d2) print(d2 - d1) d3 = d1 - timedelta(100) print(d3) d4 = d1 - 2 * timedelta(50) print(d4)
1991-05-10 00:00:00 10 days, 0:00:00 1991-01-20 00:00:00 1991-01-20 00:00:00
It is also possible to add days and minutes to t datetime object:
from datetime import datetime, timedelta d1 = datetime(1991, 4, 30) d2 = d1 + timedelta(10,100) print(d2) print(d2 - d1)
1991-05-10 00:01:40 10 days, 0:01:40
Convert datetime Objects to Strings
The easiest way to convert a datetime object into a string consists in using str.
s = str(d1) s
Conversion with strftime
The method call datetime.strftime(format) return a string representing the date and time, controlled by an explicit format string. A complete list of formatting directives can be found at strftime:
print(d1.strftime('%Y-%m-%d')) print("weekday: " + d1.strftime('%a')) print("weekday as a full name: " + d1.strftime('%A')) # Weekday as a decimal number, where 0 is Sunday # and 6 is Saturday print("weekday as a decimal number: " + d1.strftime('%w'))
1991-04-30 weekday: Tue weekday as a full name: Tuesday weekday as a decimal number: 2
# Day of the month as a zero-padded decimal number. # 01, 02, ..., 31 print(d1.strftime('%d')) # Month as locale’s abbreviated name. # Jan, Feb, ..., Dec (en_US); # Jan, Feb, ..., Dez (de_DE) print(d1.strftime('%b')) # Month as locale’s full name. # January, February, ..., December (en_US); # Januar, Februar, ..., Dezember (de_DE) print(d1.strftime('%B')) # Month as a zero-padded decimal number. # 01, 02, ..., 12 print(d1.strftime('%m'))
30 Apr April 04
Creating datetime Objects from Strings
We can use strptime to create new datetime object by parsing a string containing a data and time. The arguments of strptime are the string to be parsed and a format specification.
from datetime import datetime t = datetime.strptime("30 Nov 00", "%d %b %y") print(t)
dt = "2007-03-04T21:08:12" datetime.strptime( dt, "%Y-%m-%dT%H:%M:%S" )
datetime.datetime(2007, 3, 4, 21, 8, 12)
dt = '12/24/1957 4:03:29 AM' dt = datetime.strptime(dt, '%m/%d/%Y %I:%M:%S %p') dt
datetime.datetime(1957, 12, 24, 4, 3, 29)
We can create an English date string on a Linux machine with the Shell command
dt = 'Wed Apr 12 20:29:53 CEST 2017' dt = datetime.strptime(dt, '%a %b %d %H:%M:%S %Z %Y') print(dt)
Though datetime.strptime is an easy way to parse a date with a known format, it can be quote complicated and cumbersome to write every time a new specification string for new date formats.
Using the parse method from dateutil.parser:
from dateutil.parser import parse parse('2011-01-03')
datetime.datetime(2011, 1, 3, 0, 0)
parse('Wed Apr 12 20:29:53 CEST 2017')
datetime.datetime(2017, 4, 12, 20, 29, 53, tzinfo=tzlocal())