KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > date > SerialDateUtilities


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jcommon/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * ------------------------
28  * SerialDateUtilities.java
29  * ------------------------
30  * (C) Copyright 2001-2003, by Object Refinery Limited.
31  *
32  * Original Author: David Gilbert (for Object Refinery Limited);
33  * Contributor(s): -;
34  *
35  * $Id: SerialDateUtilities.java,v 1.6 2005/11/16 15:58:40 taqua Exp $
36  *
37  * Changes (from 26-Oct-2001)
38  * --------------------------
39  * 26-Oct-2001 : Changed package to com.jrefinery.date.*;
40  * 08-Dec-2001 : Dropped isLeapYear() method (DG);
41  * 04-Mar-2002 : Renamed SerialDates.java --> SerialDateUtilities.java (DG);
42  * 25-Jun-2002 : Fixed a bug in the dayCountActual() method (DG);
43  * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
44  *
45  */

46
47 package org.jfree.date;
48
49 import java.text.DateFormatSymbols JavaDoc;
50 import java.util.Calendar JavaDoc;
51
52 /**
53  * A utility class that provides a number of useful methods (some static).
54  * Many of these are used in the implementation of the day-count convention
55  * classes. I recognise some limitations in this implementation:
56  * <p>
57  * [1] some of the methods assume that the default Calendar is a
58  * GregorianCalendar (used mostly to determine leap years) - so the code
59  * won&rsquo;t work if some other Calendar is the default. I'm not sure how
60  * to handle this properly?
61  * <p>
62  * [2] a whole bunch of static methods isn't very object-oriented - but I couldn't think of a good
63  * way to extend the Date and Calendar classes to add the functions I required,
64  * so static methods are doing the job for now.
65  *
66  * @author David Gilbert
67  */

68 public class SerialDateUtilities {
69
70     /** The default date format symbols. */
71     private DateFormatSymbols JavaDoc dateFormatSymbols;
72
73     /** Strings representing the weekdays. */
74     private String JavaDoc[] weekdays;
75
76     /** Strings representing the months. */
77     private String JavaDoc[] months;
78
79     /**
80      * Creates a new utility class for the default locale.
81      */

82     public SerialDateUtilities() {
83         this.dateFormatSymbols = new DateFormatSymbols JavaDoc();
84         this.weekdays = this.dateFormatSymbols.getWeekdays();
85         this.months = this.dateFormatSymbols.getMonths();
86     }
87
88     /**
89      * Returns an array of strings representing the days-of-the-week.
90      *
91      * @return an array of strings representing the days-of-the-week.
92      */

93     public String JavaDoc[] getWeekdays() {
94         return this.weekdays;
95     }
96
97     /**
98      * Returns an array of strings representing the months.
99      *
100      * @return an array of strings representing the months.
101      */

102     public String JavaDoc[] getMonths() {
103         return this.months;
104     }
105
106     /**
107      * Converts the specified string to a weekday, using the default locale.
108      *
109      * @param s a string representing the day-of-the-week.
110      *
111      * @return an integer representing the day-of-the-week.
112      */

113     public int stringToWeekday(final String JavaDoc s) {
114
115         if (s.equals(this.weekdays[Calendar.SATURDAY])) {
116             return SerialDate.SATURDAY;
117         }
118         else if (s.equals(this.weekdays[Calendar.SUNDAY])) {
119             return SerialDate.SUNDAY;
120         }
121         else if (s.equals(this.weekdays[Calendar.MONDAY])) {
122             return SerialDate.MONDAY;
123         }
124         else if (s.equals(this.weekdays[Calendar.TUESDAY])) {
125             return SerialDate.TUESDAY;
126         }
127         else if (s.equals(this.weekdays[Calendar.WEDNESDAY])) {
128             return SerialDate.WEDNESDAY;
129         }
130         else if (s.equals(this.weekdays[Calendar.THURSDAY])) {
131             return SerialDate.THURSDAY;
132         }
133         else {
134             return SerialDate.FRIDAY;
135         }
136
137     }
138
139     /**
140      * Returns the actual number of days between two dates.
141      *
142      * @param start the start date.
143      * @param end the end date.
144      *
145      * @return the number of days between the start date and the end date.
146      */

147     public static int dayCountActual(final SerialDate start, final SerialDate end) {
148         return end.compare(start);
149     }
150
151     /**
152      * Returns the number of days between the specified start and end dates,
153      * assuming that there are thirty days in every month (that is,
154      * corresponding to the 30/360 day-count convention).
155      * <P>
156      * The method handles cases where the start date is before the end date (by
157      * switching the dates and returning a negative result).
158      *
159      * @param start the start date.
160      * @param end the end date.
161      *
162      * @return the number of days between the two dates, assuming the 30/360 day-count convention.
163      */

164     public static int dayCount30(final SerialDate start, final SerialDate end) {
165         final int d1;
166         final int m1;
167         final int y1;
168         final int d2;
169         final int m2;
170         final int y2;
171         if (start.isBefore(end)) { // check the order of the dates
172
d1 = start.getDayOfMonth();
173             m1 = start.getMonth();
174             y1 = start.getYYYY();
175             d2 = end.getDayOfMonth();
176             m2 = end.getMonth();
177             y2 = end.getYYYY();
178             return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1);
179         }
180         else {
181             return -dayCount30(end, start);
182         }
183     }
184
185     /**
186      * Returns the number of days between the specified start and end dates,
187      * assuming that there are thirty days in every month, and applying the
188      * ISDA adjustments (that is, corresponding to the 30/360 (ISDA) day-count
189      * convention).
190      * <P>
191      * The method handles cases where the start date is before the end date (by
192      * switching the dates around and returning a negative result).
193      *
194      * @param start the start date.
195      * @param end the end date.
196      *
197      * @return The number of days between the two dates, assuming the 30/360
198      * (ISDA) day-count convention.
199      */

200     public static int dayCount30ISDA(final SerialDate start, final SerialDate end) {
201         int d1;
202         final int m1;
203         final int y1;
204         int d2;
205         final int m2;
206         final int y2;
207         if (start.isBefore(end)) {
208             d1 = start.getDayOfMonth();
209             m1 = start.getMonth();
210             y1 = start.getYYYY();
211             if (d1 == 31) { // first ISDA adjustment
212
d1 = 30;
213             }
214             d2 = end.getDayOfMonth();
215             m2 = end.getMonth();
216             y2 = end.getYYYY();
217             if ((d2 == 31) && (d1 == 30)) { // second ISDA adjustment
218
d2 = 30;
219             }
220             return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1);
221         }
222         else if (start.isAfter(end)) {
223             return -dayCount30ISDA(end, start);
224         }
225         else {
226             return 0;
227         }
228     }
229
230     /**
231      * Returns the number of days between the specified start and end dates,
232      * assuming that there are thirty days in every month, and applying the PSA
233      * adjustments (that is, corresponding to the 30/360 (PSA) day-count convention).
234      * The method handles cases where the start date is before the end date (by
235      * switching the dates around and returning a negative result).
236      *
237      * @param start the start date.
238      * @param end the end date.
239      *
240      * @return The number of days between the two dates, assuming the 30/360
241      * (PSA) day-count convention.
242      */

243     public static int dayCount30PSA(final SerialDate start, final SerialDate end) {
244         int d1;
245         final int m1;
246         final int y1;
247         int d2;
248         final int m2;
249         final int y2;
250
251         if (start.isOnOrBefore(end)) { // check the order of the dates
252
d1 = start.getDayOfMonth();
253             m1 = start.getMonth();
254             y1 = start.getYYYY();
255
256             if (SerialDateUtilities.isLastDayOfFebruary(start)) {
257                 d1 = 30;
258             }
259             if ((d1 == 31) || SerialDateUtilities.isLastDayOfFebruary(start)) {
260                 // first PSA adjustment
261
d1 = 30;
262             }
263             d2 = end.getDayOfMonth();
264             m2 = end.getMonth();
265             y2 = end.getYYYY();
266             if ((d2 == 31) && (d1 == 30)) { // second PSA adjustment
267
d2 = 30;
268             }
269             return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1);
270         }
271         else {
272             return -dayCount30PSA(end, start);
273         }
274     }
275
276     /**
277      * Returns the number of days between the specified start and end dates,
278      * assuming that there are thirty days in every month, and applying the
279      * European adjustment (that is, corresponding to the 30E/360 day-count
280      * convention).
281      * <P>
282      * The method handles cases where the start date is before the end date (by
283      * switching the dates around and returning a negative result).
284      *
285      * @param start the start date.
286      * @param end the end date.
287      *
288      * @return the number of days between the two dates, assuming the 30E/360
289      * day-count convention.
290      */

291     public static int dayCount30E(final SerialDate start, final SerialDate end) {
292         int d1;
293         final int m1;
294         final int y1;
295         int d2;
296         final int m2;
297         final int y2;
298         if (start.isBefore(end)) {
299             d1 = start.getDayOfMonth();
300             m1 = start.getMonth();
301             y1 = start.getYYYY();
302             if (d1 == 31) { // first European adjustment
303
d1 = 30;
304             }
305             d2 = end.getDayOfMonth();
306             m2 = end.getMonth();
307             y2 = end.getYYYY();
308             if (d2 == 31) { // first European adjustment
309
d2 = 30;
310             }
311             return 360 * (y2 - y1) + 30 * (m2 - m1) + (d2 - d1);
312         }
313         else if (start.isAfter(end)) {
314             return -dayCount30E(end, start);
315         }
316         else {
317             return 0;
318         }
319     }
320
321     /**
322      * Returns true if the specified date is the last day in February (that is, the
323      * 28th in non-leap years, and the 29th in leap years).
324      *
325      * @param d the date to be tested.
326      *
327      * @return a boolean that indicates whether or not the specified date is
328      * the last day of February.
329      */

330     public static boolean isLastDayOfFebruary(final SerialDate d) {
331
332         final int dom;
333         if (d.getMonth() == MonthConstants.FEBRUARY) {
334             dom = d.getDayOfMonth();
335             if (SerialDate.isLeapYear(d.getYYYY())) {
336                 return (dom == 29);
337             }
338             else {
339                 return (dom == 28);
340             }
341         }
342         else { // not even February
343
return false;
344         }
345
346     }
347
348     /**
349      * Returns the number of times that February 29 falls within the specified
350      * date range. The result needs to correspond to the ACT/365 (Japanese)
351      * day-count convention. The difficult cases are where the start or the
352      * end date is Feb 29 (include or not?). Need to find out how JGBs do this
353      * (since this is where the ACT/365 (Japanese) convention comes from ...
354      *
355      * @param start the start date.
356      * @param end the end date.
357      *
358      * @return the number of times that February 29 occurs within the date
359      * range.
360      */

361     public static int countFeb29s(final SerialDate start, final SerialDate end) {
362         int count = 0;
363         SerialDate feb29;
364         final int y1;
365         final int y2;
366         int year;
367
368         // check the order of the dates
369
if (start.isBefore(end)) {
370
371             y1 = start.getYYYY();
372             y2 = end.getYYYY();
373             for (year = y1; year == y2; year++) {
374                 if (SerialDate.isLeapYear(year)) {
375                     feb29 = SerialDate.createInstance(29, MonthConstants.FEBRUARY, year);
376                     if (feb29.isInRange(start, end, SerialDate.INCLUDE_SECOND)) {
377                         count++;
378                     }
379                 }
380             }
381             return count;
382         }
383         else {
384             return countFeb29s(end, start);
385         }
386     }
387
388 }
389
Popular Tags