Coverage Report

Created: 2025-08-28 06:30

/src/quantlib/ql/time/daycounters/thirty360.cpp
Line
Count
Source (jump to first uncovered line)
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) 2018 Alexey Indiryakov
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
 <http://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/daycounters/thirty360.hpp>
22
#include <algorithm>
23
24
namespace QuantLib {
25
26
    namespace {
27
28
0
        bool isLastOfFebruary(Day d, Month m, Year y) {
29
0
            return m == 2 && d == 28 + (Date::isLeap(y) ? 1 : 0);
30
0
        }
31
32
    }
33
34
    ext::shared_ptr<DayCounter::Impl>
35
6
    Thirty360::implementation(Thirty360::Convention c, const Date& terminationDate) {
36
6
        switch (c) {
37
0
          case USA:
38
0
            return ext::shared_ptr<DayCounter::Impl>(new US_Impl);
39
0
          case European:
40
0
          case EurobondBasis:
41
0
            return ext::shared_ptr<DayCounter::Impl>(new EU_Impl);
42
0
          case Italian:
43
0
            return ext::shared_ptr<DayCounter::Impl>(new IT_Impl);
44
0
          case ISMA:
45
6
          case BondBasis:
46
6
            return ext::shared_ptr<DayCounter::Impl>(new ISMA_Impl);
47
0
          case ISDA:
48
0
          case German:
49
0
            return ext::shared_ptr<DayCounter::Impl>(new ISDA_Impl(terminationDate));
50
0
          case NASD:
51
0
            return ext::shared_ptr<DayCounter::Impl>(new NASD_Impl);
52
0
          default:
53
0
            QL_FAIL("unknown 30/360 convention");
54
6
        }
55
6
    }
56
57
    Date::serial_type Thirty360::US_Impl::dayCount(const Date& d1,
58
0
                                                   const Date& d2) const {
59
0
        Day dd1 = d1.dayOfMonth(), dd2 = d2.dayOfMonth();
60
0
        Month mm1 = d1.month(), mm2 = d2.month();
61
0
        Year yy1 = d1.year(), yy2 = d2.year();
62
63
        // See https://en.wikipedia.org/wiki/Day_count_convention#30/360_US
64
        // NOTE: the order of checks is important
65
0
        if (isLastOfFebruary(dd1, mm1, yy1)) {
66
0
            if (isLastOfFebruary(dd2, mm2, yy2)) { dd2 = 30; }
67
0
            dd1 = 30;
68
0
        }
69
0
        if (dd2 == 31 && dd1 >= 30) { dd2 = 30; }
70
0
        if (dd1 == 31) { dd1 = 30; }
71
72
0
        return 360*(yy2-yy1) + 30*(mm2-mm1) + (dd2-dd1);
73
0
    }
74
75
    Date::serial_type Thirty360::ISMA_Impl::dayCount(const Date& d1,
76
0
                                                     const Date& d2) const {
77
0
        Day dd1 = d1.dayOfMonth(), dd2 = d2.dayOfMonth();
78
0
        Month mm1 = d1.month(), mm2 = d2.month();
79
0
        Year yy1 = d1.year(), yy2 = d2.year();
80
81
0
        if (dd1 == 31) { dd1 = 30; }
82
0
        if (dd2 == 31 && dd1 == 30) { dd2 = 30; }
83
84
0
        return 360*(yy2-yy1) + 30*(mm2-mm1) + (dd2-dd1);
85
0
    }
86
87
    Date::serial_type Thirty360::EU_Impl::dayCount(const Date& d1,
88
0
                                                   const Date& d2) const {
89
0
        Day dd1 = d1.dayOfMonth(), dd2 = d2.dayOfMonth();
90
0
        Month mm1 = d1.month(), mm2 = d2.month();
91
0
        Year yy1 = d1.year(), yy2 = d2.year();
92
93
0
        if (dd1 == 31) { dd1 = 30; }
94
0
        if (dd2 == 31) { dd2 = 30; }
95
96
0
        return 360*(yy2-yy1) + 30*(mm2-mm1) + (dd2-dd1);
97
0
    }
98
99
    Date::serial_type Thirty360::IT_Impl::dayCount(const Date& d1,
100
0
                                                   const Date& d2) const {
101
0
        Day dd1 = d1.dayOfMonth(), dd2 = d2.dayOfMonth();
102
0
        Month mm1 = d1.month(), mm2 = d2.month();
103
0
        Year yy1 = d1.year(), yy2 = d2.year();
104
105
0
        if (dd1 == 31) { dd1 = 30; }
106
0
        if (dd2 == 31) { dd2 = 30; }
107
108
0
        if (mm1 == 2 && dd1 > 27) { dd1 = 30; }
109
0
        if (mm2 == 2 && dd2 > 27) { dd2 = 30; }
110
111
0
        return 360*(yy2-yy1) + 30*(mm2-mm1) + (dd2-dd1);
112
0
    }
113
114
    Date::serial_type Thirty360::ISDA_Impl::dayCount(const Date& d1,
115
0
                                                     const Date& d2) const {
116
0
        Day dd1 = d1.dayOfMonth(), dd2 = d2.dayOfMonth();
117
0
        Month mm1 = d1.month(), mm2 = d2.month();
118
0
        Year yy1 = d1.year(), yy2 = d2.year();
119
120
0
        if (dd1 == 31) { dd1 = 30; }
121
0
        if (dd2 == 31) { dd2 = 30; }
122
123
0
        if (isLastOfFebruary(dd1, mm1, yy1)) { dd1 = 30; }
124
125
0
        if (d2 != terminationDate_ && isLastOfFebruary(dd2, mm2, yy2)) { dd2 = 30; }
126
127
0
        return 360*(yy2-yy1) + 30*(mm2-mm1) + (dd2-dd1);
128
0
    }
129
130
    Date::serial_type Thirty360::NASD_Impl::dayCount(const Date& d1,
131
0
                                                     const Date& d2) const {
132
0
        Day dd1 = d1.dayOfMonth(), dd2 = d2.dayOfMonth();
133
0
        Integer mm1 = d1.month(), mm2 = d2.month();
134
0
        Year yy1 = d1.year(), yy2 = d2.year();
135
136
0
        if (dd1 == 31) { dd1 = 30; }
137
0
        if (dd2 == 31 && dd1 >= 30) { dd2 = 30; }
138
0
        if (dd2 == 31 && dd1 < 30) { dd2 = 1; mm2++; }
139
140
0
        return 360*(yy2-yy1) + 30*(mm2-mm1) + (dd2-dd1);
141
0
    }
142
143
}