QuantLib: Dates

In order to process financial data, we need to have an efficient way of dealing with dates, time periods and calendars. QuantLib provides a range of classes in order to help in this task. The most fundamental class is the Date class. Date represents a day which can lie between 1st January 1901 and 31st December 2199. Internally dates are stored in the same way as they are stored in Excel, by an integer number that counts the days from 1st January 1900. By not allowing any dates before 1901, QuantLib avoids the leap year bug of Excel, in which the year 1900 is counted as a leap year.

Dates can be initialised using an Excel date number, or by explicitly stating the day, month and year.

Date d1(34524);
Date d2(6, September, 2012);

std::cout << d1 << std::endl;
std::cout << d2 << std::endl;

Note that the month argument in the second constructor is an enum which can take the month’s names in full (e.g. September) or the abbreviated month’s name (e.g. Sep).
The output of the above code is

July 9th, 1994
September 6th, 2012

The default constructor Date::Date() creates an empty date. Internally this date is represented by the serial number 0, which corresponds to 1st January 1900. This date is outside of the range of valid dates and is therefore regarded as invalid.

Date also provides some static member functions that create new dates.

static Date Date::todaysDate();
static Date Date::minDate();
static Date Date::maxDate();

todaysDate() is self explanatory, as it returns the current date, as set by the computer’s clock, minDate() returns the earliest allowed date, i.e. the 1st January 1901, and maxDate() returns the latest allowed date, i.e. the 31st December 2199.

Date Queries

There are a few helpful accessor methods.
The method weekday() returns the day of the week which is a number between 1 and 7, dayOfTheMonth() returns a number between 1 and 31 representing the day of the month. Similarly dayOfTheYear() returns a number between 1 and 365 (or 366 in leap years) representing the day of the year, where 1 stands for 1st January. The method month() returns the month. This is an enum that can be converted to the month’s number from 1 to 12. In the same way, year() gives access to the year number of the date, such as 2012. Finally, serialNumber() returns the internal integer representation of the date which is compatible with Excel or Applix.

Date d(6, Sep, 2012);

std::cout << "Date is " << d << std::endl;
std::cout << "Weekday is " << d.weekday() << std::endl;
std::cout << "Day of the month is " << d.dayOfMonth() << std::endl;
std::cout << "Day of the year is " << d.dayOfYear() << std::endl;
std::cout << "Month is " << d.month() << std::endl;
std::cout << "Year is " << d.year() << std::endl;
std::cout << "Serial number is " << d.serialNumber() << std::endl;

This code produces the output below.

Date is September 6th, 2012
Weekday is Thursday
Day of the month is 6
Day of the year is 250
Month is September
Year is 2012
Serial number is 41158

More Static Methods

There are a few more static methods that provide information on dates or that create dates from other dates. These are listed below.

static bool Date::isLeap(Year y);
static bool Date::isEndOfMonth(const Date& d);
static Date endOfMonth(const Date& d);
static Date nextWeekday(const Date& d,
                        Weekday w);
static Date nthWeekday(Size n,
                       Weekday w,
                       Month m,
                       Year y);

The function isLeap() returns true if the year is a leap year and false if it isn’t. The result is correct within the given date range. For the year 1900 QuantLib deliberately reproduces the Excel bug by classifying it as leap year. For years outside of the range 1900 to 2200 the code will fail.

The function isEndOfMonth() returns true if the given date is the last day of the month, and false if it isn’t. endOfMonth() will return the date that corresponds to the last day of the month which the given date is in.

nextWeekday() returns a date that is the following weekday. If the day passed to the function is either Friday, Saturday, or Sunday then the following Monday will be returned. Otherwise the function will simply return the following day.

To get a date that represents the nth weekday in a month, use the method nthWeekday(). To clarify, assume that you want to get a Date object for the 3rd Tuesday in August 2008 you would call nthWeekday(3, 2, August, 2008);

In summary consider the following code

if (Date::isLeap(2008))
  std::cout << "The year 2008 is a leap year." << std::endl;
  std::cout << "The year 2008 is not a leap year." << std::endl;

if (Date::isLeap(2003))
  std::cout << "The year 2003 is a leap year." << std::endl;
  std::cout << "The year 2003 is not a leap year." << std::endl;

Date d1(31,Mar,1969);
Date d2(20,Jun,1969);

if (Date::isEndOfMonth(d1))
  std::cout << "The date "<< d1 << " is the end of the month." << std::endl;
  std::cout << "The date "<< d1 << " is not the end of the month." << std::endl;

if (Date::isEndOfMonth(d2))
  std::cout << "The date "<< d2 << " is the end of the month." << std::endl;
  std::cout << "The date "<< d2 << " is not the end of the month." << std::endl;

std::cout << "End of the month from "<< d2 << " is "
  << Date::endOfMonth(d2)
  << "." << std::endl;

std::cout << "Next Friday after " << d1 << " is "
    << Date::nextWeekday(d1, Friday) << std::endl;
std::cout << "Next Tuesday after " << d2 << " is "
    << Date::nextWeekday(d2, Tuesday) << std::endl;

std::cout << "The 3rd Tuesday of August 2008 is "
    << Date::nthWeekday(3, Tuesday, August, 2008) << "." << std::endl;

This example produces the following output.

The year 2008 is a leap year.
The year 2003 is not a leap year.
The date March 31st, 1969 is the end of the month.
The date June 20th, 1969 is not the end of the month.
End of the month from June 20th, 1969 is June 30th, 1969.
Next Friday after March 31st, 1969 is April 4th, 1969
Next Tuesday after June 20th, 1969 is June 24th, 1969
The 3rd Tuesday of August 2008 is August 19th, 2008.

Note how, in the nthWeekday example, the weekday was passed by its name. This is possible because QuantLib defines an enum called Weekday, that allows the weekdays to be referenced by their name, such as Monday, Tuesday, or by their abbreviated name, such as Mon, Tue.

Date Calculations

It is possible to add and subtract time periods to or from dates. The easiest way of doing this is simply by adding or subtracting an integer. This integer represents the number of days by which the date should be shifted. One can use the usual operators for doing this.

Date d(14, September, 2007);
// adding but leaving the date unaffected
std::cout << "Adding 20 days " << d+20 << std::endl;
// subtract 25 days
d -= 25;
std::cout << "Date is now " << d << std::endl;
// prefix increment
std::cout << "Date is now " << ++d << std::endl;
// postfix increment
std::cout << "Date is now " << d++ << std::endl;
std::cout << "Date is now " << d << std::endl;

The output of this is

Adding 20 days October 4th, 2007
Date is now August 20th, 2007
Date is now August 21st, 2007
Date is now August 21st, 2007
Date is now August 22nd, 2007

While the above calculations are straightforward when the exact number of days is known, it is not easy to shift the date by a set number of months or years. This can be done using time periods which will be handled in the next arcticle.