Python, Date and Time

Introduction

Python, Date and Time

Python provides rich functionalities for dealing with date and time data. The standard libraries contains the modules

  • time
  • calendar
  • datetime

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 time, calendar and datetime.

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)
1993-12-14

We can instantiate dates in the range from January 1, 1 to December 31, 9999. This can be inquired from the attributes min and max:

from datetime import date

print(date.min)
print(date.max)
0001-01-01
9999-12-31

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.

x.toordinal()
Output::
727911

It is possible to calculate a date from a ordinal by using the class method "fromordinal":

date.fromordinal(727911)
Output::
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:

x.weekday()
Output::
1
date.today()
Output::
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)
15:06:23

The possible times range between:

print(time.min)
print(time.max)
00:00:00
23:59:59.999999

Accessing 'hour', 'minute' and 'second':

t.hour, t.minute, t.second
Output::
(15, 6, 23)

Each component of a time instance can be changed by using 'replace':

t = t.replace(hour=11, minute=59)
t
Output::
datetime.time(11, 59, 23)

We can render a date as a C-style like string, corresponding to the C ctime function:

x.ctime()
Output::
'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:

  • naive
  • aware

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
Output::
datetime.datetime(2017, 4, 19, 16, 31)

t is naive, because the following is True:

t.tzinfo == None
Output::
True

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:

t.tzinfo, t.tzinfo.utcoffset(t)
Output::
(<UTC>, datetime.timedelta(0))
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
Output::
[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)
Output::
(datetime.timedelta(959), datetime.timedelta)

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':

delta.days
Output::
959
t1 = datetime(2017, 1, 31, 14, 17)
t2 = datetime(2015, 12, 15, 16, 59)
delta = t1 - t2
delta.days, delta.seconds
Output::
(412, 76680)

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
Output::
'1991-04-30 00:00:00'

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

Formatting months:

# 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)
2000-11-30 00:00:00
dt = "2007-03-04T21:08:12"
datetime.strptime( dt, "%Y-%m-%dT%H:%M:%S" )
Output::
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
Output::
datetime.datetime(1957, 12, 24, 4, 3, 29)

We can create an English date string on a Linux machine with the Shell command
LC_ALL=en_EN.utf8 date

dt = 'Wed Apr 12 20:29:53 CEST 2017'
dt = datetime.strptime(dt, '%a %b %d %H:%M:%S %Z %Y')
print(dt)
2017-04-12 20:29:53

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')
Output::
datetime.datetime(2011, 1, 3, 0, 0)
parse('Wed Apr 12 20:29:53 CEST 2017')
Output::
datetime.datetime(2017, 4, 12, 20, 29, 53, tzinfo=tzlocal())