View Javadoc
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  */