1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package net.objectlab.kit.datecalc.jdk;
34
35 import java.util.Calendar;
36
37 import net.objectlab.kit.datecalc.common.CalculatorConstants;
38 import net.objectlab.kit.datecalc.common.PeriodCountBasis;
39 import net.objectlab.kit.datecalc.common.PeriodCountCalculator;
40
41
42
43
44
45
46
47
48 public class CalendarPeriodCountCalculator implements PeriodCountCalculator<Calendar> {
49
50 private static final long MILLIS_IN_DAY = 1000L * 60L * 60L * 24L;
51
52 public int dayDiff(final Calendar start, final Calendar end, final PeriodCountBasis basis) {
53
54 int diff;
55
56 switch (basis) {
57 case CONV_30_360:
58 diff = calculateConv30360(start, end);
59 break;
60
61 case CONV_360E_ISDA:
62 diff = calculateConv360EIsda(start, end);
63 break;
64
65 case CONV_360E_ISMA:
66 diff = calculateConv360EIsma(start, end);
67 break;
68
69 default:
70 diff = dayDiff(start, end);
71 }
72
73 return diff;
74 }
75
76 private int calculateConv360EIsma(final Calendar start, final Calendar end) {
77 int diff;
78 int dayStart = start.get(Calendar.DAY_OF_MONTH);
79 int dayEnd = end.get(Calendar.DAY_OF_MONTH);
80 if (dayEnd == CalculatorConstants.MONTH_31_DAYS) {
81 dayEnd = CalculatorConstants.MONTH_30_DAYS;
82 }
83 if (dayStart == CalculatorConstants.MONTH_31_DAYS) {
84 dayStart = CalculatorConstants.MONTH_30_DAYS;
85 }
86 diff = (end.get(Calendar.YEAR) - start.get(Calendar.YEAR)) * CalculatorConstants.YEAR_360 + (end.get(Calendar.MONTH) - start.get(Calendar.MONTH)) * CalculatorConstants.MONTH_30_DAYS
87 + dayEnd - dayStart;
88 return diff;
89 }
90
91 private int calculateConv360EIsda(final Calendar start, final Calendar end) {
92 if (start.equals(end)) {
93 return 0;
94 }
95 int diff;
96 int dayStart = start.get(Calendar.DAY_OF_MONTH);
97 int dayEnd = end.get(Calendar.DAY_OF_MONTH);
98 if (start.getActualMaximum(Calendar.DAY_OF_MONTH) == dayStart) {
99 dayStart = CalculatorConstants.MONTH_30_DAYS;
100 }
101 if (end.get(Calendar.MONTH) != Calendar.FEBRUARY && end.getActualMaximum(Calendar.DAY_OF_MONTH) == dayEnd) {
102 dayEnd = CalculatorConstants.MONTH_30_DAYS;
103 }
104
105 diff = (end.get(Calendar.YEAR) - start.get(Calendar.YEAR)) * CalculatorConstants.YEAR_360 + (end.get(Calendar.MONTH) - start.get(Calendar.MONTH)) * CalculatorConstants.MONTH_30_DAYS
106 + dayEnd - dayStart;
107 return diff;
108 }
109
110 private int calculateConv30360(final Calendar start, final Calendar end) {
111 int diff;
112 int dayStart = start.get(Calendar.DAY_OF_MONTH);
113 int dayEnd = end.get(Calendar.DAY_OF_MONTH);
114 if (dayEnd == CalculatorConstants.MONTH_31_DAYS && dayStart >= CalculatorConstants.MONTH_30_DAYS) {
115 dayEnd = CalculatorConstants.MONTH_30_DAYS;
116 }
117 if (dayStart == CalculatorConstants.MONTH_31_DAYS) {
118 dayStart = CalculatorConstants.MONTH_30_DAYS;
119 }
120 diff = (end.get(Calendar.YEAR) - start.get(Calendar.YEAR)) * CalculatorConstants.YEAR_360 + (end.get(Calendar.MONTH) - start.get(Calendar.MONTH)) * CalculatorConstants.MONTH_30_DAYS
121 + dayEnd - dayStart;
122 return diff;
123 }
124
125
126
127
128
129
130
131
132
133 private static int dayDiff(final Calendar start, final Calendar end) {
134 final long diff = Math.abs(start.getTimeInMillis() - end.getTimeInMillis());
135 final double dayDiff = (double) diff / MILLIS_IN_DAY;
136 return (int) Math.round(dayDiff);
137 }
138
139 public double monthDiff(final Calendar start, final Calendar end, final PeriodCountBasis basis) {
140 return yearDiff(start, end, basis) * CalculatorConstants.MONTHS_IN_YEAR;
141 }
142
143 public double yearDiff(final Calendar start, final Calendar end, final PeriodCountBasis basis) {
144 double diff = 0.0;
145
146 switch (basis) {
147 case ACT_ACT:
148 final int startYear = start.get(Calendar.YEAR);
149 final int endYear = end.get(Calendar.YEAR);
150 if (startYear != endYear) {
151 final Calendar endOfStartYear = (Calendar) start.clone();
152 endOfStartYear.set(Calendar.DAY_OF_YEAR, endOfStartYear.getActualMaximum(Calendar.DAY_OF_YEAR));
153 final Calendar startOfEndYear = (Calendar) end.clone();
154 startOfEndYear.set(Calendar.DAY_OF_YEAR, startOfEndYear.getActualMinimum(Calendar.DAY_OF_YEAR));
155
156 final int diff1 = dayDiff(start, endOfStartYear);
157 final int diff2 = dayDiff(startOfEndYear, end);
158
159 diff = (diff1 + 1.0) / start.getActualMaximum(Calendar.DAY_OF_YEAR) + (endYear - startYear - 1.0)
160 + diff2 / (double) end.getActualMaximum(Calendar.DAY_OF_YEAR);
161 }
162 break;
163
164 case CONV_30_360:
165 case CONV_360E_ISDA:
166 case CONV_360E_ISMA:
167 case ACT_360:
168 diff = dayDiff(start, end, basis) / CalculatorConstants.YEAR_360_0;
169 break;
170
171 case ACT_365:
172 diff = dayDiff(start, end, basis) / CalculatorConstants.YEAR_365_0;
173 break;
174
175 default:
176 throw new UnsupportedOperationException("Sorry no ACT_UST yet");
177 }
178
179 return diff;
180 }
181
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199