KickJava   Java API By Example, From Geeks To Geeks.

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


1 /* ========================================================================
2  * JCommon : a free general purpose class library for the Java(tm) platform
3  * ========================================================================
4  *
5  * (C) Copyright 2000-2006, 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  * SerialDate.java
29  * ---------------
30  * (C) Copyright 2001-2006, by Object Refinery Limited.
31  *
32  * Original Author: David Gilbert (for Object Refinery Limited);
33  * Contributor(s): -;
34  *
35  * $Id: SerialDate.java,v 1.8 2006/08/29 13:44:16 mungady Exp $
36  *
37  * Changes (from 11-Oct-2001)
38  * --------------------------
39  * 11-Oct-2001 : Re-organised the class and moved it to new package
40  * com.jrefinery.date (DG);
41  * 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate
42  * class (DG);
43  * 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate
44  * class is gone (DG); Changed getPreviousDayOfWeek(),
45  * getFollowingDayOfWeek() and getNearestDayOfWeek() to correct
46  * bugs (DG);
47  * 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG);
48  * 29-May-2002 : Moved the month constants into a separate interface
49  * (MonthConstants) (DG);
50  * 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG);
51  * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
52  * 13-Mar-2003 : Implemented Serializable (DG);
53  * 29-May-2003 : Fixed bug in addMonths method (DG);
54  * 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG);
55  * 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG);
56  *
57  */

58
59 package org.jfree.date;
60
61 import java.io.Serializable JavaDoc;
62 import java.text.DateFormatSymbols JavaDoc;
63 import java.text.SimpleDateFormat JavaDoc;
64 import java.util.Calendar JavaDoc;
65 import java.util.GregorianCalendar JavaDoc;
66
67 /**
68  * An abstract class that defines our requirements for manipulating dates,
69  * without tying down a particular implementation.
70  * <P>
71  * Requirement 1 : match at least what Excel does for dates;
72  * Requirement 2 : the date represented by the class is immutable;
73  * <P>
74  * Why not just use java.util.Date? We will, when it makes sense. At times,
75  * java.util.Date can be *too* precise - it represents an instant in time,
76  * accurate to 1/1000th of a second (with the date itself depending on the
77  * time-zone). Sometimes we just want to represent a particular day (e.g. 21
78  * January 2015) without concerning ourselves about the time of day, or the
79  * time-zone, or anything else. That's what we've defined SerialDate for.
80  * <P>
81  * You can call getInstance() to get a concrete subclass of SerialDate,
82  * without worrying about the exact implementation.
83  *
84  * @author David Gilbert
85  */

86 public abstract class SerialDate implements Comparable JavaDoc,
87                                             Serializable JavaDoc,
88                                             MonthConstants {
89
90     /** For serialization. */
91     private static final long serialVersionUID = -293716040467423637L;
92     
93     /** Date format symbols. */
94     public static final DateFormatSymbols JavaDoc
95         DATE_FORMAT_SYMBOLS = new SimpleDateFormat JavaDoc().getDateFormatSymbols();
96
97     /** The serial number for 1 January 1900. */
98     public static final int SERIAL_LOWER_BOUND = 2;
99
100     /** The serial number for 31 December 9999. */
101     public static final int SERIAL_UPPER_BOUND = 2958465;
102
103     /** The lowest year value supported by this date format. */
104     public static final int MINIMUM_YEAR_SUPPORTED = 1900;
105
106     /** The highest year value supported by this date format. */
107     public static final int MAXIMUM_YEAR_SUPPORTED = 9999;
108
109     /** Useful constant for Monday. Equivalent to java.util.Calendar.MONDAY. */
110     public static final int MONDAY = Calendar.MONDAY;
111
112     /**
113      * Useful constant for Tuesday. Equivalent to java.util.Calendar.TUESDAY.
114      */

115     public static final int TUESDAY = Calendar.TUESDAY;
116
117     /**
118      * Useful constant for Wednesday. Equivalent to
119      * java.util.Calendar.WEDNESDAY.
120      */

121     public static final int WEDNESDAY = Calendar.WEDNESDAY;
122
123     /**
124      * Useful constant for Thrusday. Equivalent to java.util.Calendar.THURSDAY.
125      */

126     public static final int THURSDAY = Calendar.THURSDAY;
127
128     /** Useful constant for Friday. Equivalent to java.util.Calendar.FRIDAY. */
129     public static final int FRIDAY = Calendar.FRIDAY;
130
131     /**
132      * Useful constant for Saturday. Equivalent to java.util.Calendar.SATURDAY.
133      */

134     public static final int SATURDAY = Calendar.SATURDAY;
135
136     /** Useful constant for Sunday. Equivalent to java.util.Calendar.SUNDAY. */
137     public static final int SUNDAY = Calendar.SUNDAY;
138
139     /** The number of days in each month in non leap years. */
140     static final int[] LAST_DAY_OF_MONTH =
141         {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
142
143     /** The number of days in a (non-leap) year up to the end of each month. */
144     static final int[] AGGREGATE_DAYS_TO_END_OF_MONTH =
145         {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
146
147     /** The number of days in a year up to the end of the preceding month. */
148     static final int[] AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH =
149         {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
150
151     /** The number of days in a leap year up to the end of each month. */
152     static final int[] LEAP_YEAR_AGGREGATE_DAYS_TO_END_OF_MONTH =
153         {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
154
155     /**
156      * The number of days in a leap year up to the end of the preceding month.
157      */

158     static final int[]
159         LEAP_YEAR_AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH =
160             {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
161
162     /** A useful constant for referring to the first week in a month. */
163     public static final int FIRST_WEEK_IN_MONTH = 1;
164
165     /** A useful constant for referring to the second week in a month. */
166     public static final int SECOND_WEEK_IN_MONTH = 2;
167
168     /** A useful constant for referring to the third week in a month. */
169     public static final int THIRD_WEEK_IN_MONTH = 3;
170
171     /** A useful constant for referring to the fourth week in a month. */
172     public static final int FOURTH_WEEK_IN_MONTH = 4;
173
174     /** A useful constant for referring to the last week in a month. */
175     public static final int LAST_WEEK_IN_MONTH = 0;
176
177     /** Useful range constant. */
178     public static final int INCLUDE_NONE = 0;
179
180     /** Useful range constant. */
181     public static final int INCLUDE_FIRST = 1;
182
183     /** Useful range constant. */
184     public static final int INCLUDE_SECOND = 2;
185
186     /** Useful range constant. */
187     public static final int INCLUDE_BOTH = 3;
188
189     /**
190      * Useful constant for specifying a day of the week relative to a fixed
191      * date.
192      */

193     public static final int PRECEDING = -1;
194
195     /**
196      * Useful constant for specifying a day of the week relative to a fixed
197      * date.
198      */

199     public static final int NEAREST = 0;
200
201     /**
202      * Useful constant for specifying a day of the week relative to a fixed
203      * date.
204      */

205     public static final int FOLLOWING = 1;
206
207     /** A description for the date. */
208     private String JavaDoc description;
209
210     /**
211      * Default constructor.
212      */

213     protected SerialDate() {
214     }
215
216     /**
217      * Returns <code>true</code> if the supplied integer code represents a
218      * valid day-of-the-week, and <code>false</code> otherwise.
219      *
220      * @param code the code being checked for validity.
221      *
222      * @return <code>true</code> if the supplied integer code represents a
223      * valid day-of-the-week, and <code>false</code> otherwise.
224      */

225     public static boolean isValidWeekdayCode(final int code) {
226
227         switch(code) {
228             case SUNDAY:
229             case MONDAY:
230             case TUESDAY:
231             case WEDNESDAY:
232             case THURSDAY:
233             case FRIDAY:
234             case SATURDAY:
235                 return true;
236             default:
237                 return false;
238         }
239
240     }
241
242     /**
243      * Converts the supplied string to a day of the week.
244      *
245      * @param s a string representing the day of the week.
246      *
247      * @return <code>-1</code> if the string is not convertable, the day of
248      * the week otherwise.
249      */

250     public static int stringToWeekdayCode(String JavaDoc s) {
251
252         final String JavaDoc[] shortWeekdayNames
253             = DATE_FORMAT_SYMBOLS.getShortWeekdays();
254         final String JavaDoc[] weekDayNames = DATE_FORMAT_SYMBOLS.getWeekdays();
255
256         int result = -1;
257         s = s.trim();
258         for (int i = 0; i < weekDayNames.length; i++) {
259             if (s.equals(shortWeekdayNames[i])) {
260                 result = i;
261                 break;
262             }
263             if (s.equals(weekDayNames[i])) {
264                 result = i;
265                 break;
266             }
267         }
268         return result;
269
270     }
271
272     /**
273      * Returns a string representing the supplied day-of-the-week.
274      * <P>
275      * Need to find a better approach.
276      *
277      * @param weekday the day of the week.
278      *
279      * @return a string representing the supplied day-of-the-week.
280      */

281     public static String JavaDoc weekdayCodeToString(final int weekday) {
282
283         final String JavaDoc[] weekdays = DATE_FORMAT_SYMBOLS.getWeekdays();
284         return weekdays[weekday];
285
286     }
287
288     /**
289      * Returns an array of month names.
290      *
291      * @return an array of month names.
292      */

293     public static String JavaDoc[] getMonths() {
294
295         return getMonths(false);
296
297     }
298
299     /**
300      * Returns an array of month names.
301      *
302      * @param shortened a flag indicating that shortened month names should
303      * be returned.
304      *
305      * @return an array of month names.
306      */

307     public static String JavaDoc[] getMonths(final boolean shortened) {
308
309         if (shortened) {
310             return DATE_FORMAT_SYMBOLS.getShortMonths();
311         }
312         else {
313             return DATE_FORMAT_SYMBOLS.getMonths();
314         }
315
316     }
317
318     /**
319      * Returns true if the supplied integer code represents a valid month.
320      *
321      * @param code the code being checked for validity.
322      *
323      * @return <code>true</code> if the supplied integer code represents a
324      * valid month.
325      */

326     public static boolean isValidMonthCode(final int code) {
327
328         switch(code) {
329             case JANUARY:
330             case FEBRUARY:
331             case MARCH:
332             case APRIL:
333             case MAY:
334             case JUNE:
335             case JULY:
336             case AUGUST:
337             case SEPTEMBER:
338             case OCTOBER:
339             case NOVEMBER:
340             case DECEMBER:
341                 return true;
342             default:
343                 return false;
344         }
345
346     }
347
348     /**
349      * Returns the quarter for the specified month.
350      *
351      * @param code the month code (1-12).
352      *
353      * @return the quarter that the month belongs to.
354      */

355     public static int monthCodeToQuarter(final int code) {
356
357         switch(code) {
358             case JANUARY:
359             case FEBRUARY:
360             case MARCH: return 1;
361             case APRIL:
362             case MAY:
363             case JUNE: return 2;
364             case JULY:
365             case AUGUST:
366             case SEPTEMBER: return 3;
367             case OCTOBER:
368             case NOVEMBER:
369             case DECEMBER: return 4;
370             default: throw new IllegalArgumentException JavaDoc(
371                 "SerialDate.monthCodeToQuarter: invalid month code.");
372         }
373
374     }
375
376     /**
377      * Returns a string representing the supplied month.
378      * <P>
379      * The string returned is the long form of the month name taken from the
380      * default locale.
381      *
382      * @param month the month.
383      *
384      * @return a string representing the supplied month.
385      */

386     public static String JavaDoc monthCodeToString(final int month) {
387
388         return monthCodeToString(month, false);
389
390     }
391
392     /**
393      * Returns a string representing the supplied month.
394      * <P>
395      * The string returned is the long or short form of the month name taken
396      * from the default locale.
397      *
398      * @param month the month.
399      * @param shortened if <code>true</code> return the abbreviation of the
400      * month.
401      *
402      * @return a string representing the supplied month.
403      */

404     public static String JavaDoc monthCodeToString(final int month,
405                                            final boolean shortened) {
406
407         // check arguments...
408
if (!isValidMonthCode(month)) {
409             throw new IllegalArgumentException JavaDoc(
410                 "SerialDate.monthCodeToString: month outside valid range.");
411         }
412
413         final String JavaDoc[] months;
414
415         if (shortened) {
416             months = DATE_FORMAT_SYMBOLS.getShortMonths();
417         }
418         else {
419             months = DATE_FORMAT_SYMBOLS.getMonths();
420         }
421
422         return months[month - 1];
423
424     }
425
426     /**
427      * Converts a string to a month code.
428      * <P>
429      * This method will return one of the constants JANUARY, FEBRUARY, ...,
430      * DECEMBER that corresponds to the string. If the string is not
431      * recognised, this method returns -1.
432      *
433      * @param s the string to parse.
434      *
435      * @return <code>-1</code> if the string is not parseable, the month of the
436      * year otherwise.
437      */

438     public static int stringToMonthCode(String JavaDoc s) {
439
440         final String JavaDoc[] shortMonthNames = DATE_FORMAT_SYMBOLS.getShortMonths();
441         final String JavaDoc[] monthNames = DATE_FORMAT_SYMBOLS.getMonths();
442
443         int result = -1;
444         s = s.trim();
445
446         // first try parsing the string as an integer (1-12)...
447
try {
448             result = Integer.parseInt(s);
449         }
450         catch (NumberFormatException JavaDoc e) {
451             // suppress
452
}
453
454         // now search through the month names...
455
if ((result < 1) || (result > 12)) {
456             for (int i = 0; i < monthNames.length; i++) {
457                 if (s.equals(shortMonthNames[i])) {
458                     result = i + 1;
459                     break;
460                 }
461                 if (s.equals(monthNames[i])) {
462                     result = i + 1;
463                     break;
464                 }
465             }
466         }
467
468         return result;
469
470     }
471
472     /**
473      * Returns true if the supplied integer code represents a valid
474      * week-in-the-month, and false otherwise.
475      *
476      * @param code the code being checked for validity.
477      * @return <code>true</code> if the supplied integer code represents a
478      * valid week-in-the-month.
479      */

480     public static boolean isValidWeekInMonthCode(final int code) {
481
482         switch(code) {
483             case FIRST_WEEK_IN_MONTH:
484             case SECOND_WEEK_IN_MONTH:
485             case THIRD_WEEK_IN_MONTH:
486             case FOURTH_WEEK_IN_MONTH:
487             case LAST_WEEK_IN_MONTH: return true;
488             default: return false;
489         }
490
491     }
492
493     /**
494      * Determines whether or not the specified year is a leap year.
495      *
496      * @param yyyy the year (in the range 1900 to 9999).
497      *
498      * @return <code>true</code> if the specified year is a leap year.
499      */

500     public static boolean isLeapYear(final int yyyy) {
501
502         if ((yyyy % 4) != 0) {
503             return false;
504         }
505         else if ((yyyy % 400) == 0) {
506             return true;
507         }
508         else if ((yyyy % 100) == 0) {
509             return false;
510         }
511         else {
512             return true;
513         }
514
515     }
516
517     /**
518      * Returns the number of leap years from 1900 to the specified year
519      * INCLUSIVE.
520      * <P>
521      * Note that 1900 is not a leap year.
522      *
523      * @param yyyy the year (in the range 1900 to 9999).
524      *
525      * @return the number of leap years from 1900 to the specified year.
526      */

527     public static int leapYearCount(final int yyyy) {
528
529         final int leap4 = (yyyy - 1896) / 4;
530         final int leap100 = (yyyy - 1800) / 100;
531         final int leap400 = (yyyy - 1600) / 400;
532         return leap4 - leap100 + leap400;
533
534     }
535
536     /**
537      * Returns the number of the last day of the month, taking into account
538      * leap years.
539      *
540      * @param month the month.
541      * @param yyyy the year (in the range 1900 to 9999).
542      *
543      * @return the number of the last day of the month.
544      */

545     public static int lastDayOfMonth(final int month, final int yyyy) {
546
547         final int result = LAST_DAY_OF_MONTH[month];
548         if (month != FEBRUARY) {
549             return result;
550         }
551         else if (isLeapYear(yyyy)) {
552             return result + 1;
553         }
554         else {
555             return result;
556         }
557
558     }
559
560     /**
561      * Creates a new date by adding the specified number of days to the base
562      * date.
563      *
564      * @param days the number of days to add (can be negative).
565      * @param base the base date.
566      *
567      * @return a new date.
568      */

569     public static SerialDate addDays(final int days, final SerialDate base) {
570
571         final int serialDayNumber = base.toSerial() + days;
572         return SerialDate.createInstance(serialDayNumber);
573
574     }
575
576     /**
577      * Creates a new date by adding the specified number of months to the base
578      * date.
579      * <P>
580      * If the base date is close to the end of the month, the day on the result
581      * may be adjusted slightly: 31 May + 1 month = 30 June.
582      *
583      * @param months the number of months to add (can be negative).
584      * @param base the base date.
585      *
586      * @return a new date.
587      */

588     public static SerialDate addMonths(final int months,
589                                        final SerialDate base) {
590
591         final int yy = (12 * base.getYYYY() + base.getMonth() + months - 1)
592                        / 12;
593         final int mm = (12 * base.getYYYY() + base.getMonth() + months - 1)
594                        % 12 + 1;
595         final int dd = Math.min(
596             base.getDayOfMonth(), SerialDate.lastDayOfMonth(mm, yy)
597         );
598         return SerialDate.createInstance(dd, mm, yy);
599
600     }
601
602     /**
603      * Creates a new date by adding the specified number of years to the base
604      * date.
605      *
606      * @param years the number of years to add (can be negative).
607      * @param base the base date.
608      *
609      * @return A new date.
610      */

611     public static SerialDate addYears(final int years, final SerialDate base) {
612
613         final int baseY = base.getYYYY();
614         final int baseM = base.getMonth();
615         final int baseD = base.getDayOfMonth();
616
617         final int targetY = baseY + years;
618         final int targetD = Math.min(
619             baseD, SerialDate.lastDayOfMonth(baseM, targetY)
620         );
621
622         return SerialDate.createInstance(targetD, baseM, targetY);
623
624     }
625
626     /**
627      * Returns the latest date that falls on the specified day-of-the-week and
628      * is BEFORE the base date.
629      *
630      * @param targetWeekday a code for the target day-of-the-week.
631      * @param base the base date.
632      *
633      * @return the latest date that falls on the specified day-of-the-week and
634      * is BEFORE the base date.
635      */

636     public static SerialDate getPreviousDayOfWeek(final int targetWeekday,
637                                                   final SerialDate base) {
638
639         // check arguments...
640
if (!SerialDate.isValidWeekdayCode(targetWeekday)) {
641             throw new IllegalArgumentException JavaDoc(
642                 "Invalid day-of-the-week code."
643             );
644         }
645
646         // find the date...
647
final int adjust;
648         final int baseDOW = base.getDayOfWeek();
649         if (baseDOW > targetWeekday) {
650             adjust = Math.min(0, targetWeekday - baseDOW);
651         }
652         else {
653             adjust = -7 + Math.max(0, targetWeekday - baseDOW);
654         }
655
656         return SerialDate.addDays(adjust, base);
657
658     }
659
660     /**
661      * Returns the earliest date that falls on the specified day-of-the-week
662      * and is AFTER the base date.
663      *
664      * @param targetWeekday a code for the target day-of-the-week.
665      * @param base the base date.
666      *
667      * @return the earliest date that falls on the specified day-of-the-week
668      * and is AFTER the base date.
669      */

670     public static SerialDate getFollowingDayOfWeek(final int targetWeekday,
671                                                    final SerialDate base) {
672
673         // check arguments...
674
if (!SerialDate.isValidWeekdayCode(targetWeekday)) {
675             throw new IllegalArgumentException JavaDoc(
676                 "Invalid day-of-the-week code."
677             );
678         }
679
680         // find the date...
681
final int adjust;
682         final int baseDOW = base.getDayOfWeek();
683         if (baseDOW > targetWeekday) {
684             adjust = 7 + Math.min(0, targetWeekday - baseDOW);
685         }
686         else {
687             adjust = Math.max(0, targetWeekday - baseDOW);
688         }
689
690         return SerialDate.addDays(adjust, base);
691     }
692
693     /**
694      * Returns the date that falls on the specified day-of-the-week and is
695      * CLOSEST to the base date.
696      *
697      * @param targetDOW a code for the target day-of-the-week.
698      * @param base the base date.
699      *
700      * @return the date that falls on the specified day-of-the-week and is
701      * CLOSEST to the base date.
702      */

703     public static SerialDate getNearestDayOfWeek(final int targetDOW,
704                                                  final SerialDate base) {
705
706         // check arguments...
707
if (!SerialDate.isValidWeekdayCode(targetDOW)) {
708             throw new IllegalArgumentException JavaDoc(
709                 "Invalid day-of-the-week code."
710             );
711         }
712
713         // find the date...
714
final int baseDOW = base.getDayOfWeek();
715         int adjust = -Math.abs(targetDOW - baseDOW);
716         if (adjust >= 4) {
717             adjust = 7 - adjust;
718         }
719         if (adjust <= -4) {
720             adjust = 7 + adjust;
721         }
722         return SerialDate.addDays(adjust, base);
723
724     }
725
726     /**
727      * Rolls the date forward to the last day of the month.
728      *
729      * @param base the base date.
730      *
731      * @return a new serial date.
732      */

733     public SerialDate getEndOfCurrentMonth(final SerialDate base) {
734         final int last = SerialDate.lastDayOfMonth(
735             base.getMonth(), base.getYYYY()
736         );
737         return SerialDate.createInstance(last, base.getMonth(), base.getYYYY());
738     }
739
740     /**
741      * Returns a string corresponding to the week-in-the-month code.
742      * <P>
743      * Need to find a better approach.
744      *
745      * @param count an integer code representing the week-in-the-month.
746      *
747      * @return a string corresponding to the week-in-the-month code.
748      */

749     public static String JavaDoc weekInMonthToString(final int count) {
750
751         switch (count) {
752             case SerialDate.FIRST_WEEK_IN_MONTH : return "First";
753             case SerialDate.SECOND_WEEK_IN_MONTH : return "Second";
754             case SerialDate.THIRD_WEEK_IN_MONTH : return "Third";
755             case SerialDate.FOURTH_WEEK_IN_MONTH : return "Fourth";
756             case SerialDate.LAST_WEEK_IN_MONTH : return "Last";
757             default :
758                 return "SerialDate.weekInMonthToString(): invalid code.";
759         }
760
761     }
762
763     /**
764      * Returns a string representing the supplied 'relative'.
765      * <P>
766      * Need to find a better approach.
767      *
768      * @param relative a constant representing the 'relative'.
769      *
770      * @return a string representing the supplied 'relative'.
771      */

772     public static String JavaDoc relativeToString(final int relative) {
773
774         switch (relative) {
775             case SerialDate.PRECEDING : return "Preceding";
776             case SerialDate.NEAREST : return "Nearest";
777             case SerialDate.FOLLOWING : return "Following";
778             default : return "ERROR : Relative To String";
779         }
780
781     }
782
783     /**
784      * Factory method that returns an instance of some concrete subclass of
785      * {@link SerialDate}.
786      *
787      * @param day the day (1-31).
788      * @param month the month (1-12).
789      * @param yyyy the year (in the range 1900 to 9999).
790      *
791      * @return An instance of {@link SerialDate}.
792      */

793     public static SerialDate createInstance(final int day, final int month,
794                                             final int yyyy) {
795         return new SpreadsheetDate(day, month, yyyy);
796     }
797
798     /**
799      * Factory method that returns an instance of some concrete subclass of
800      * {@link SerialDate}.
801      *
802      * @param serial the serial number for the day (1 January 1900 = 2).
803      *
804      * @return a instance of SerialDate.
805      */

806     public static SerialDate createInstance(final int serial) {
807         return new SpreadsheetDate(serial);
808     }
809
810     /**
811      * Factory method that returns an instance of a subclass of SerialDate.
812      *
813      * @param date A Java date object.
814      *
815      * @return a instance of SerialDate.
816      */

817     public static SerialDate createInstance(final java.util.Date JavaDoc date) {
818
819         final GregorianCalendar JavaDoc calendar = new GregorianCalendar JavaDoc();
820         calendar.setTime(date);
821         return new SpreadsheetDate(calendar.get(Calendar.DATE),
822                                    calendar.get(Calendar.MONTH) + 1,
823                                    calendar.get(Calendar.YEAR));
824
825     }
826
827     /**
828      * Returns the serial number for the date, where 1 January 1900 = 2 (this
829      * corresponds, almost, to the numbering system used in Microsoft Excel for
830      * Windows and Lotus 1-2-3).
831      *
832      * @return the serial number for the date.
833      */

834     public abstract int toSerial();
835
836     /**
837      * Returns a java.util.Date. Since java.util.Date has more precision than
838      * SerialDate, we need to define a convention for the 'time of day'.
839      *
840      * @return this as <code>java.util.Date</code>.
841      */

842     public abstract java.util.Date JavaDoc toDate();
843
844     /**
845      * Returns the description that is attached to the date. It is not
846      * required that a date have a description, but for some applications it
847      * is useful.
848      *
849      * @return The description (possibly <code>null</code>).
850      */

851     public String JavaDoc getDescription() {
852         return this.description;
853     }
854
855     /**
856      * Sets the description for the date.
857      *
858      * @param description the description for this date (<code>null</code>
859      * permitted).
860      */

861     public void setDescription(final String JavaDoc description) {
862         this.description = description;
863     }
864
865     /**
866      * Converts the date to a string.
867      *
868      * @return a string representation of the date.
869      */

870     public String JavaDoc toString() {
871         return getDayOfMonth() + "-" + SerialDate.monthCodeToString(getMonth())
872                                + "-" + getYYYY();
873     }
874
875     /**
876      * Returns the year (assume a valid range of 1900 to 9999).
877      *
878      * @return the year.
879      */

880     public abstract int getYYYY();
881
882     /**
883      * Returns the month (January = 1, February = 2, March = 3).
884      *
885      * @return the month of the year.
886      */

887     public abstract int getMonth();
888
889     /**
890      * Returns the day of the month.
891      *
892      * @return the day of the month.
893      */

894     public abstract int getDayOfMonth();
895
896     /**
897      * Returns the day of the week.
898      *
899      * @return the day of the week.
900      */

901     public abstract int getDayOfWeek();
902
903     /**
904      * Returns the difference (in days) between this date and the specified
905      * 'other' date.
906      * <P>
907      * The result is positive if this date is after the 'other' date and
908      * negative if it is before the 'other' date.
909      *
910      * @param other the date being compared to.
911      *
912      * @return the difference between this and the other date.
913      */

914     public abstract int compare(SerialDate other);
915
916     /**
917      * Returns true if this SerialDate represents the same date as the
918      * specified SerialDate.
919      *
920      * @param other the date being compared to.
921      *
922      * @return <code>true</code> if this SerialDate represents the same date as
923      * the specified SerialDate.
924      */

925     public abstract boolean isOn(SerialDate other);
926
927     /**
928      * Returns true if this SerialDate represents an earlier date compared to
929      * the specified SerialDate.
930      *
931      * @param other The date being compared to.
932      *
933      * @return <code>true</code> if this SerialDate represents an earlier date
934      * compared to the specified SerialDate.
935      */

936     public abstract boolean isBefore(SerialDate other);
937
938     /**
939      * Returns true if this SerialDate represents the same date as the
940      * specified SerialDate.
941      *
942      * @param other the date being compared to.
943      *
944      * @return <code>true<code> if this SerialDate represents the same date
945      * as the specified SerialDate.
946      */

947     public abstract boolean isOnOrBefore(SerialDate other);
948
949     /**
950      * Returns true if this SerialDate represents the same date as the
951      * specified SerialDate.
952      *
953      * @param other the date being compared to.
954      *
955      * @return <code>true</code> if this SerialDate represents the same date
956      * as the specified SerialDate.
957      */

958     public abstract boolean isAfter(SerialDate other);
959
960     /**
961      * Returns true if this SerialDate represents the same date as the
962      * specified SerialDate.
963      *
964      * @param other the date being compared to.
965      *
966      * @return <code>true</code> if this SerialDate represents the same date
967      * as the specified SerialDate.
968      */

969     public abstract boolean isOnOrAfter(SerialDate other);
970
971     /**
972      * Returns <code>true</code> if this {@link SerialDate} is within the
973      * specified range (INCLUSIVE). The date order of d1 and d2 is not
974      * important.
975      *
976      * @param d1 a boundary date for the range.
977      * @param d2 the other boundary date for the range.
978      *
979      * @return A boolean.
980      */

981     public abstract boolean isInRange(SerialDate d1, SerialDate d2);
982
983     /**
984      * Returns <code>true</code> if this {@link SerialDate} is within the
985      * specified range (caller specifies whether or not the end-points are
986      * included). The date order of d1 and d2 is not important.
987      *
988      * @param d1 a boundary date for the range.
989      * @param d2 the other boundary date for the range.
990      * @param include a code that controls whether or not the start and end
991      * dates are included in the range.
992      *
993      * @return A boolean.
994      */

995     public abstract boolean isInRange(SerialDate d1, SerialDate d2,
996                                       int include);
997
998     /**
999      * Returns the latest date that falls on the specified day-of-the-week and
1000     * is BEFORE this date.
1001     *
1002     * @param targetDOW a code for the target day-of-the-week.
1003     *
1004     * @return the latest date that falls on the specified day-of-the-week and
1005     * is BEFORE this date.
1006     */

1007    public SerialDate getPreviousDayOfWeek(final int targetDOW) {
1008        return getPreviousDayOfWeek(targetDOW, this);
1009    }
1010
1011    /**
1012     * Returns the earliest date that falls on the specified day-of-the-week
1013     * and is AFTER this date.
1014     *
1015     * @param targetDOW a code for the target day-of-the-week.
1016     *
1017     * @return the earliest date that falls on the specified day-of-the-week
1018     * and is AFTER this date.
1019     */

1020    public SerialDate getFollowingDayOfWeek(final int targetDOW) {
1021        return getFollowingDayOfWeek(targetDOW, this);
1022    }
1023
1024    /**
1025     * Returns the nearest date that falls on the specified day-of-the-week.
1026     *
1027     * @param targetDOW a code for the target day-of-the-week.
1028     *
1029     * @return the nearest date that falls on the specified day-of-the-week.
1030     */

1031    public SerialDate getNearestDayOfWeek(final int targetDOW) {
1032        return getNearestDayOfWeek(targetDOW, this);
1033    }
1034
1035}
1036
Popular Tags