QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
calendar.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5 Copyright (C) 2003, 2004, 2005, 2006, 2007 StatPro Italia srl
6 Copyright (C) 2004 Jeff Yu
7 Copyright (C) 2014 Paolo Mazzocchi
8 Copyright (C) 2020 Leonardo Arcari
9 Copyright (C) 2020 Kline s.r.l.
10
11 This file is part of QuantLib, a free-software/open-source library
12 for financial quantitative analysts and developers - http://quantlib.org/
13
14 QuantLib is free software: you can redistribute it and/or modify it
15 under the terms of the QuantLib license. You should have received a
16 copy of the license along with this program; if not, please email
17 <quantlib-dev@lists.sf.net>. The license is also available online at
18 <http://quantlib.org/license.shtml>.
19
20 This program is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22 FOR A PARTICULAR PURPOSE. See the license for more details.
23*/
24
25#include <ql/time/calendar.hpp>
26#include <ql/errors.hpp>
27
28namespace QuantLib {
29
30 namespace {
31
32 // Requires: from < to.
33 Date::serial_type daysBetweenImpl(const Calendar& cal,
34 const Date& from, const Date& to,
35 bool includeFirst, bool includeLast) {
36 auto res = static_cast<Date::serial_type>(includeLast && cal.isBusinessDay(to));
37 for (Date d = includeFirst ? from : from + 1; d < to; ++d) {
38 res += static_cast<Date::serial_type>(cal.isBusinessDay(d));
39 }
40 return res;
41 }
42
43 }
44
46 QL_REQUIRE(impl_, "no calendar implementation provided");
47
48#ifdef QL_HIGH_RESOLUTION_DATE
49 const Date _d(d.dayOfMonth(), d.month(), d.year());
50#else
51 const Date& _d = d;
52#endif
53
54 // if d was a genuine holiday previously removed, revert the change
55 impl_->removedHolidays.erase(_d);
56 // if it's already a holiday, leave the calendar alone.
57 // Otherwise, add it.
58 if (impl_->isBusinessDay(_d))
59 impl_->addedHolidays.insert(_d);
60 }
61
63 QL_REQUIRE(impl_, "no calendar implementation provided");
64
65#ifdef QL_HIGH_RESOLUTION_DATE
66 const Date _d(d.dayOfMonth(), d.month(), d.year());
67#else
68 const Date& _d = d;
69#endif
70
71 // if d was an artificially-added holiday, revert the change
72 impl_->addedHolidays.erase(_d);
73 // if it's already a business day, leave the calendar alone.
74 // Otherwise, add it.
75 if (!impl_->isBusinessDay(_d))
76 impl_->removedHolidays.insert(_d);
77 }
78
80 impl_->addedHolidays.clear();
81 impl_->removedHolidays.clear();
82 }
83
85 BusinessDayConvention c) const {
86 QL_REQUIRE(d != Date(), "null date");
87
88 if (c == Unadjusted)
89 return d;
90
91 Date d1 = d;
92 if (c == Following || c == ModifiedFollowing
94 while (isHoliday(d1))
95 ++d1;
96 if (c == ModifiedFollowing
98 if (d1.month() != d.month()) {
99 return adjust(d, Preceding);
100 }
102 if (d.dayOfMonth() <= 15 && d1.dayOfMonth() > 15) {
103 return adjust(d, Preceding);
104 }
105 }
106 }
107 } else if (c == Preceding || c == ModifiedPreceding) {
108 while (isHoliday(d1))
109 --d1;
110 if (c == ModifiedPreceding && d1.month() != d.month()) {
111 return adjust(d,Following);
112 }
113 } else if (c == Nearest) {
114 Date d2 = d;
115 while (isHoliday(d1) && isHoliday(d2))
116 {
117 ++d1;
118 --d2;
119 }
120 if (isHoliday(d1))
121 return d2;
122 else
123 return d1;
124 } else {
125 QL_FAIL("unknown business-day convention");
126 }
127 return d1;
128 }
129
131 Integer n, TimeUnit unit,
133 bool endOfMonth) const {
134 QL_REQUIRE(d!=Date(), "null date");
135 if (n == 0) {
136 return adjust(d,c);
137 } else if (unit == Days) {
138 Date d1 = d;
139 if (n > 0) {
140 while (n > 0) {
141 ++d1;
142 while (isHoliday(d1))
143 ++d1;
144 --n;
145 }
146 } else {
147 while (n < 0) {
148 --d1;
149 while(isHoliday(d1))
150 --d1;
151 ++n;
152 }
153 }
154 return d1;
155 } else if (unit == Weeks) {
156 Date d1 = d + n*unit;
157 return adjust(d1,c);
158 } else {
159 Date d1 = d + n*unit;
160
161 // we are sure the unit is Months or Years
162 if (endOfMonth){
163 if (c == Unadjusted && Date::isEndOfMonth(d)){
164 // move to end of calendar day if using Unadjusted convention and d is last calendar day
165 return Date::endOfMonth(d1);
166 } else if (isEndOfMonth(d)) {
167 // move to end of business day if d is last bussiness day
168 return Calendar::endOfMonth(d1);
169 }
170 }
171 return adjust(d1, c);
172 }
173 }
174
176 const Period & p,
178 bool endOfMonth) const {
179 return advance(d, p.length(), p.units(), c, endOfMonth);
180 }
181
183 const Date& to,
184 bool includeFirst,
185 bool includeLast) const {
186 return (from < to) ? daysBetweenImpl(*this, from, to, includeFirst, includeLast) :
187 (from > to) ? -daysBetweenImpl(*this, to, from, includeLast, includeFirst) :
188 Date::serial_type(includeFirst && includeLast && isBusinessDay(from));
189 }
190
191
192
193 // Western calendars
194
196 return w == Saturday || w == Sunday;
197 }
198
200 static const Day EasterMonday[] = {
201 98, 90, 103, 95, 114, 106, 91, 111, 102, // 1901-1909
202 87, 107, 99, 83, 103, 95, 115, 99, 91, 111, // 1910-1919
203 96, 87, 107, 92, 112, 103, 95, 108, 100, 91, // 1920-1929
204 111, 96, 88, 107, 92, 112, 104, 88, 108, 100, // 1930-1939
205 85, 104, 96, 116, 101, 92, 112, 97, 89, 108, // 1940-1949
206 100, 85, 105, 96, 109, 101, 93, 112, 97, 89, // 1950-1959
207 109, 93, 113, 105, 90, 109, 101, 86, 106, 97, // 1960-1969
208 89, 102, 94, 113, 105, 90, 110, 101, 86, 106, // 1970-1979
209 98, 110, 102, 94, 114, 98, 90, 110, 95, 86, // 1980-1989
210 106, 91, 111, 102, 94, 107, 99, 90, 103, 95, // 1990-1999
211 115, 106, 91, 111, 103, 87, 107, 99, 84, 103, // 2000-2009
212 95, 115, 100, 91, 111, 96, 88, 107, 92, 112, // 2010-2019
213 104, 95, 108, 100, 92, 111, 96, 88, 108, 92, // 2020-2029
214 112, 104, 89, 108, 100, 85, 105, 96, 116, 101, // 2030-2039
215 93, 112, 97, 89, 109, 100, 85, 105, 97, 109, // 2040-2049
216 101, 93, 113, 97, 89, 109, 94, 113, 105, 90, // 2050-2059
217 110, 101, 86, 106, 98, 89, 102, 94, 114, 105, // 2060-2069
218 90, 110, 102, 86, 106, 98, 111, 102, 94, 114, // 2070-2079
219 99, 90, 110, 95, 87, 106, 91, 111, 103, 94, // 2080-2089
220 107, 99, 91, 103, 95, 115, 107, 91, 111, 103, // 2090-2099
221 88, 108, 100, 85, 105, 96, 109, 101, 93, 112, // 2100-2109
222 97, 89, 109, 93, 113, 105, 90, 109, 101, 86, // 2110-2119
223 106, 97, 89, 102, 94, 113, 105, 90, 110, 101, // 2120-2129
224 86, 106, 98, 110, 102, 94, 114, 98, 90, 110, // 2130-2139
225 95, 86, 106, 91, 111, 102, 94, 107, 99, 90, // 2140-2149
226 103, 95, 115, 106, 91, 111, 103, 87, 107, 99, // 2150-2159
227 84, 103, 95, 115, 100, 91, 111, 96, 88, 107, // 2160-2169
228 92, 112, 104, 95, 108, 100, 92, 111, 96, 88, // 2170-2179
229 108, 92, 112, 104, 89, 108, 100, 85, 105, 96, // 2180-2189
230 116, 101, 93, 112, 97, 89, 109, 100, 85, 105 // 2190-2199
231 };
232 return EasterMonday[y-1901];
233 }
234
235 // Orthodox calendars
236
238 return w == Saturday || w == Sunday;
239 }
240
242 static const Day EasterMonday[] = {
243 105, 118, 110, 102, 121, 106, 126, 118, 102, // 1901-1909
244 122, 114, 99, 118, 110, 95, 115, 106, 126, 111, // 1910-1919
245 103, 122, 107, 99, 119, 110, 123, 115, 107, 126, // 1920-1929
246 111, 103, 123, 107, 99, 119, 104, 123, 115, 100, // 1930-1939
247 120, 111, 96, 116, 108, 127, 112, 104, 124, 115, // 1940-1949
248 100, 120, 112, 96, 116, 108, 128, 112, 104, 124, // 1950-1959
249 109, 100, 120, 105, 125, 116, 101, 121, 113, 104, // 1960-1969
250 117, 109, 101, 120, 105, 125, 117, 101, 121, 113, // 1970-1979
251 98, 117, 109, 129, 114, 105, 125, 110, 102, 121, // 1980-1989
252 106, 98, 118, 109, 122, 114, 106, 118, 110, 102, // 1990-1999
253 122, 106, 126, 118, 103, 122, 114, 99, 119, 110, // 2000-2009
254 95, 115, 107, 126, 111, 103, 123, 107, 99, 119, // 2010-2019
255 111, 123, 115, 107, 127, 111, 103, 123, 108, 99, // 2020-2029
256 119, 104, 124, 115, 100, 120, 112, 96, 116, 108, // 2030-2039
257 128, 112, 104, 124, 116, 100, 120, 112, 97, 116, // 2040-2049
258 108, 128, 113, 104, 124, 109, 101, 120, 105, 125, // 2050-2059
259 117, 101, 121, 113, 105, 117, 109, 101, 121, 105, // 2060-2069
260 125, 110, 102, 121, 113, 98, 118, 109, 129, 114, // 2070-2079
261 106, 125, 110, 102, 122, 106, 98, 118, 110, 122, // 2080-2089
262 114, 99, 119, 110, 102, 115, 107, 126, 118, 103, // 2090-2099
263 123, 115, 100, 120, 112, 96, 116, 108, 128, 112, // 2100-2109
264 104, 124, 109, 100, 120, 105, 125, 116, 108, 121, // 2110-2119
265 113, 104, 124, 109, 101, 120, 105, 125, 117, 101, // 2120-2129
266 121, 113, 98, 117, 109, 129, 114, 105, 125, 110, // 2130-2139
267 102, 121, 113, 98, 118, 109, 129, 114, 106, 125, // 2140-2149
268 110, 102, 122, 106, 126, 118, 103, 122, 114, 99, // 2150-2159
269 119, 110, 102, 115, 107, 126, 111, 103, 123, 114, // 2160-2169
270 99, 119, 111, 130, 115, 107, 127, 111, 103, 123, // 2170-2179
271 108, 99, 119, 104, 124, 115, 100, 120, 112, 103, // 2180-2189
272 116, 108, 128, 119, 104, 124, 116, 100, 120, 112 // 2190-2199
273 };
274 return EasterMonday[y-1901];
275 }
276
277 std::vector<Date> Calendar::holidayList(
278 const Date& from, const Date& to, bool includeWeekEnds) const {
279
280 QL_REQUIRE(to>=from, "'from' date ("
281 << from << ") must be equal to or earlier than 'to' date ("
282 << to << ")");
283 std::vector<Date> result;
284 for (Date d = from; d <= to; ++d) {
285 if (isHoliday(d) && (includeWeekEnds || !isWeekend(d.weekday())))
286 result.push_back(d);
287 }
288 return result;
289 }
290
291 std::vector<Date> Calendar::businessDayList(
292 const Date& from, const Date& to) const {
293
294 QL_REQUIRE(to>=from, "'from' date ("
295 << from << ") must be equal to or earlier than 'to' date ("
296 << to << ")");
297 std::vector<Date> result;
298 for (Date d = from; d <= to; ++d) {
299 if (isBusinessDay(d))
300 result.push_back(d);
301 }
302 return result;
303 }
304}
calendar class
static Day easterMonday(Year)
expressed relative to first day of year
Definition: calendar.cpp:241
bool isWeekend(Weekday) const override
Definition: calendar.cpp:237
static Day easterMonday(Year)
expressed relative to first day of year
Definition: calendar.cpp:199
bool isWeekend(Weekday) const override
Definition: calendar.cpp:195
bool isWeekend(Weekday w) const
Definition: calendar.hpp:255
Date::serial_type businessDaysBetween(const Date &from, const Date &to, bool includeFirst=true, bool includeLast=false) const
Definition: calendar.cpp:182
void removeHoliday(const Date &)
Definition: calendar.cpp:62
bool isEndOfMonth(const Date &d) const
Definition: calendar.hpp:243
bool isBusinessDay(const Date &d) const
Definition: calendar.hpp:223
void addHoliday(const Date &)
Definition: calendar.cpp:45
Date adjust(const Date &, BusinessDayConvention convention=Following) const
Definition: calendar.cpp:84
std::vector< Date > holidayList(const Date &from, const Date &to, bool includeWeekEnds=false) const
Definition: calendar.cpp:277
bool isHoliday(const Date &d) const
Definition: calendar.hpp:251
Date advance(const Date &, Integer n, TimeUnit unit, BusinessDayConvention convention=Following, bool endOfMonth=false) const
Definition: calendar.cpp:130
ext::shared_ptr< Impl > impl_
Definition: calendar.hpp:72
void resetAddedAndRemovedHolidays()
Definition: calendar.cpp:79
std::vector< Date > businessDayList(const Date &from, const Date &to) const
Definition: calendar.cpp:291
Date endOfMonth(const Date &d) const
last business day of the month to which the given date belongs
Definition: calendar.hpp:247
Concrete date class.
Definition: date.hpp:125
Month month() const
Definition: date.cpp:82
Day dayOfMonth() const
Definition: date.hpp:400
static Date endOfMonth(const Date &d)
last day of the month to which the given date belongs
Definition: date.hpp:428
static bool isEndOfMonth(const Date &d)
whether a date is the last day of its month
Definition: date.hpp:434
std::int_fast32_t serial_type
serial number type
Definition: date.hpp:128
TimeUnit units() const
Definition: period.hpp:51
Integer length() const
Definition: period.hpp:50
Classes and functions for error handling.
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Date d
Integer Year
Year number.
Definition: date.hpp:87
Integer Day
Day number.
Definition: date.hpp:53
TimeUnit
Units used to describe time periods.
Definition: timeunit.hpp:37
BusinessDayConvention
Business Day conventions.
@ Sunday
Definition: weekday.hpp:41
@ Saturday
Definition: weekday.hpp:47
QL_INTEGER Integer
integer number
Definition: types.hpp:35
Definition: any.hpp:35