1 /*
2 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit.
3 *
4 * Based in London, we are world leaders in the design and development
5 * of bespoke applications for the securities financing markets.
6 *
7 * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
8 * ___ _ _ _ _ _
9 * / _ \| |__ (_) ___ ___| |_| | __ _| |__
10 * | | | | '_ \| |/ _ \/ __| __| | / _` | '_ \
11 * | |_| | |_) | | __/ (__| |_| |__| (_| | |_) |
12 * \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
13 * |__/
14 *
15 * www.ObjectLab.co.uk
16 *
17 * $Id$
18 *
19 * Copyright 2006 the original author or authors.
20 *
21 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
22 * use this file except in compliance with the License. You may obtain a copy of
23 * the License at
24 *
25 * http://www.apache.org/licenses/LICENSE-2.0
26 *
27 * Unless required by applicable law or agreed to in writing, software
28 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30 * License for the specific language governing permissions and limitations under
31 * the License.
32 */
33 package net.objectlab.kit.datecalc.jdk;
34
35 import static java.util.Calendar.DAY_OF_MONTH;
36 import static java.util.Calendar.DECEMBER;
37 import static java.util.Calendar.JUNE;
38 import static java.util.Calendar.MARCH;
39 import static java.util.Calendar.MONTH;
40 import static java.util.Calendar.SEPTEMBER;
41 import static java.util.Calendar.WEDNESDAY;
42 import static net.objectlab.kit.datecalc.common.IMMPeriod.QUARTERLY;
43
44 import java.util.ArrayList;
45 import java.util.Calendar;
46 import java.util.List;
47
48 import net.objectlab.kit.datecalc.common.AbstractIMMDateCalculator;
49 import net.objectlab.kit.datecalc.common.IMMPeriod;
50
51 /**
52 * Jdk Calendar implementation of the
53 * {@link net.objectlab.kit.datecalc.common.IMMDateCalculator}
54 *
55 * @author Marcin Jekot
56 *
57 */
58 public class CalendarIMMDateCalculator extends AbstractIMMDateCalculator<Calendar> {
59 private static final int NUMBER_DAYS_IN_WEEK = 7;
60
61 /**
62 * Returns a list of IMM dates between 2 dates, it will exclude the start
63 * date if it is an IMM date but would include the end date if it is an IMM.
64 *
65 * @param start
66 * start of the interval, excluded
67 * @param end
68 * end of the interval, may be included.
69 * @param period
70 * specify when the "next" IMM is, if quarterly then it is the
71 * conventional algorithm.
72 * @return list of IMM dates
73 */
74 @Override
75 public List<Calendar> getIMMDates(final Calendar start, final Calendar end, final IMMPeriod period) {
76
77 final List<Calendar> dates = new ArrayList<>();
78 Calendar cal = (Calendar) start.clone();
79 while (true) {
80 cal = getNextIMMDate(true, cal, period);
81 if (!cal.after(end)) {
82 dates.add(cal);
83 } else {
84 break;
85 }
86 }
87
88 return dates;
89 }
90
91 @Override
92 protected Calendar getNextIMMDate(final boolean requestNextIMM, final Calendar startDate, final IMMPeriod period) {
93
94 Calendar cal = (Calendar) startDate.clone();
95
96 if (isIMMMonth(cal)) {
97 moveToIMMDay(cal);
98 if (requestNextIMM && cal.after(startDate) || !requestNextIMM && cal.before(startDate)) {
99 return cal;
100 }
101 }
102
103 final int delta = requestNextIMM ? 1 : -1;
104 do {
105 cal.add(MONTH, delta);
106 } while (!isIMMMonth(cal));
107
108 moveToIMMDay(cal);
109
110 cal = handlePeriod(requestNextIMM, period, cal);
111
112 return cal;
113 }
114
115 private Calendar handlePeriod(final boolean requestNextIMM, final IMMPeriod period, final Calendar givenCal) {
116 Calendar cal = givenCal;
117 final int month = cal.get(MONTH);
118 switch (period) {
119 case BI_ANNUALY_JUN_DEC:
120 if (month == MARCH || month == SEPTEMBER) {
121 // need to move to the next one.
122 cal = getNextIMMDate(requestNextIMM, cal, period);
123 }
124 break;
125
126 case BI_ANNUALY_MAR_SEP:
127 if (month == JUNE || month == DECEMBER) {
128 // need to move to the next one.
129 cal = getNextIMMDate(requestNextIMM, cal, period);
130 }
131 break;
132
133 case ANNUALLY:
134 // second jump
135 cal = getNextIMMDate(requestNextIMM, cal, QUARTERLY);
136 // third jump
137 cal = getNextIMMDate(requestNextIMM, cal, QUARTERLY);
138 // fourth jump
139 cal = getNextIMMDate(requestNextIMM, cal, QUARTERLY);
140 // fifth jump
141 cal = getNextIMMDate(requestNextIMM, cal, QUARTERLY);
142 break;
143
144 case QUARTERLY:
145 default:
146 break;
147 }
148 return cal;
149 }
150
151 // -----------------------------------------------------------------------
152 //
153 // ObjectLab, world leaders in the design and development of bespoke
154 // applications for the securities financing markets.
155 // www.ObjectLab.co.uk
156 //
157 // -----------------------------------------------------------------------
158
159 private static boolean isIMMMonth(final Calendar cal) {
160 final int month = cal.get(MONTH);
161
162 switch (month) {
163 case MARCH:
164 case JUNE:
165 case SEPTEMBER:
166 case DECEMBER:
167 return true;
168 default:
169 return false;
170 }
171 }
172
173 /**
174 * Assumes that the month is correct, get the day for the 3rd wednesday.
175 *
176 * @param cal
177 */
178 private static void moveToIMMDay(final Calendar cal) {
179 cal.set(DAY_OF_MONTH, 1);
180
181 // go to 1st wed
182 final int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
183 if (dayOfWeek < WEDNESDAY) {
184 cal.add(DAY_OF_MONTH, WEDNESDAY - dayOfWeek);
185 } else if (dayOfWeek > WEDNESDAY) {
186 cal.add(DAY_OF_MONTH, WEDNESDAY + NUMBER_DAYS_IN_WEEK - dayOfWeek);
187 }
188
189 // go to 3rd wednesday - i.e. move 2 weeks forward
190 cal.add(DAY_OF_MONTH, NUMBER_DAYS_IN_WEEK * 2);
191 }
192
193 @Override
194 public boolean isIMMDate(final Calendar date) {
195 // TODO a slightly crude implementation - revisit
196 final Calendar cal = (Calendar) date.clone();
197 moveToIMMDay(cal);
198 return cal.equals(date);
199 }
200 }
201
202 /*
203 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit.
204 *
205 * Based in London, we are world leaders in the design and development
206 * of bespoke applications for the securities financing markets.
207 *
208 * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
209 * ___ _ _ _ _ _
210 * / _ \| |__ (_) ___ ___| |_| | __ _| |__
211 * | | | | '_ \| |/ _ \/ __| __| | / _` | '_ \
212 * | |_| | |_) | | __/ (__| |_| |__| (_| | |_) |
213 * \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
214 * |__/
215 *
216 * www.ObjectLab.co.uk
217 */