diff --git a/ql/time/calendar.hpp b/ql/time/calendar.hpp
index 35b603260f2..be35499301e 100644
--- a/ql/time/calendar.hpp
+++ b/ql/time/calendar.hpp
@@ -108,6 +108,12 @@ namespace QuantLib {
weekend for the given market.
*/
bool isWeekend(Weekday w) const;
+ /*! Returns true iff in the given market, the date is on
+ or before the first business day for that month.
+ */
+ bool isStartOfMonth(const Date& d) const;
+ //! first business day of the month to which the given date belongs
+ Date startOfMonth(const Date& d) const;
/*! Returns true iff in the given market, the date is on
or after the last business day for that month.
*/
@@ -240,6 +246,14 @@ namespace QuantLib {
return impl_->isBusinessDay(_d);
}
+ inline bool Calendar::isStartOfMonth(const Date& d) const {
+ return (d.month() != adjust(d-1, Preceding).month());
+ }
+
+ inline Date Calendar::startOfMonth(const Date& d) const {
+ return adjust(Date::startOfMonth(d), Following);
+ }
+
inline bool Calendar::isEndOfMonth(const Date& d) const {
return (d.month() != adjust(d+1).month());
}
diff --git a/ql/time/date.hpp b/ql/time/date.hpp
index 55c477bf4e5..63ae49212ac 100644
--- a/ql/time/date.hpp
+++ b/ql/time/date.hpp
@@ -207,6 +207,10 @@ namespace QuantLib {
static Date maxDate();
//! whether the given year is a leap one
static bool isLeap(Year y);
+ //! first day of the month to which the given date belongs
+ static Date startOfMonth(const Date& d);
+ //! whether a date is the first day of its month
+ static bool isStartOfMonth(const Date& d);
//! last day of the month to which the given date belongs
static Date endOfMonth(const Date& d);
//! whether a date is the last day of its month
@@ -425,6 +429,16 @@ namespace QuantLib {
return advance(*this,-p.length(),p.units());
}
+ inline Date Date::startOfMonth(const Date& d) {
+ Month m = d.month();
+ Year y = d.year();
+ return Date(1, m, y);
+ }
+
+ inline bool Date::isStartOfMonth(const Date& d) {
+ return (d.dayOfMonth() == 1);
+ }
+
inline Date Date::endOfMonth(const Date& d) {
Month m = d.month();
Year y = d.year();
diff --git a/test-suite/calendars.cpp b/test-suite/calendars.cpp
index 47eeb387d34..ea7a816894f 100644
--- a/test-suite/calendars.cpp
+++ b/test-suite/calendars.cpp
@@ -3369,6 +3369,26 @@ BOOST_AUTO_TEST_CASE(testMexicoInaugurationDay) {
}
}
+BOOST_AUTO_TEST_CASE(testStartOfMonth) {
+ BOOST_TEST_MESSAGE("Testing start-of-month calculation...");
+
+ Calendar c = TARGET(); // any calendar would be OK
+
+ Date som, counter = Date::minDate() + 2 * Months;
+ Date last = Date::maxDate();
+
+ while (counter < last) {
+ som = c.startOfMonth(counter);
+ // check that som is som
+ if (!c.isStartOfMonth(som))
+ BOOST_FAIL("\n " << som.weekday() << " " << som << " is not the first business day in "
+ << som.month() << " " << som.year() << " according to " << c.name());
+ // check that som is in the same month as counter
+ if (som.month() != counter.month())
+ BOOST_FAIL("\n " << som << " is not in the same month as " << counter);
+ counter = counter + 1;
+ }
+}
BOOST_AUTO_TEST_CASE(testEndOfMonth) {
BOOST_TEST_MESSAGE("Testing end-of-month calculation...");