Coverage Report

Created: 2026-01-25 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/time/calendars/israel.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2015 Paolo Mazzocchi
5
 Copyright (C) 2015 Riccardo Barone
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
#include <ql/time/calendars/israel.hpp>
22
#include <ql/errors.hpp>
23
24
namespace QuantLib {
25
26
    namespace {
27
28
0
        bool isPurim(const Date& d) {
29
0
            static std::set<Date> knownDates = {
30
0
                {21, March,    2000},
31
0
                {9,  March,    2001},
32
0
                {26, February, 2002},
33
0
                {18, March,    2003},
34
0
                {7,  March,    2004},
35
0
                {25, March,    2005},
36
0
                {14, March,    2006},
37
0
                {4,  March,    2007},
38
0
                {21, March,    2008},
39
0
                {10, March,    2009},
40
0
                {28, February, 2010},
41
0
                {20, March,    2011},
42
0
                {8,  March,    2012},
43
0
                {24, February, 2013},
44
0
                {16, March,    2014},
45
0
                {05, March,    2015},
46
0
                {24, March,    2016},
47
0
                {12, March,    2017},
48
0
                {1,  March,    2018},
49
0
                {21, March,    2019},
50
0
                {10, March,    2020},
51
0
                {26, February, 2021},
52
0
                {17, March,    2022},
53
0
                {7,  March,    2023},
54
0
                {24, March,    2024},
55
0
                {14, March,    2025},
56
0
                {3,  March,    2026},
57
0
                {23, March,    2027},
58
0
                {12, March,    2028},
59
0
                {1,  March,    2029},
60
0
                {19, March,    2030},
61
0
                {9,  March,    2031},
62
0
                {26, February, 2032},
63
0
                {15, March,    2033},
64
0
                {5,  March,    2034},
65
0
                {25, March,    2035},
66
0
                {13, March,    2036},
67
0
                {1,  March,    2037},
68
0
                {21, March,    2038},
69
0
                {10, March,    2039},
70
0
                {28, February, 2040},
71
0
                {17, March,    2041},
72
0
                {6,  March,    2042},
73
0
                {26, March,    2043},
74
0
                {13, March,    2044},
75
0
                {3,  March,    2045},
76
0
                {22, March,    2046},
77
0
                {12, March,    2047},
78
0
                {28, February, 2048},
79
0
                {18, March,    2049},
80
0
                {8,  March,    2050},
81
0
            };
82
0
            return knownDates.find(d) != knownDates.end();
83
0
        }
84
85
0
        bool isPassover1st(const Date& d) {
86
0
            static std::set<Date> knownDates = {
87
0
                {20, April, 2000},
88
0
                {8,  April, 2001},
89
0
                {28, March, 2002},
90
0
                {17, April, 2003},
91
0
                {6,  April, 2004},
92
0
                {24, April, 2005},
93
0
                {13, April, 2006},
94
0
                {3,  April, 2007},
95
0
                {20, April, 2008},
96
0
                {9,  April, 2009},
97
0
                {30, March, 2010},
98
0
                {19, April, 2011},
99
0
                {7,  April, 2012},
100
0
                {26, March, 2013},
101
0
                {15, April, 2014},
102
0
                {4,  April, 2015},
103
0
                {23, April, 2016},
104
0
                {11, April, 2017},
105
0
                {31, March, 2018},
106
0
                {20, April, 2019},
107
0
                {9,  April, 2020},
108
0
                {28, March, 2021},
109
0
                {16, April, 2022},
110
0
                {6 , April, 2023},
111
0
                {23, April, 2024},
112
0
                {13, April, 2025},
113
0
                {2 , April, 2026},
114
0
                {22, April, 2027},
115
0
                {11, April, 2028},
116
0
                {31, March, 2029},
117
0
                {18, April, 2030},
118
0
                {8,  April, 2031},
119
0
                {27, March, 2032},
120
0
                {14, April, 2033},
121
0
                {4,  April, 2034},
122
0
                {24, April, 2035},
123
0
                {12, April, 2036},
124
0
                {31, March, 2037},
125
0
                {20, April, 2038},
126
0
                {9,  April, 2039},
127
0
                {29, March, 2040},
128
0
                {16, April, 2041},
129
0
                {5,  April, 2042},
130
0
                {25, April, 2043},
131
0
                {12, April, 2044},
132
0
                {2,  April, 2045},
133
0
                {21, April, 2046},
134
0
                {11, April, 2047},
135
0
                {29, March, 2048},
136
0
                {17, April, 2049},
137
0
                {7,  April, 2050},
138
0
            };
139
0
            return knownDates.find(d) != knownDates.end();
140
0
        }
141
142
0
        bool isIndependenceDay(const Date& d) {
143
0
            static std::set<Date> knownDates = {
144
0
                {10, May,   2000},
145
0
                {26, April, 2001},
146
0
                {17, April, 2002},
147
0
                {7,  May,   2003},
148
0
                {27, April, 2004},
149
0
                {12, May,   2005},
150
0
                {3,  May,   2006},
151
0
                {24, April, 2007},
152
0
                {8,  May,   2008},
153
0
                {29, April, 2009},
154
0
                {20, April, 2010},
155
0
                {10, May,   2011},
156
0
                {26, April, 2012},
157
0
                {16, April, 2013},
158
0
                {6,  May,   2014},
159
0
                {23, April, 2015},
160
0
                {12, May,   2016},
161
0
                {2,  May,   2017},
162
0
                {19, April, 2018},
163
0
                {9,  May,   2019},
164
0
                {29, April, 2020},
165
0
                {15, April, 2021},
166
0
                {5,  May,   2022},
167
0
                {26, April, 2023},
168
0
                {14, May,   2024},
169
0
                {1,  May,   2025},
170
0
                {22, April, 2026},
171
0
                {12, May,   2027},
172
0
                {2,  May,   2028},
173
0
                {19, April, 2029},
174
0
                {8,  May,   2030},
175
0
                {29, April, 2031},
176
0
                {15, April, 2032},
177
0
                {4,  May,   2033},
178
0
                {25, April, 2034},
179
0
                {15, May,   2035},
180
0
                {1,  May,   2036},
181
0
                {21, April, 2037},
182
0
                {10, May,   2038},
183
0
                {28, April, 2039},
184
0
                {18, April, 2040},
185
0
                {7,  May,   2041},
186
0
                {24, April, 2042},
187
0
                {14, May,   2043},
188
0
                {3,  May,   2044},
189
0
                {20, April, 2045},
190
0
                {10, May,   2046},
191
0
                {1,  May,   2047},
192
0
                {16, April, 2048},
193
0
                {6,  May,   2049},
194
0
                {27, April, 2050},
195
0
            };
196
0
            return knownDates.find(d) != knownDates.end();
197
0
        }
198
199
0
        bool isMemorialDay(const Date& d) {
200
0
            return isIndependenceDay(d+1);
201
0
        }
202
203
0
        bool isShavuot(const Date& d) {
204
0
            static std::set<Date> knownDates = {
205
0
                {9,  June, 2000},
206
0
                {28, May,  2001},
207
0
                {17, May,  2002},
208
0
                {6,  June, 2003},
209
0
                {26, May,  2004},
210
0
                {13, June, 2005},
211
0
                {2,  June, 2006},
212
0
                {23, May,  2007},
213
0
                {9,  June, 2008},
214
0
                {29, May,  2009},
215
0
                {19, May,  2010},
216
0
                {8,  June, 2011},
217
0
                {27, May,  2012},
218
0
                {15, May,  2013},
219
0
                {4,  June, 2014},
220
0
                {24, May,  2015},
221
0
                {12, June, 2016},
222
0
                {31, May,  2017},
223
0
                {20, May,  2018},
224
0
                {9,  June, 2019},
225
0
                {29, May,  2020},
226
0
                {17, May,  2021},
227
0
                {5,  June, 2022},
228
0
                {26, May,  2023},
229
0
                {12, June, 2024},
230
0
                {2,  June, 2025},
231
0
                {22, May,  2026},
232
0
                {11, June, 2027},
233
0
                {31, May,  2028},
234
0
                {20, May,  2029},
235
0
                {7,  June, 2030},
236
0
                {28, May,  2031},
237
0
                {16, May,  2032},
238
0
                {3,  June, 2033},
239
0
                {24, May,  2034},
240
0
                {13, June, 2035},
241
0
                {1,  June, 2036},
242
0
                {20, May,  2037},
243
0
                {9,  June, 2038},
244
0
                {29, May,  2039},
245
0
                {18, May,  2040},
246
0
                {5,  June, 2041},
247
0
                {25, May,  2042},
248
0
                {14, June, 2043},
249
0
                {1,  June, 2044},
250
0
                {22, May,  2045},
251
0
                {10, June, 2046},
252
0
                {31, May,  2047},
253
0
                {18, May,  2048},
254
0
                {6,  June, 2049},
255
0
                {27, May,  2050},
256
0
            };
257
0
            return knownDates.find(d) != knownDates.end();
258
0
        }
259
260
0
        bool isFastDay(const Date& d) {
261
0
            static std::set<Date> knownDates = {
262
0
                {10, August, 2000},
263
0
                {29, July,   2001},
264
0
                {18, July,   2002},
265
0
                {7,  August, 2003},
266
0
                {27, July,   2004},
267
0
                {14, August, 2005},
268
0
                {3,  August, 2006},
269
0
                {24, July,   2007},
270
0
                {10, August, 2008},
271
0
                {30, July,   2009},
272
0
                {20, July,   2010},
273
0
                {9,  August, 2011},
274
0
                {29, July,   2012},
275
0
                {16, July,   2013},
276
0
                {5,  August, 2014},
277
0
                {26, July,   2015},
278
0
                {14, August, 2016},
279
0
                {1,  August, 2017},
280
0
                {22, July,   2018},
281
0
                {11, August, 2019},
282
0
                {30, July,   2020},
283
0
                {18, July,   2021},
284
0
                {7,  August, 2022},
285
0
                {27, July,   2023},
286
0
                {13, August, 2024},
287
0
                {3,  August, 2025},
288
0
                {23, July,   2026},
289
0
                {12, August, 2027},
290
0
                {1,  August, 2028},
291
0
                {22, July,   2029},
292
0
                {8,  August, 2030},
293
0
                {29, July,   2031},
294
0
                {18, July,   2032},
295
0
                {4,  August, 2033},
296
0
                {25, July,   2034},
297
0
                {14, August, 2035},
298
0
                {3,  August, 2036},
299
0
                {21, July,   2037},
300
0
                {10, August, 2038},
301
0
                {31, July,   2039},
302
0
                {19, July,   2040},
303
0
                {6,  August, 2041},
304
0
                {27, July,   2042},
305
0
                {16, August, 2043},
306
0
                {2,  August, 2044},
307
0
                {23, July,   2045},
308
0
                {12, August, 2046},
309
0
                {1,  August, 2047},
310
0
                {19, July,   2048},
311
0
                {8,  August, 2049},
312
0
                {28, July,   2050},
313
0
            };
314
0
            return knownDates.find(d) != knownDates.end();
315
0
        }
316
317
0
        bool isNewYearsDay(const Date& d) {
318
0
            static std::set<Date> knownDates = {
319
0
                {30, September, 2000},
320
0
                {17, September, 2001},
321
0
                {7,  September, 2002},
322
0
                {27, September, 2003},
323
0
                {16, September, 2004},
324
0
                {4,  October,   2005},
325
0
                {23, September, 2006},
326
0
                {13, September, 2007},
327
0
                {30, September, 2008},
328
0
                {19, September, 2009},
329
0
                {9,  September, 2010},
330
0
                {29, September, 2011},
331
0
                {17, September, 2012},
332
0
                {5,  September, 2013},
333
0
                {25, September, 2014},
334
0
                {14, September, 2015},
335
0
                {3,  October,   2016},
336
0
                {21, September, 2017},
337
0
                {10, September, 2018},
338
0
                {30, September, 2019},
339
0
                {19, September, 2020},
340
0
                {7,  September, 2021},
341
0
                {26, September, 2022},
342
0
                {16, September, 2023},
343
0
                {3,  October,   2024},
344
0
                {23, September, 2025},
345
0
                {12, September, 2026},
346
0
                {2,  October,   2027},
347
0
                {21, September, 2028},
348
0
                {10, September, 2029},
349
0
                {28, September, 2030},
350
0
                {18, September, 2031},
351
0
                {6,  September, 2032},
352
0
                {24, September, 2033},
353
0
                {14, September, 2034},
354
0
                {4,  October,   2035},
355
0
                {22, September, 2036},
356
0
                {10, September, 2037},
357
0
                {30, September, 2038},
358
0
                {19, September, 2039},
359
0
                {8,  September, 2040},
360
0
                {26, September, 2041},
361
0
                {15, September, 2042},
362
0
                {5,  October,   2043},
363
0
                {22, September, 2044},
364
0
                {12, September, 2045},
365
0
                {1,  October,   2046},
366
0
                {21, September, 2047},
367
0
                {8,  September, 2048},
368
0
                {27, September, 2049},
369
0
                {17, September, 2050},
370
0
            };
371
0
            return knownDates.find(d) != knownDates.end();
372
0
        }
373
374
0
        bool isYomKippur(const Date& d) {
375
0
            return isNewYearsDay(d-9);
376
0
        }
377
378
0
        bool isSukkot(const Date& d) {
379
0
            return isYomKippur(d-5);
380
0
        }
381
382
0
        bool isSimchatTorah(const Date& d) {
383
0
            return isSukkot(d-7);
384
0
        }
385
386
    }
387
388
389
    class Israel::TelAvivImpl final : public Calendar::Impl {
390
      public:
391
0
        std::string name() const override { return "Tel Aviv stock exchange"; }
392
        bool isWeekend(Weekday) const override;
393
        bool isBusinessDay(const Date&) const override;
394
    };
395
396
    class Israel::ShirImpl final : public Calendar::WesternImpl {
397
      public:
398
0
        std::string name() const override { return "SHIR fixing calendar"; }
399
        bool isBusinessDay(const Date&) const override;
400
    };
401
402
0
    Israel::Israel(Israel::Market market) {
403
        // all calendar instances share the same implementation instance
404
0
        static auto telAvivImpl = ext::make_shared<Israel::TelAvivImpl>();
405
0
        static auto shirImpl = ext::make_shared<Israel::ShirImpl>();
406
0
        switch (market) {
407
0
        case Settlement:
408
0
        case TASE:
409
0
            impl_ = telAvivImpl;
410
0
            break;
411
0
        case SHIR:
412
0
            impl_ = shirImpl;
413
0
            break;
414
0
        default:
415
0
            QL_FAIL("unknown market");
416
0
        }
417
0
    }
418
419
0
    bool Israel::TelAvivImpl::isWeekend(Weekday w) const {
420
0
        return w == Friday || w == Saturday;
421
0
    }
422
423
0
    bool Israel::TelAvivImpl::isBusinessDay(const Date& date) const {
424
0
        Weekday w = date.weekday();
425
0
        Year y = date.year();
426
427
0
        if (isWeekend(w)
428
0
            || isPurim(date)
429
0
            || (y <= 2020 && isPassover1st(date+1)) // Eve of Passover, until 2020
430
0
            || isPassover1st(date)
431
0
            || isPassover1st(date-5) // Eve of Passover VII, until 2020
432
0
            || isPassover1st(date-6) // Passover VII
433
0
            || isMemorialDay(date)
434
0
            || isIndependenceDay(date)
435
0
            || (y <= 2020 && isShavuot(date+1)) // Eve of Shavuot, until 2020
436
0
            || isShavuot(date)
437
0
            || isFastDay(date)
438
0
            || (y <= 2019 && isNewYearsDay(date+1))  // Eve of new year, until 2019
439
0
            || isNewYearsDay(date)
440
0
            || isNewYearsDay(date-1)  // 2nd day of new year
441
0
            || isYomKippur(date+1) // Eve of Yom Kippur
442
0
            || isYomKippur(date)
443
0
            || isSukkot(date+1)  // Eve of Sukkot
444
0
            || isSukkot(date)
445
0
            || isSimchatTorah(date+1)  // Eve of Simchat Torah
446
0
            || isSimchatTorah(date))
447
0
            return false; // NOLINT(readability-simplify-boolean-expr)
448
449
0
        return true;
450
0
    }
451
452
0
    bool Israel::ShirImpl::isBusinessDay(const Date& date) const {
453
0
        Weekday w = date.weekday();
454
0
        Day d = date.dayOfMonth();
455
0
        Day dd = date.dayOfYear();
456
0
        Month m = date.month();
457
0
        Year y = date.year();
458
459
0
        if (isWeekend(w)
460
0
            || isPurim(date)
461
0
            || isPurim(date-1) // Purim (Jerusalem)
462
0
            || isPassover1st(date+1) // Eve of Passover
463
0
            || isPassover1st(date)
464
0
            || isPassover1st(date-6) // Last day of Passover
465
0
            || isIndependenceDay(date)
466
0
            || isShavuot(date)
467
0
            || isFastDay(date)
468
0
            || isNewYearsDay(date+1)  // Eve of new year, until 2019
469
0
            || isNewYearsDay(date)
470
0
            || isNewYearsDay(date-1)  // 2nd day of new year
471
0
            || isYomKippur(date+1) // Eve of Yom Kippur
472
0
            || isYomKippur(date)
473
0
            || isSukkot(date)
474
0
            || isSimchatTorah(date)
475
            // one-off closings
476
0
            || (d == 27 && m == February && y == 2024) // Municipal elections
477
            // holidays abroad
478
0
            || (d == 1 && m == January)  // Western New Year's day
479
0
            || dd == easterMonday(y) - 3  // Good Friday
480
0
            || (d >= 25 && w == Monday && m == May && y != 2022) // Spring Bank Holiday
481
0
            || (d == 3 && m == June && y == 2022)
482
0
            || (d == 25 && m == December)  // Christmas
483
0
            || (d == 26 && m == December)  // Boxing day
484
            // other days when fixings were not published
485
0
            || (d == 1 && m == November && y == 2022) // no idea why
486
0
            || (d == 2 && m == January && y == 2023) // Maybe New Year's Day is adjusted to Monday?
487
0
            || (d == 10 && m == April && y == 2023) // Easter Monday, not a holiday in 2024 and 2025
488
0
            )
489
0
            return false; // NOLINT(readability-simplify-boolean-expr)
490
491
0
        return true;
492
0
    }
493
494
}