Dates and periods

The part of the library that deals with dates and calendars is relatively self-contained; in fact, I’ve been told that some people only use that part of the library. If you’re an R user, there is even a package called qlcal that makes it available in R with an idiomatic syntax (kudos, Dirk!)

import QuantLib as ql

Depending on where you live, the order of the arguments in the Date constructor might seem unfamiliar; which is why, in C++, the month needs to be passed as an enumeration and not as a number. In that language, this makes it impossible to get confused and initialize the dates in the wrong way—well, it’s still possible to get confused, but if you try to pass month, day, year as in the U.S. format you’ll get a compile-time error, and if you pass year, month, day as in the ISO format you’ll get a run-time error, so at least you won’t do the wrong thing without noticing.

Unfortunately, we don’t have strong-typed enums in Python, so you’ll have to remember: day, month, year.

d = ql.Date(11, ql.May, 2021)
d
Date(11,5,2021)

Simple algebra

Some simple date calculations can be done by means of the Date and Period classes. They do what you would expect, without taking any holidays into account.

d + ql.Period(4, ql.Days)
Date(15,5,2021)
d + ql.Period(1, ql.Weeks)
Date(18,5,2021)
d + ql.Period(3, ql.Months)
Date(11,8,2021)

Some corner cases are treated as per market conventions:

ql.Date(31, 1, 2021) + ql.Period(1, ql.Months)
Date(28,2,2021)
ql.Date(29, 2, 2020) + ql.Period(1, ql.Years)
Date(28,2,2021)

Difference between dates gives you the number of days between them…

d2 = d + ql.Period(3, ql.Months)
d2 - d
92

…and adding an int to a date is shorthand for adding that number of days.

d + 5
Date(16,5,2021)

The same goes for incrementing:

d += ql.Period(2, ql.Months)
d
Date(11,7,2021)
d += 1
d
Date(12,7,2021)
d == d2
False
d < d2
True

There’s some limited algebra for periods, too. They can be compared when the result is unambiguous…

p1 = ql.Period(3, ql.Months)
p2 = ql.Period(8, ql.Weeks)
p1 < p2
False

…but sometimes the comparison can’t be decided.

p1 = ql.Period(1, ql.Months)
p2 = ql.Period(30, ql.Days)
try:
    p1 < p2
except Exception as e:
    print(f"{type(e).__name__}: {e}")
RuntimeError: undecidable comparison between 1M and 30D

The same goes for other operators like addition and subtraction.

ql.Period(3, ql.Months) + ql.Period(2, ql.Months)
Period("5M")
ql.Period(1, ql.Years) - ql.Period(8, ql.Months)
Period("4M")
try:
    ql.Period(3, ql.Weeks) + ql.Period(2, ql.Months)
except Exception as e:
    print(f"Error: {e}")
Error: impossible addition between 3W and 2M

Parsing

Just a couple of examples, in case you need to read dates from a file:

ql.DateParser.parseISO("2020-04-29")
Date(29,4,2020)
ql.DateParser.parseFormatted("04/29/20", "%m/%d/%y")
Date(29,4,2020)

Conversions to and from native Python dates

Also, in case you used pandas or some other module to read data, you might have dates as instances of Python’s date class. You can convert them to QuantLib dates with the static from_date method…

import datetime

d = datetime.date(2021, 5, 11)

ql.Date.from_date(d)
Date(11,5,2021)

…and you can do the opposite by means of the to_date method:

d = ql.Date(11, 5, 2021)
d.to_date()
datetime.date(2021, 5, 11)