Clean code part3
Listing B-1
SerialDate.Java
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 * SerialDate.java
29 * ---------------
30 * (C) Copyright 2001-2005, by Object Refinery Limited.
31 *
32 * Original Author: David Gilbert (for Object Refinery Limited);
33 * Contributor(s): -;
34 *
35 * $Id: SerialDate.java,v 1.7 2005/11/03 09:25:17 mungady Exp $
36 *
37 * Changes (from 11-Oct-2001)
350 Appendix B: org.jfree.date.SerialDate
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;
62 import java.text.DateFormatSymbols;
63 import java.text.SimpleDateFormat;
64 import java.util.Calendar;
65 import java.util.GregorianCalendar;
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 : 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,
87 Serializable,
88 MonthConstants {
89
90 /** For serialization. */
91 private static final long serialVersionUID = -293716040467423637L;
92
93 /** Date format symbols. */
94 public static final DateFormatSymbols
95 DATE_FORMAT_SYMBOLS = new SimpleDateFormat().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
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 351
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
Listing B-1 (continued)
SerialDate.Java
352 Appendix B: org.jfree.date.SerialDate
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 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
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 353
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 s) {
251
252 final String[] shortWeekdayNames
253 = DATE_FORMAT_SYMBOLS.getShortWeekdays();
254 final String[] 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 weekdayCodeToString(final int weekday) {
282
283 final String[] weekdays = DATE_FORMAT_SYMBOLS.getWeekdays();
284 return weekdays[weekday];
285
286 }
287
288 /**
Listing B-1 (continued)
SerialDate.Java
354 Appendix B: org.jfree.date.SerialDate
289 * Returns an array of month names.
290 *
291 * @return an array of month names.
292 */
293 public static String[] 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[] 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 *
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 355
351 * @param code the month code (1-12).
352 *
353 * @return the quarter that the month belongs to.
354 * @throws java.lang.IllegalArgumentException
355 */
356 public static int monthCodeToQuarter(final int code) {
357
358 switch(code) {
359 case JANUARY:
360 case FEBRUARY:
361 case MARCH: return 1;
362 case APRIL:
363 case MAY:
364 case JUNE: return 2;
365 case JULY:
366 case AUGUST:
367 case SEPTEMBER: return 3;
368 case OCTOBER:
369 case NOVEMBER:
370 case DECEMBER: return 4;
371 default: throw new IllegalArgumentException(
372 "SerialDate.monthCodeToQuarter: invalid month code.");
373 }
374
375 }
376
377 /**
378 * Returns a string representing the supplied month.
379 * <P>
380 * The string returned is the long form of the month name taken from the
381 * default locale.
382 *
383 * @param month the month.
384 *
385 * @return a string representing the supplied month.
386 */
387 public static String monthCodeToString(final int month) {
388
389 return monthCodeToString(month, false);
390
391 }
392
393 /**
394 * Returns a string representing the supplied month.
395 * <P>
396 * The string returned is the long or short form of the month name taken
397 * from the default locale.
398 *
399 * @param month the month.
400 * @param shortened if <code>true</code> return the abbreviation of the
401 * month.
402 *
403 * @return a string representing the supplied month.
404 * @throws java.lang.IllegalArgumentException
405 */
406 public static String monthCodeToString(final int month,
407 final boolean shortened) {
408
409 // check arguments...
410 if (!isValidMonthCode(month)) {
411 throw new IllegalArgumentException(
412 "SerialDate.monthCodeToString: month outside valid range.");
Listing B-1 (continued)
SerialDate.Java
356 Appendix B: org.jfree.date.SerialDate
413 }
414
415 final String[] months;
416
417 if (shortened) {
418 months = DATE_FORMAT_SYMBOLS.getShortMonths();
419 }
420 else {
421 months = DATE_FORMAT_SYMBOLS.getMonths();
422 }
423
424 return months[month - 1];
425
426 }
427
428 /**
429 * Converts a string to a month code.
430 * <P>
431 * This method will return one of the constants JANUARY, FEBRUARY, ...,
432 * DECEMBER that corresponds to the string. If the string is not
433 * recognised, this method returns -1.
434 *
435 * @param s the string to parse.
436 *
437 * @return <code>-1</code> if the string is not parseable, the month of the
438 * year otherwise.
439 */
440 public static int stringToMonthCode(String s) {
441
442 final String[] shortMonthNames = DATE_FORMAT_SYMBOLS.getShortMonths();
443 final String[] monthNames = DATE_FORMAT_SYMBOLS.getMonths();
444
445 int result = -1;
446 s = s.trim();
447
448 // first try parsing the string as an integer (1-12)...
449 try {
450 result = Integer.parseInt(s);
451 }
452 catch (NumberFormatException e) {
453 // suppress
454 }
455
456 // now search through the month names...
457 if ((result < 1) || (result > 12)) {
458 for (int i = 0; i < monthNames.length; i++) {
459 if (s.equals(shortMonthNames[i])) {
460 result = i + 1;
461 break;
462 }
463 if (s.equals(monthNames[i])) {
464 result = i + 1;
465 break;
466 }
467 }
468 }
469
470 return result;
471
472 }
473
474 /**
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 357
475 * Returns true if the supplied integer code represents a valid
476 * week-in-the-month, and false otherwise.
477 *
478 * @param code the code being checked for validity.
479 * @return <code>true</code> if the supplied integer code represents a
480 * valid week-in-the-month.
481 */
482 public static boolean isValidWeekInMonthCode(final int code) {
483
484 switch(code) {
485 case FIRST_WEEK_IN_MONTH:
486 case SECOND_WEEK_IN_MONTH:
487 case THIRD_WEEK_IN_MONTH:
488 case FOURTH_WEEK_IN_MONTH:
489 case LAST_WEEK_IN_MONTH: return true;
490 default: return false;
491 }
492
493 }
494
495 /**
496 * Determines whether or not the specified year is a leap year.
497 *
498 * @param yyyy the year (in the range 1900 to 9999).
499 *
500 * @return <code>true</code> if the specified year is a leap year.
501 */
502 public static boolean isLeapYear(final int yyyy) {
503
504 if ((yyyy % 4) != 0) {
505 return false;
506 }
507 else if ((yyyy % 400) == 0) {
508 return true;
509 }
510 else if ((yyyy % 100) == 0) {
511 return false;
512 }
513 else {
514 return true;
515 }
516
517 }
518
519 /**
520 * Returns the number of leap years from 1900 to the specified year
521 * INCLUSIVE.
522 * <P>
523 * Note that 1900 is not a leap year.
524 *
525 * @param yyyy the year (in the range 1900 to 9999).
526 *
527 * @return the number of leap years from 1900 to the specified year.
528 */
529 public static int leapYearCount(final int yyyy) {
530
531 final int leap4 = (yyyy - 1896) / 4;
532 final int leap100 = (yyyy - 1800) / 100;
533 final int leap400 = (yyyy - 1600) / 400;
534 return leap4 - leap100 + leap400;
535
536 }
Listing B-1 (continued)
SerialDate.Java
358 Appendix B: org.jfree.date.SerialDate
537
538 /**
539 * Returns the number of the last day of the month, taking into account
540 * leap years.
541 *
542 * @param month the month.
543 * @param yyyy the year (in the range 1900 to 9999).
544 *
545 * @return the number of the last day of the month.
546 */
547 public static int lastDayOfMonth(final int month, final int yyyy) {
548
549 final int result = LAST_DAY_OF_MONTH[month];
550 if (month != FEBRUARY) {
551 return result;
552 }
553 else if (isLeapYear(yyyy)) {
554 return result + 1;
555 }
556 else {
557 return result;
558 }
559
560 }
561
562 /**
563 * Creates a new date by adding the specified number of days to the base
564 * date.
565 *
566 * @param days the number of days to add (can be negative).
567 * @param base the base date.
568 *
569 * @return a new date.
570 */
571 public static SerialDate addDays(final int days, final SerialDate base) {
572
573 final int serialDayNumber = base.toSerial() + days;
574 return SerialDate.createInstance(serialDayNumber);
575
576 }
577
578 /**
579 * Creates a new date by adding the specified number of months to the base
580 * date.
581 * <P>
582 * If the base date is close to the end of the month, the day on the result
583 * may be adjusted slightly: 31 May + 1 month = 30 June.
584 *
585 * @param months the number of months to add (can be negative).
586 * @param base the base date.
587 *
588 * @return a new date.
589 */
590 public static SerialDate addMonths(final int months,
591 final SerialDate base) {
592
593 final int yy = (12 * base.getYYYY() + base.getMonth() + months - 1)
594 / 12;
595 final int mm = (12 * base.getYYYY() + base.getMonth() + months - 1)
596 % 12 + 1;
597 final int dd = Math.min(
598 base.getDayOfMonth(), SerialDate.lastDayOfMonth(mm, yy)
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 359
599 );
600 return SerialDate.createInstance(dd, mm, yy);
601
602 }
603
604 /**
605 * Creates a new date by adding the specified number of years to the base
606 * date.
607 *
608 * @param years the number of years to add (can be negative).
609 * @param base the base date.
610 *
611 * @return A new date.
612 */
613 public static SerialDate addYears(final int years, final SerialDate base) {
614
615 final int baseY = base.getYYYY();
616 final int baseM = base.getMonth();
617 final int baseD = base.getDayOfMonth();
618
619 final int targetY = baseY + years;
620 final int targetD = Math.min(
621 baseD, SerialDate.lastDayOfMonth(baseM, targetY)
622 );
623
624 return SerialDate.createInstance(targetD, baseM, targetY);
625
626 }
627
628 /**
629 * Returns the latest date that falls on the specified day-of-the-week and
630 * is BEFORE the base date.
631 *
632 * @param targetWeekday a code for the target day-of-the-week.
633 * @param base the base date.
634 *
635 * @return the latest date that falls on the specified day-of-the-week and
636 * is BEFORE the base date.
637 */
638 public static SerialDate getPreviousDayOfWeek(final int targetWeekday,
639 final SerialDate base) {
640
641 // check arguments...
642 if (!SerialDate.isValidWeekdayCode(targetWeekday)) {
643 throw new IllegalArgumentException(
644 "Invalid day-of-the-week code."
645 );
646 }
647
648 // find the date...
649 final int adjust;
650 final int baseDOW = base.getDayOfWeek();
651 if (baseDOW > targetWeekday) {
652 adjust = Math.min(0, targetWeekday - baseDOW);
653 }
654 else {
655 adjust = -7 + Math.max(0, targetWeekday - baseDOW);
656 }
657
658 return SerialDate.addDays(adjust, base);
659
660 }
Listing B-1 (continued)
SerialDate.Java
360 Appendix B: org.jfree.date.SerialDate
661
662 /**
663 * Returns the earliest date that falls on the specified day-of-the-week
664 * and is AFTER the base date.
665 *
666 * @param targetWeekday a code for the target day-of-the-week.
667 * @param base the base date.
668 *
669 * @return the earliest date that falls on the specified day-of-the-week
670 * and is AFTER the base date.
671 */
672 public static SerialDate getFollowingDayOfWeek(final int targetWeekday,
673 final SerialDate base) {
674
675 // check arguments...
676 if (!SerialDate.isValidWeekdayCode(targetWeekday)) {
677 throw new IllegalArgumentException(
678 "Invalid day-of-the-week code."
679 );
680 }
681
682 // find the date...
683 final int adjust;
684 final int baseDOW = base.getDayOfWeek();
685 if (baseDOW > targetWeekday) {
686 adjust = 7 + Math.min(0, targetWeekday - baseDOW);
687 }
688 else {
689 adjust = Math.max(0, targetWeekday - baseDOW);
690 }
691
692 return SerialDate.addDays(adjust, base);
693 }
694
695 /**
696 * Returns the date that falls on the specified day-of-the-week and is
697 * CLOSEST to the base date.
698 *
699 * @param targetDOW a code for the target day-of-the-week.
700 * @param base the base date.
701 *
702 * @return the date that falls on the specified day-of-the-week and is
703 * CLOSEST to the base date.
704 */
705 public static SerialDate getNearestDayOfWeek(final int targetDOW,
706 final SerialDate base) {
707
708 // check arguments...
709 if (!SerialDate.isValidWeekdayCode(targetDOW)) {
710 throw new IllegalArgumentException(
711 "Invalid day-of-the-week code."
712 );
713 }
714
715 // find the date...
716 final int baseDOW = base.getDayOfWeek();
717 int adjust = -Math.abs(targetDOW - baseDOW);
718 if (adjust >= 4) {
719 adjust = 7 - adjust;
720 }
721 if (adjust <= -4) {
722 adjust = 7 + adjust;
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 361
723 }
724 return SerialDate.addDays(adjust, base);
725
726 }
727
728 /**
729 * Rolls the date forward to the last day of the month.
730 *
731 * @param base the base date.
732 *
733 * @return a new serial date.
734 */
735 public SerialDate getEndOfCurrentMonth(final SerialDate base) {
736 final int last = SerialDate.lastDayOfMonth(
737 base.getMonth(), base.getYYYY()
738 );
739 return SerialDate.createInstance(last, base.getMonth(), base.getYYYY());
740 }
741
742 /**
743 * Returns a string corresponding to the week-in-the-month code.
744 * <P>
745 * Need to find a better approach.
746 *
747 * @param count an integer code representing the week-in-the-month.
748 *
749 * @return a string corresponding to the week-in-the-month code.
750 */
751 public static String weekInMonthToString(final int count) {
752
753 switch (count) {
754 case SerialDate.FIRST_WEEK_IN_MONTH : return "First";
755 case SerialDate.SECOND_WEEK_IN_MONTH : return "Second";
756 case SerialDate.THIRD_WEEK_IN_MONTH : return "Third";
757 case SerialDate.FOURTH_WEEK_IN_MONTH : return "Fourth";
758 case SerialDate.LAST_WEEK_IN_MONTH : return "Last";
759 default :
760 return "SerialDate.weekInMonthToString(): invalid code.";
761 }
762
763 }
764
765 /**
766 * Returns a string representing the supplied 'relative'.
767 * <P>
768 * Need to find a better approach.
769 *
770 * @param relative a constant representing the 'relative'.
771 *
772 * @return a string representing the supplied 'relative'.
773 */
774 public static String relativeToString(final int relative) {
775
776 switch (relative) {
777 case SerialDate.PRECEDING : return "Preceding";
778 case SerialDate.NEAREST : return "Nearest";
779 case SerialDate.FOLLOWING : return "Following";
780 default : return "ERROR : Relative To String";
781 }
782
783 }
784
Listing B-1 (continued)
SerialDate.Java
362 Appendix B: org.jfree.date.SerialDate
785 /**
786 * Factory method that returns an instance of some concrete subclass of
787 * {@link SerialDate}.
788 *
789 * @param day the day (1-31).
790 * @param month the month (1-12).
791 * @param yyyy the year (in the range 1900 to 9999).
792 *
793 * @return An instance of {@link SerialDate}.
794 */
795 public static SerialDate createInstance(final int day, final int month,
796 final int yyyy) {
797 return new SpreadsheetDate(day, month, yyyy);
798 }
799
800 /**
801 * Factory method that returns an instance of some concrete subclass of
802 * {@link SerialDate}.
803 *
804 * @param serial the serial number for the day (1 January 1900 = 2).
805 *
806 * @return a instance of SerialDate.
807 */
808 public static SerialDate createInstance(final int serial) {
809 return new SpreadsheetDate(serial);
810 }
811
812 /**
813 * Factory method that returns an instance of a subclass of SerialDate.
814 *
815 * @param date A Java date object.
816 *
817 * @return a instance of SerialDate.
818 */
819 public static SerialDate createInstance(final java.util.Date date) {
820
821 final GregorianCalendar calendar = new GregorianCalendar();
822 calendar.setTime(date);
823 return new SpreadsheetDate(calendar.get(Calendar.DATE),
824 calendar.get(Calendar.MONTH) + 1,
825 calendar.get(Calendar.YEAR));
826
827 }
828
829 /**
830 * Returns the serial number for the date, where 1 January 1900 = 2 (this
831 * corresponds, almost, to the numbering system used in Microsoft Excel for
832 * Windows and Lotus 1-2-3).
833 *
834 * @return the serial number for the date.
835 */
836 public abstract int toSerial();
837
838 /**
839 * Returns a java.util.Date. Since java.util.Date has more precision than
840 * SerialDate, we need to define a convention for the 'time of day'.
841 *
842 * @return this as <code>java.util.Date</code>.
843 */
844 public abstract java.util.Date toDate();
845
846 /**
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 363
847 * Returns a description of the date.
848 *
849 * @return a description of the date.
850 */
851 public String getDescription() {
852 return this.description;
853 }
854
855 /**
856 * Sets the description for the date.
857 *
858 * @param description the new description for the date.
859 */
860 public void setDescription(final String description) {
861 this.description = description;
862 }
863
864 /**
865 * Converts the date to a string.
866 *
867 * @return a string representation of the date.
868 */
869 public String toString() {
870 return getDayOfMonth() + "-" + SerialDate.monthCodeToString(getMonth())
871 + "-" + getYYYY();
872 }
873
874 /**
875 * Returns the year (assume a valid range of 1900 to 9999).
876 *
877 * @return the year.
878 */
879 public abstract int getYYYY();
880
881 /**
882 * Returns the month (January = 1, February = 2, March = 3).
883 *
884 * @return the month of the year.
885 */
886 public abstract int getMonth();
887
888 /**
889 * Returns the day of the month.
890 *
891 * @return the day of the month.
892 */
893 public abstract int getDayOfMonth();
894
895 /**
896 * Returns the day of the week.
897 *
898 * @return the day of the week.
899 */
900 public abstract int getDayOfWeek();
901
902 /**
903 * Returns the difference (in days) between this date and the specified
904 * 'other' date.
905 * <P>
906 * The result is positive if this date is after the 'other' date and
907 * negative if it is before the 'other' date.
908 *
Listing B-1 (continued)
SerialDate.Java
364 Appendix B: org.jfree.date.SerialDate
909 * @param other the date being compared to.
910 *
911 * @return the difference between this and the other date.
912 */
913 public abstract int compare(SerialDate other);
914
915 /**
916 * Returns true if this SerialDate represents the same date as the
917 * specified SerialDate.
918 *
919 * @param other the date being compared to.
920 *
921 * @return <code>true</code> if this SerialDate represents the same date as
922 * the specified SerialDate.
923 */
924 public abstract boolean isOn(SerialDate other);
925
926 /**
927 * Returns true if this SerialDate represents an earlier date compared to
928 * the specified SerialDate.
929 *
930 * @param other The date being compared to.
931 *
932 * @return <code>true</code> if this SerialDate represents an earlier date
933 * compared to the specified SerialDate.
934 */
935 public abstract boolean isBefore(SerialDate other);
936
937 /**
938 * Returns true if this SerialDate represents the same date as the
939 * specified SerialDate.
940 *
941 * @param other the date being compared to.
942 *
943 * @return <code>true<code> if this SerialDate represents the same date
944 * as the specified SerialDate.
945 */
946 public abstract boolean isOnOrBefore(SerialDate other);
947
948 /**
949 * Returns true if this SerialDate represents the same date as the
950 * specified SerialDate.
951 *
952 * @param other the date being compared to.
953 *
954 * @return <code>true</code> if this SerialDate represents the same date
955 * as the specified SerialDate.
956 */
957 public abstract boolean isAfter(SerialDate other);
958
959 /**
960 * Returns true if this SerialDate represents the same date as the
961 * specified SerialDate.
962 *
963 * @param other the date being compared to.
964 *
965 * @return <code>true</code> if this SerialDate represents the same date
966 * as the specified SerialDate.
967 */
968 public abstract boolean isOnOrAfter(SerialDate other);
969
970 /**
971 * Returns <code>true</code> if this {@link SerialDate} is within the
Listing B-1 (continued)
SerialDate.Java
Appendix B: org.jfree.date.SerialDate 365
972 * specified range (INCLUSIVE). The date order of d1 and d2 is not
973 * important.
974 *
975 * @param d1 a boundary date for the range.
976 * @param d2 the other boundary date for the range.
977 *
978 * @return A boolean.
979 */
980 public abstract boolean isInRange(SerialDate d1, SerialDate d2);
981
982 /**
983 * Returns <code>true</code> if this {@link SerialDate} is within the
984 * specified range (caller specifies whether or not the end-points are
985 * included). The date order of d1 and d2 is not important.
986 *
987 * @param d1 a boundary date for the range.
988 * @param d2 the other boundary date for the range.
989 * @param include a code that controls whether or not the start and end
990 * dates are included in the range.
991 *
992 * @return A boolean.
993 */
994 public abstract boolean isInRange(SerialDate d1, SerialDate d2,
995 int include);
996
997 /**
998 * Returns the latest date that falls on the specified day-of-the-week and
999 * is BEFORE this date.
1000 *
1001 * @param targetDOW a code for the target day-of-the-week.
1002 *
1003 * @return the latest date that falls on the specified day-of-the-week and
1004 * is BEFORE this date.
1005 */
1006 public SerialDate getPreviousDayOfWeek(final int targetDOW) {
1007 return getPreviousDayOfWeek(targetDOW, this);
1008 }
1009
1010 /**
1011 * Returns the earliest date that falls on the specified day-of-the-week
1012 * and is AFTER this date.
1013 *
1014 * @param targetDOW a code for the target day-of-the-week.
1015 *
1016 * @return the earliest date that falls on the specified day-of-the-week
1017 * and is AFTER this date.
1018 */
1019 public SerialDate getFollowingDayOfWeek(final int targetDOW) {
1020 return getFollowingDayOfWeek(targetDOW, this);
1021 }
1022
1023 /**
1024 * Returns the nearest date that falls on the specified day-of-the-week.
1025 *
1026 * @param targetDOW a code for the target day-of-the-week.
1027 *
1028 * @return the nearest date that falls on the specified day-of-the-week.
1029 */
1030 public SerialDate getNearestDayOfWeek(final int targetDOW) {
1031 return getNearestDayOfWeek(targetDOW, this);
1032 }
1033
1034 }
Listing B-1 (continued)
SerialDate.Java
366 Appendix B: org.jfree.date.SerialDate
Listing B-2
SerialDateTest.java
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 * SerialDateTests.java
29 * --------------------
30 * (C) Copyright 2001-2005, by Object Refinery Limited.
31 *
32 * Original Author: David Gilbert (for Object Refinery Limited);
33 * Contributor(s): -;
34 *
35 * $Id: SerialDateTests.java,v 1.6 2005/11/16 15:58:40 taqua Exp $
36 *
37 * Changes
38 * -------
39 * 15-Nov-2001 : Version 1 (DG);
40 * 25-Jun-2002 : Removed unnecessary import (DG);
41 * 24-Oct-2002 : Fixed errors reported by Checkstyle (DG);
42 * 13-Mar-2003 : Added serialization test (DG);
43 * 05-Jan-2005 : Added test for bug report 1096282 (DG);
44 *
45 */
46
47 package org.jfree.date.junit;
48
49 import java.io.ByteArrayInputStream;
50 import java.io.ByteArrayOutputStream;
51 import java.io.ObjectInput;
52 import java.io.ObjectInputStream;
53 import java.io.ObjectOutput;
54 import java.io.ObjectOutputStream;
55
56 import junit.framework.Test;
57 import junit.framework.TestCase;
58 import junit.framework.TestSuite;
59
60 import org.jfree.date.MonthConstants;
61 import org.jfree.date.SerialDate;
62
Appendix B: org.jfree.date.SerialDate 367
63 /**
64 * Some JUnit tests for the {@link SerialDate} class.
65 */
66 public class SerialDateTests extends TestCase {
67
68 /** Date representing November 9. */
69 private SerialDate nov9Y2001;
70
71 /**
72 * Creates a new test case.
73 *
74 * @param name the name.
75 */
76 public SerialDateTests(final String name) {
77 super(name);
78 }
79
80 /**
81 * Returns a test suite for the JUnit test runner.
82 *
83 * @return The test suite.
84 */
85 public static Test suite() {
86 return new TestSuite(SerialDateTests.class);
87 }
88
89 /**
90 * Problem set up.
91 */
92 protected void setUp() {
93 this.nov9Y2001 = SerialDate.createInstance(9, MonthConstants.NOVEMBER, 2001);
94 }
95
96 /**
97 * 9 Nov 2001 plus two months should be 9 Jan 2002.
98 */
99 public void testAddMonthsTo9Nov2001() {
100 final SerialDate jan9Y2002 = SerialDate.addMonths(2, this.nov9Y2001);
101 final SerialDate answer = SerialDate.createInstance(9, 1, 2002);
102 assertEquals(answer, jan9Y2002);
103 }
104
105 /**
106 * A test case for a reported bug, now fixed.
107 */
108 public void testAddMonthsTo5Oct2003() {
109 final SerialDate d1 = SerialDate.createInstance(5, MonthConstants.OCTOBER, 2003);
110 final SerialDate d2 = SerialDate.addMonths(2, d1);
111 assertEquals(d2, SerialDate.createInstance(5, MonthConstants.DECEMBER, 2003));
112 }
113
114 /**
115 * A test case for a reported bug, now fixed.
116 */
117 public void testAddMonthsTo1Jan2003() {
118 final SerialDate d1 = SerialDate.createInstance(1, MonthConstants.JANUARY, 2003);
119 final SerialDate d2 = SerialDate.addMonths(0, d1);
120 assertEquals(d2, d1);
121 }
122
123 /**
124 * Monday preceding Friday 9 November 2001 should be 5 November.
Listing B-2 (continued)
SerialDateTest.java
368 Appendix B: org.jfree.date.SerialDate
125 */
126 public void testMondayPrecedingFriday9Nov2001() {
127 SerialDate mondayBefore = SerialDate.getPreviousDayOfWeek(
128 SerialDate.MONDAY, this.nov9Y2001
129 );
130 assertEquals(5, mondayBefore.getDayOfMonth());
131 }
132
133 /**
134 * Monday following Friday 9 November 2001 should be 12 November.
135 */
136 public void testMondayFollowingFriday9Nov2001() {
137 SerialDate mondayAfter = SerialDate.getFollowingDayOfWeek(
138 SerialDate.MONDAY, this.nov9Y2001
139 );
140 assertEquals(12, mondayAfter.getDayOfMonth());
141 }
142
143 /**
144 * Monday nearest Friday 9 November 2001 should be 12 November.
145 */
146 public void testMondayNearestFriday9Nov2001() {
147 SerialDate mondayNearest = SerialDate.getNearestDayOfWeek(
148 SerialDate.MONDAY, this.nov9Y2001
149 );
150 assertEquals(12, mondayNearest.getDayOfMonth());
151 }
152
153 /**
154 * The Monday nearest to 22nd January 1970 falls on the 19th.
155 */
156 public void testMondayNearest22Jan1970() {
157 SerialDate jan22Y1970 = SerialDate.createInstance(22, MonthConstants.JANUARY, 1970);
158 SerialDate mondayNearest=SerialDate.getNearestDayOfWeek(SerialDate.MONDAY, jan22Y1970);
159 assertEquals(19, mondayNearest.getDayOfMonth());
160 }
161
162 /**
163 * Problem that the conversion of days to strings returns the right result. Actually, this
164 * result depends on the Locale so this test needs to be modified.
165 */
166 public void testWeekdayCodeToString() {
167
168 final String test = SerialDate.weekdayCodeToString(SerialDate.SATURDAY);
169 assertEquals("Saturday", test);
170
171 }
172
173 /**
174 * Test the conversion of a string to a weekday. Note that this test will fail if the
175 * default locale doesn't use English weekday names...devise a better test!
176 */
177 public void testStringToWeekday() {
178
179 int weekday = SerialDate.stringToWeekdayCode("Wednesday");
180 assertEquals(SerialDate.WEDNESDAY, weekday);
181
182 weekday = SerialDate.stringToWeekdayCode(" Wednesday ");
183 assertEquals(SerialDate.WEDNESDAY, weekday);
184
Listing B-2 (continued)
SerialDateTest.java
Appendix B: org.jfree.date.SerialDate 369
185 weekday = SerialDate.stringToWeekdayCode("Wed");
186 assertEquals(SerialDate.WEDNESDAY, weekday);
187
188 }
189
190 /**
191 * Test the conversion of a string to a month. Note that this test will fail if the
192 * default locale doesn't use English month names...devise a better test!
193 */
194 public void testStringToMonthCode() {
195
196 int m = SerialDate.stringToMonthCode("January");
197 assertEquals(MonthConstants.JANUARY, m);
198
199 m = SerialDate.stringToMonthCode(" January ");
200 assertEquals(MonthConstants.JANUARY, m);
201
202 m = SerialDate.stringToMonthCode("Jan");
203 assertEquals(MonthConstants.JANUARY, m);
204
205 }
206
207 /**
208 * Tests the conversion of a month code to a string.
209 */
210 public void testMonthCodeToStringCode() {
211
212 final String test = SerialDate.monthCodeToString(MonthConstants.DECEMBER);
213 assertEquals("December", test);
214
215 }
216
217 /**
218 * 1900 is not a leap year.
219 */
220 public void testIsNotLeapYear1900() {
221 assertTrue(!SerialDate.isLeapYear(1900));
222 }
223
224 /**
225 * 2000 is a leap year.
226 */
227 public void testIsLeapYear2000() {
228 assertTrue(SerialDate.isLeapYear(2000));
229 }
230
231 /**
232 * The number of leap years from 1900 up-to-and-including 1899 is 0.
233 */
234 public void testLeapYearCount1899() {
235 assertEquals(SerialDate.leapYearCount(1899), 0);
236 }
237
238 /**
239 * The number of leap years from 1900 up-to-and-including 1903 is 0.
240 */
241 public void testLeapYearCount1903() {
242 assertEquals(SerialDate.leapYearCount(1903), 0);
243 }
244
245 /**
246 * The number of leap years from 1900 up-to-and-including 1904 is 1.
247 */
Listing B-2 (continued)
SerialDateTest.java
370 Appendix B: org.jfree.date.SerialDate
248 public void testLeapYearCount1904() {
249 assertEquals(SerialDate.leapYearCount(1904), 1);
250 }
251
252 /**
253 * The number of leap years from 1900 up-to-and-including 1999 is 24.
254 */
255 public void testLeapYearCount1999() {
256 assertEquals(SerialDate.leapYearCount(1999), 24);
257 }
258
259 /**
260 * The number of leap years from 1900 up-to-and-including 2000 is 25.
261 */
262 public void testLeapYearCount2000() {
263 assertEquals(SerialDate.leapYearCount(2000), 25);
264 }
265
266 /**
267 * Serialize an instance, restore it, and check for equality.
268 */
269 public void testSerialization() {
270
271 SerialDate d1 = SerialDate.createInstance(15, 4, 2000);
272 SerialDate d2 = null;
273
274 try {
275 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
276 ObjectOutput out = new ObjectOutputStream(buffer);
277 out.writeObject(d1);
278 out.close();
279
280 ObjectInput in = new ObjectInputStream(
new ByteArrayInputStream(buffer.toByteArray()));
281 d2 = (SerialDate) in.readObject();
282 in.close();
283 }
284 catch (Exception e) {
285 System.out.println(e.toString());
286 }
287 assertEquals(d1, d2);
288
289 }
290
291 /**
292 * A test for bug report 1096282 (now fixed).
293 */
294 public void test1096282() {
295 SerialDate d = SerialDate.createInstance(29, 2, 2004);
296 d = SerialDate.addYears(1, d);
297 SerialDate expected = SerialDate.createInstance(28, 2, 2005);
298 assertTrue(d.isOn(expected));
299 }
300
301 /**
302 * Miscellaneous tests for the addMonths() method.
303 */
304 public void testAddMonths() {
305 SerialDate d1 = SerialDate.createInstance(31, 5, 2004);
306
Listing B-2 (continued)
SerialDateTest.java
Appendix B: org.jfree.date.SerialDate 371
307 SerialDate d2 = SerialDate.addMonths(1, d1);
308 assertEquals(30, d2.getDayOfMonth());
309 assertEquals(6, d2.getMonth());
310 assertEquals(2004, d2.getYYYY());
311
312 SerialDate d3 = SerialDate.addMonths(2, d1);
313 assertEquals(31, d3.getDayOfMonth());
314 assertEquals(7, d3.getMonth());
315 assertEquals(2004, d3.getYYYY());
316
317 SerialDate d4 = SerialDate.addMonths(1, SerialDate.addMonths(1, d1));
318 assertEquals(30, d4.getDayOfMonth());
319 assertEquals(7, d4.getMonth());
320 assertEquals(2004, d4.getYYYY());
321 }
322 }
Listing B-2 (continued)
SerialDateTest.java
372 Appendix B: org.jfree.date.SerialDate
Listing B-3
MonthConstants.java
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 * MonthConstants.java
29 * -------------------
30 * (C) Copyright 2002, 2003, by Object Refinery Limited.
31 *
32 * Original Author: David Gilbert (for Object Refinery Limited);
33 * Contributor(s): -;
34 *
35 * $Id: MonthConstants.java,v 1.4 2005/11/16 15:58:40 taqua Exp $
36 *
37 * Changes
38 * -------
39 * 29-May-2002 : Version 1 (code moved from SerialDate class) (DG);
40 *
41 */
42
43 package org.jfree.date;
44
45 /**
46 * Useful constants for months. Note that these are NOT equivalent to the
47 * constants defined by java.util.Calendar (where JANUARY=0 and DECEMBER=11).
48 * <P>
49 * Used by the SerialDate and RegularTimePeriod classes.
50 *
51 * @author David Gilbert
52 */
53 public interface MonthConstants {
54
55 /** Constant for January. */
56 public static final int JANUARY = 1;
57
58 /** Constant for February. */
59 public static final int FEBRUARY = 2;
60
Appendix B: org.jfree.date.SerialDate 373
61 /** Constant for March. */
62 public static final int MARCH = 3;
63
64 /** Constant for April. */
65 public static final int APRIL = 4;
66
67 /** Constant for May. */
68 public static final int MAY = 5;
69
70 /** Constant for June. */
71 public static final int JUNE = 6;
72
73 /** Constant for July. */
74 public static final int JULY = 7;
75
76 /** Constant for August. */
77 public static final int AUGUST = 8;
78
79 /** Constant for September. */
80 public static final int SEPTEMBER = 9;
81
82 /** Constant for October. */
83 public static final int OCTOBER = 10;
84
85 /** Constant for November. */
86 public static final int NOVEMBER = 11;
87
88 /** Constant for December. */
89 public static final int DECEMBER = 12;
90
91 }
Listing B-3 (continued)
MonthConstants.java
374 Appendix B: org.jfree.date.SerialDate
Listing B-4
BobsSerialDateTest.java
1 package org.jfree.date.junit;
2
3 import junit.framework.TestCase;
4 import org.jfree.date.*;
5 import static org.jfree.date.SerialDate.*;
6
7 import java.util.*;
8
9 public class BobsSerialDateTest extends TestCase {
10
11 public void testIsValidWeekdayCode() throws Exception {
12 for (int day = 1; day <= 7; day++)
13 assertTrue(isValidWeekdayCode(day));
14 assertFalse(isValidWeekdayCode(0));
15 assertFalse(isValidWeekdayCode(8));
16 }
17
18 public void testStringToWeekdayCode() throws Exception {
19
20 assertEquals(-1, stringToWeekdayCode("Hello"));
21 assertEquals(MONDAY, stringToWeekdayCode("Monday"));
22 assertEquals(MONDAY, stringToWeekdayCode("Mon"));
23 //todo assertEquals(MONDAY,stringToWeekdayCode("monday"));
24 // assertEquals(MONDAY,stringToWeekdayCode("MONDAY"));
25 // assertEquals(MONDAY, stringToWeekdayCode("mon"));
26
27 assertEquals(TUESDAY, stringToWeekdayCode("Tuesday"));
28 assertEquals(TUESDAY, stringToWeekdayCode("Tue"));
29 // assertEquals(TUESDAY,stringToWeekdayCode("tuesday"));
30 // assertEquals(TUESDAY,stringToWeekdayCode("TUESDAY"));
31 // assertEquals(TUESDAY, stringToWeekdayCode("tue"));
32 // assertEquals(TUESDAY, stringToWeekdayCode("tues"));
33
34 assertEquals(WEDNESDAY, stringToWeekdayCode("Wednesday"));
35 assertEquals(WEDNESDAY, stringToWeekdayCode("Wed"));
36 // assertEquals(WEDNESDAY,stringToWeekdayCode("wednesday"));
37 // assertEquals(WEDNESDAY,stringToWeekdayCode("WEDNESDAY"));
38 // assertEquals(WEDNESDAY, stringToWeekdayCode("wed"));
39
40 assertEquals(THURSDAY, stringToWeekdayCode("Thursday"));
41 assertEquals(THURSDAY, stringToWeekdayCode("Thu"));
42 // assertEquals(THURSDAY,stringToWeekdayCode("thursday"));
43 // assertEquals(THURSDAY,stringToWeekdayCode("THURSDAY"));
44 // assertEquals(THURSDAY, stringToWeekdayCode("thu"));
45 // assertEquals(THURSDAY, stringToWeekdayCode("thurs"));
46
47 assertEquals(FRIDAY, stringToWeekdayCode("Friday"));
48 assertEquals(FRIDAY, stringToWeekdayCode("Fri"));
49 // assertEquals(FRIDAY,stringToWeekdayCode("friday"));
50 // assertEquals(FRIDAY,stringToWeekdayCode("FRIDAY"));
51 // assertEquals(FRIDAY, stringToWeekdayCode("fri"));
52
53 assertEquals(SATURDAY, stringToWeekdayCode("Saturday"));
54 assertEquals(SATURDAY, stringToWeekdayCode("Sat"));
55 // assertEquals(SATURDAY,stringToWeekdayCode("saturday"));
56 // assertEquals(SATURDAY,stringToWeekdayCode("SATURDAY"));
57 // assertEquals(SATURDAY, stringToWeekdayCode("sat"));
58
59 assertEquals(SUNDAY, stringToWeekdayCode("Sunday"));
60 assertEquals(SUNDAY, stringToWeekdayCode("Sun"));
61 // assertEquals(SUNDAY,stringToWeekdayCode("sunday"));
62 // assertEquals(SUNDAY,stringToWeekdayCode("SUNDAY"));
63 // assertEquals(SUNDAY, stringToWeekdayCode("sun"));
64 }
65
Appendix B: org.jfree.date.SerialDate 375
66 public void testWeekdayCodeToString() throws Exception {
67 assertEquals("Sunday", weekdayCodeToString(SUNDAY));
68 assertEquals("Monday", weekdayCodeToString(MONDAY));
69 assertEquals("Tuesday", weekdayCodeToString(TUESDAY));
70 assertEquals("Wednesday", weekdayCodeToString(WEDNESDAY));
71 assertEquals("Thursday", weekdayCodeToString(THURSDAY));
72 assertEquals("Friday", weekdayCodeToString(FRIDAY));
73 assertEquals("Saturday", weekdayCodeToString(SATURDAY));
74 }
75
76 public void testIsValidMonthCode() throws Exception {
77 for (int i = 1; i <= 12; i++)
78 assertTrue(isValidMonthCode(i));
79 assertFalse(isValidMonthCode(0));
80 assertFalse(isValidMonthCode(13));
81 }
82
83 public void testMonthToQuarter() throws Exception {
84 assertEquals(1, monthCodeToQuarter(JANUARY));
85 assertEquals(1, monthCodeToQuarter(FEBRUARY));
86 assertEquals(1, monthCodeToQuarter(MARCH));
87 assertEquals(2, monthCodeToQuarter(APRIL));
88 assertEquals(2, monthCodeToQuarter(MAY));
89 assertEquals(2, monthCodeToQuarter(JUNE));
90 assertEquals(3, monthCodeToQuarter(JULY));
91 assertEquals(3, monthCodeToQuarter(AUGUST));
92 assertEquals(3, monthCodeToQuarter(SEPTEMBER));
93 assertEquals(4, monthCodeToQuarter(OCTOBER));
94 assertEquals(4, monthCodeToQuarter(NOVEMBER));
95 assertEquals(4, monthCodeToQuarter(DECEMBER));
96
97 try {
98 monthCodeToQuarter(-1);
99 fail("Invalid Month Code should throw exception");
100 } catch (IllegalArgumentException e) {
101 }
102 }
103
104 public void testMonthCodeToString() throws Exception {
105 assertEquals("January", monthCodeToString(JANUARY));
106 assertEquals("February", monthCodeToString(FEBRUARY));
107 assertEquals("March", monthCodeToString(MARCH));
108 assertEquals("April", monthCodeToString(APRIL));
109 assertEquals("May", monthCodeToString(MAY));
110 assertEquals("June", monthCodeToString(JUNE));
111 assertEquals("July", monthCodeToString(JULY));
112 assertEquals("August", monthCodeToString(AUGUST));
113 assertEquals("September", monthCodeToString(SEPTEMBER));
114 assertEquals("October", monthCodeToString(OCTOBER));
115 assertEquals("November", monthCodeToString(NOVEMBER));
116 assertEquals("December", monthCodeToString(DECEMBER));
117
118 assertEquals("Jan", monthCodeToString(JANUARY, true));
119 assertEquals("Feb", monthCodeToString(FEBRUARY, true));
120 assertEquals("Mar", monthCodeToString(MARCH, true));
121 assertEquals("Apr", monthCodeToString(APRIL, true));
122 assertEquals("May", monthCodeToString(MAY, true));
123 assertEquals("Jun", monthCodeToString(JUNE, true));
124 assertEquals("Jul", monthCodeToString(JULY, true));
125 assertEquals("Aug", monthCodeToString(AUGUST, true));
126 assertEquals("Sep", monthCodeToString(SEPTEMBER, true));
127 assertEquals("Oct", monthCodeToString(OCTOBER, true));
Listing B-4 (continued)
BobsSerialDateTest.java
376 Appendix B: org.jfree.date.SerialDate
128 assertEquals("Nov", monthCodeToString(NOVEMBER, true));
129 assertEquals("Dec", monthCodeToString(DECEMBER, true));
130
131 try {
132 monthCodeToString(-1);
133 fail("Invalid month code should throw exception");
134 } catch (IllegalArgumentException e) {
135 }
136
137 }
138
139 public void testStringToMonthCode() throws Exception {
140 assertEquals(JANUARY,stringToMonthCode("1"));
141 assertEquals(FEBRUARY,stringToMonthCode("2"));
142 assertEquals(MARCH,stringToMonthCode("3"));
143 assertEquals(APRIL,stringToMonthCode("4"));
144 assertEquals(MAY,stringToMonthCode("5"));
145 assertEquals(JUNE,stringToMonthCode("6"));
146 assertEquals(JULY,stringToMonthCode("7"));
147 assertEquals(AUGUST,stringToMonthCode("8"));
148 assertEquals(SEPTEMBER,stringToMonthCode("9"));
149 assertEquals(OCTOBER,stringToMonthCode("10"));
150 assertEquals(NOVEMBER, stringToMonthCode("11"));
151 assertEquals(DECEMBER,stringToMonthCode("12"));
152
153 //todo assertEquals(-1, stringToMonthCode("0"));
154 // assertEquals(-1, stringToMonthCode("13"));
155
156 assertEquals(-1,stringToMonthCode("Hello"));
157
158 for (int m = 1; m <= 12; m++) {
159 assertEquals(m, stringToMonthCode(monthCodeToString(m, false)));
160 assertEquals(m, stringToMonthCode(monthCodeToString(m, true)));
161 }
162
163 // assertEquals(1,stringToMonthCode("jan"));
164 // assertEquals(2,stringToMonthCode("feb"));
165 // assertEquals(3,stringToMonthCode("mar"));
166 // assertEquals(4,stringToMonthCode("apr"));
167 // assertEquals(5,stringToMonthCode("may"));
168 // assertEquals(6,stringToMonthCode("jun"));
169 // assertEquals(7,stringToMonthCode("jul"));
170 // assertEquals(8,stringToMonthCode("aug"));
171 // assertEquals(9,stringToMonthCode("sep"));
172 // assertEquals(10,stringToMonthCode("oct"));
173 // assertEquals(11,stringToMonthCode("nov"));
174 // assertEquals(12,stringToMonthCode("dec"));
175
176 // assertEquals(1,stringToMonthCode("JAN"));
177 // assertEquals(2,stringToMonthCode("FEB"));
178 // assertEquals(3,stringToMonthCode("MAR"));
179 // assertEquals(4,stringToMonthCode("APR"));
180 // assertEquals(5,stringToMonthCode("MAY"));
181 // assertEquals(6,stringToMonthCode("JUN"));
182 // assertEquals(7,stringToMonthCode("JUL"));
183 // assertEquals(8,stringToMonthCode("AUG"));
184 // assertEquals(9,stringToMonthCode("SEP"));
185 // assertEquals(10,stringToMonthCode("OCT"));
186 // assertEquals(11,stringToMonthCode("NOV"));
187 // assertEquals(12,stringToMonthCode("DEC"));
188
189 // assertEquals(1,stringToMonthCode("january"));
190 // assertEquals(2,stringToMonthCode("february"));
Listing B-4 (continued)
BobsSerialDateTest.java
Appendix B: org.jfree.date.SerialDate 377
191 // assertEquals(3,stringToMonthCode("march"));
192 // assertEquals(4,stringToMonthCode("april"));
193 // assertEquals(5,stringToMonthCode("may"));
194 // assertEquals(6,stringToMonthCode("june"));
195 // assertEquals(7,stringToMonthCode("july"));
196 // assertEquals(8,stringToMonthCode("august"));
197 // assertEquals(9,stringToMonthCode("september"));
198 // assertEquals(10,stringToMonthCode("october"));
199 // assertEquals(11,stringToMonthCode("november"));
200 // assertEquals(12,stringToMonthCode("december"));
201
202 // assertEquals(1,stringToMonthCode("JANUARY"));
203 // assertEquals(2,stringToMonthCode("FEBRUARY"));
204 // assertEquals(3,stringToMonthCode("MAR"));
205 // assertEquals(4,stringToMonthCode("APRIL"));
206 // assertEquals(5,stringToMonthCode("MAY"));
207 // assertEquals(6,stringToMonthCode("JUNE"));
208 // assertEquals(7,stringToMonthCode("JULY"));
209 // assertEquals(8,stringToMonthCode("AUGUST"));
210 // assertEquals(9,stringToMonthCode("SEPTEMBER"));
211 // assertEquals(10,stringToMonthCode("OCTOBER"));
212 // assertEquals(11,stringToMonthCode("NOVEMBER"));
213 // assertEquals(12,stringToMonthCode("DECEMBER"));
214 }
215
216 public void testIsValidWeekInMonthCode() throws Exception {
217 for (int w = 0; w <= 4; w++) {
218 assertTrue(isValidWeekInMonthCode(w));
219 }
220 assertFalse(isValidWeekInMonthCode(5));
221 }
222
223 public void testIsLeapYear() throws Exception {
224 assertFalse(isLeapYear(1900));
225 assertFalse(isLeapYear(1901));
226 assertFalse(isLeapYear(1902));
227 assertFalse(isLeapYear(1903));
228 assertTrue(isLeapYear(1904));
229 assertTrue(isLeapYear(1908));
230 assertFalse(isLeapYear(1955));
231 assertTrue(isLeapYear(1964));
232 assertTrue(isLeapYear(1980));
233 assertTrue(isLeapYear(2000));
234 assertFalse(isLeapYear(2001));
235 assertFalse(isLeapYear(2100));
236 }
237
238 public void testLeapYearCount() throws Exception {
239 assertEquals(0, leapYearCount(1900));
240 assertEquals(0, leapYearCount(1901));
241 assertEquals(0, leapYearCount(1902));
242 assertEquals(0, leapYearCount(1903));
243 assertEquals(1, leapYearCount(1904));
244 assertEquals(1, leapYearCount(1905));
245 assertEquals(1, leapYearCount(1906));
246 assertEquals(1, leapYearCount(1907));
247 assertEquals(2, leapYearCount(1908));
248 assertEquals(24, leapYearCount(1999));
249 assertEquals(25, leapYearCount(2001));
250 assertEquals(49, leapYearCount(2101));
251 assertEquals(73, leapYearCount(2201));
Listing B-4 (continued)
BobsSerialDateTest.java
378 Appendix B: org.jfree.date.SerialDate
252 assertEquals(97, leapYearCount(2301));
253 assertEquals(122, leapYearCount(2401));
254 }
255
256 public void testLastDayOfMonth() throws Exception {
257 assertEquals(31, lastDayOfMonth(JANUARY, 1901));
258 assertEquals(28, lastDayOfMonth(FEBRUARY, 1901));
259 assertEquals(31, lastDayOfMonth(MARCH, 1901));
260 assertEquals(30, lastDayOfMonth(APRIL, 1901));
261 assertEquals(31, lastDayOfMonth(MAY, 1901));
262 assertEquals(30, lastDayOfMonth(JUNE, 1901));
263 assertEquals(31, lastDayOfMonth(JULY, 1901));
264 assertEquals(31, lastDayOfMonth(AUGUST, 1901));
265 assertEquals(30, lastDayOfMonth(SEPTEMBER, 1901));
266 assertEquals(31, lastDayOfMonth(OCTOBER, 1901));
267 assertEquals(30, lastDayOfMonth(NOVEMBER, 1901));
268 assertEquals(31, lastDayOfMonth(DECEMBER, 1901));
269 assertEquals(29, lastDayOfMonth(FEBRUARY, 1904));
270 }
271
272 public void testAddDays() throws Exception {
273 SerialDate newYears = d(1, JANUARY, 1900);
274 assertEquals(d(2, JANUARY, 1900), addDays(1, newYears));
275 assertEquals(d(1, FEBRUARY, 1900), addDays(31, newYears));
276 assertEquals(d(1, JANUARY, 1901), addDays(365, newYears));
277 assertEquals(d(31, DECEMBER, 1904), addDays(5 * 365, newYears));
278 }
279
280 private static SpreadsheetDate d(int day, int month, int year) {return new
SpreadsheetDate(day, month, year);}
281
282 public void testAddMonths() throws Exception {
283 assertEquals(d(1, FEBRUARY, 1900), addMonths(1, d(1, JANUARY, 1900)));
284 assertEquals(d(28, FEBRUARY, 1900), addMonths(1, d(31, JANUARY, 1900)));
285 assertEquals(d(28, FEBRUARY, 1900), addMonths(1, d(30, JANUARY, 1900)));
286 assertEquals(d(28, FEBRUARY, 1900), addMonths(1, d(29, JANUARY, 1900)));
287 assertEquals(d(28, FEBRUARY, 1900), addMonths(1, d(28, JANUARY, 1900)));
288 assertEquals(d(27, FEBRUARY, 1900), addMonths(1, d(27, JANUARY, 1900)));
289
290 assertEquals(d(30, JUNE, 1900), addMonths(5, d(31, JANUARY, 1900)));
291 assertEquals(d(30, JUNE, 1901), addMonths(17, d(31, JANUARY, 1900)));
292
293 assertEquals(d(29, FEBRUARY, 1904), addMonths(49, d(31, JANUARY, 1900)));
294
295 }
296
297 public void testAddYears() throws Exception {
298 assertEquals(d(1, JANUARY, 1901), addYears(1, d(1, JANUARY, 1900)));
299 assertEquals(d(28, FEBRUARY, 1905), addYears(1, d(29, FEBRUARY, 1904)));
300 assertEquals(d(28, FEBRUARY, 1905), addYears(1, d(28, FEBRUARY, 1904)));
301 assertEquals(d(28, FEBRUARY, 1904), addYears(1, d(28, FEBRUARY, 1903)));
302 }
303
304 public void testGetPreviousDayOfWeek() throws Exception {
305 assertEquals(d(24, FEBRUARY, 2006), getPreviousDayOfWeek(FRIDAY, d(1, MARCH, 2006)));
306 assertEquals(d(22, FEBRUARY, 2006), getPreviousDayOfWeek(WEDNESDAY, d(1, MARCH, 2006)));
307 assertEquals(d(29, FEBRUARY, 2004), getPreviousDayOfWeek(SUNDAY, d(3, MARCH, 2004)));
308 assertEquals(d(29, DECEMBER, 2004), getPreviousDayOfWeek(WEDNESDAY, d(5, JANUARY, 2005)));
309
310 try {
311 getPreviousDayOfWeek(-1, d(1, JANUARY, 2006));
312 fail("Invalid day of week code should throw exception");
Listing B-4 (continued)
BobsSerialDateTest.java
Appendix B: org.jfree.date.SerialDate 379
313 } catch (IllegalArgumentException e) {
314 }
315 }
316
317 public void testGetFollowingDayOfWeek() throws Exception {
318 // assertEquals(d(1, JANUARY, 2005),getFollowingDayOfWeek(SATURDAY, d(25, DECEMBER, 2004)));
319 assertEquals(d(1, JANUARY, 2005), getFollowingDayOfWeek(SATURDAY, d(26, DECEMBER, 2004)));
320 assertEquals(d(3, MARCH, 2004), getFollowingDayOfWeek(WEDNESDAY, d(28, FEBRUARY, 2004)));
321
322 try {
323 getFollowingDayOfWeek(-1, d(1, JANUARY, 2006));
324 fail("Invalid day of week code should throw exception");
325 } catch (IllegalArgumentException e) {
326 }
327 }
328
329 public void testGetNearestDayOfWeek() throws Exception {
330 assertEquals(d(16, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(16, APRIL, 2006)));
331 assertEquals(d(16, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(17, APRIL, 2006)));
332 assertEquals(d(16, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(18, APRIL, 2006)));
333 assertEquals(d(16, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(19, APRIL, 2006)));
334 assertEquals(d(23, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(20, APRIL, 2006)));
335 assertEquals(d(23, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(21, APRIL, 2006)));
336 assertEquals(d(23, APRIL, 2006), getNearestDayOfWeek(SUNDAY, d(22, APRIL, 2006)));
337
338 //todo assertEquals(d(17, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(16, APRIL, 2006)));
339 assertEquals(d(17, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(17, APRIL, 2006)));
340 assertEquals(d(17, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(18, APRIL, 2006)));
341 assertEquals(d(17, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(19, APRIL, 2006)));
342 assertEquals(d(17, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(20, APRIL, 2006)));
343 assertEquals(d(24, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(21, APRIL, 2006)));
344 assertEquals(d(24, APRIL, 2006), getNearestDayOfWeek(MONDAY, d(22, APRIL, 2006)));
345
346 // assertEquals(d(18, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(16, APRIL, 2006)));
347 // assertEquals(d(18, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(17, APRIL, 2006)));
348 assertEquals(d(18, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(18, APRIL, 2006)));
349 assertEquals(d(18, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(19, APRIL, 2006)));
350 assertEquals(d(18, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(20, APRIL, 2006)));
351 assertEquals(d(18, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(21, APRIL, 2006)));
352 assertEquals(d(25, APRIL, 2006), getNearestDayOfWeek(TUESDAY, d(22, APRIL, 2006)));
353
354 // assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(16, APRIL, 2006)));
355 // assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(17, APRIL, 2006)));
356 // assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(18, APRIL, 2006)));
357 assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(19, APRIL, 2006)));
358 assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(20, APRIL, 2006)));
359 assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(21, APRIL, 2006)));
360 assertEquals(d(19, APRIL, 2006), getNearestDayOfWeek(WEDNESDAY, d(22, APRIL, 2006)));
361
362 // assertEquals(d(13, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(16, APRIL, 2006)));
363 // assertEquals(d(20, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(17, APRIL, 2006)));
364 // assertEquals(d(20, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(18, APRIL, 2006)));
365 // assertEquals(d(20, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(19, APRIL, 2006)));
366 assertEquals(d(20, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(20, APRIL, 2006)));
367 assertEquals(d(20, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(21, APRIL, 2006)));
368 assertEquals(d(20, APRIL, 2006), getNearestDayOfWeek(THURSDAY, d(22, APRIL, 2006)));
369
370 // assertEquals(d(14, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(16, APRIL, 2006)));
371 // assertEquals(d(14, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(17, APRIL, 2006)));
372 // assertEquals(d(21, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(18, APRIL, 2006)));
373 // assertEquals(d(21, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(19, APRIL, 2006)));
374 // assertEquals(d(21, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(20, APRIL, 2006)));
Listing B-4 (continued)
BobsSerialDateTest.java
380 Appendix B: org.jfree.date.SerialDate
375 assertEquals(d(21, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(21, APRIL, 2006)));
376 assertEquals(d(21, APRIL, 2006), getNearestDayOfWeek(FRIDAY, d(22, APRIL, 2006)));
377
378 // assertEquals(d(15, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(16, APRIL, 2006)));
379 // assertEquals(d(15, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(17, APRIL, 2006)));
380 // assertEquals(d(15, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(18, APRIL, 2006)));
381 // assertEquals(d(22, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(19, APRIL, 2006)));
382 // assertEquals(d(22, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(20, APRIL, 2006)));
383 // assertEquals(d(22, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(21, APRIL, 2006)));
384 assertEquals(d(22, APRIL, 2006), getNearestDayOfWeek(SATURDAY, d(22, APRIL, 2006)));
385
386 try {
387 getNearestDayOfWeek(-1, d(1, JANUARY, 2006));
388 fail("Invalid day of week code should throw exception");
389 } catch (IllegalArgumentException e) {
390 }
391 }
392
393 public void testEndOfCurrentMonth() throws Exception {
394 SerialDate d = SerialDate.createInstance(2);
395 assertEquals(d(31, JANUARY, 2006), d.getEndOfCurrentMonth(d(1, JANUARY, 2006)));
396 assertEquals(d(28, FEBRUARY, 2006), d.getEndOfCurrentMonth(d(1, FEBRUARY, 2006)));
397 assertEquals(d(31, MARCH, 2006), d.getEndOfCurrentMonth(d(1, MARCH, 2006)));
398 assertEquals(d(30, APRIL, 2006), d.getEndOfCurrentMonth(d(1, APRIL, 2006)));
399 assertEquals(d(31, MAY, 2006), d.getEndOfCurrentMonth(d(1, MAY, 2006)));
400 assertEquals(d(30, JUNE, 2006), d.getEndOfCurrentMonth(d(1, JUNE, 2006)));
401 assertEquals(d(31, JULY, 2006), d.getEndOfCurrentMonth(d(1, JULY, 2006)));
402 assertEquals(d(31, AUGUST, 2006), d.getEndOfCurrentMonth(d(1, AUGUST, 2006)));
403 assertEquals(d(30, SEPTEMBER, 2006), d.getEndOfCurrentMonth(d(1, SEPTEMBER, 2006)));
404 assertEquals(d(31, OCTOBER, 2006), d.getEndOfCurrentMonth(d(1, OCTOBER, 2006)));
405 assertEquals(d(30, NOVEMBER, 2006), d.getEndOfCurrentMonth(d(1, NOVEMBER, 2006)));
406 assertEquals(d(31, DECEMBER, 2006), d.getEndOfCurrentMonth(d(1, DECEMBER, 2006)));
407 assertEquals(d(29, FEBRUARY, 2008), d.getEndOfCurrentMonth(d(1, FEBRUARY, 2008)));
408 }
409
410 public void testWeekInMonthToString() throws Exception {
411 assertEquals("First",weekInMonthToString(FIRST_WEEK_IN_MONTH));
412 assertEquals("Second",weekInMonthToString(SECOND_WEEK_IN_MONTH));
413 assertEquals("Third",weekInMonthToString(THIRD_WEEK_IN_MONTH));
414 assertEquals("Fourth",weekInMonthToString(FOURTH_WEEK_IN_MONTH));
415 assertEquals("Last",weekInMonthToString(LAST_WEEK_IN_MONTH));
416
417 //todo try {
418 // weekInMonthToString(-1);
419 // fail("Invalid week code should throw exception");
420 // } catch (IllegalArgumentException e) {
421 // }
422 }
423
424 public void testRelativeToString() throws Exception {
425 assertEquals("Preceding",relativeToString(PRECEDING));
426 assertEquals("Nearest",relativeToString(NEAREST));
427 assertEquals("Following",relativeToString(FOLLOWING));
428
429 //todo try {
430 // relativeToString(-1000);
431 // fail("Invalid relative code should throw exception");
432 // } catch (IllegalArgumentException e) {
433 // }
434 }
435
Listing B-4 (continued)
BobsSerialDateTest.java
Appendix B: org.jfree.date.SerialDate 381
436 public void testCreateInstanceFromDDMMYYY() throws Exception {
437 SerialDate date = createInstance(1, JANUARY, 1900);
438 assertEquals(1,date.getDayOfMonth());
439 assertEquals(JANUARY,date.getMonth());
440 assertEquals(1900,date.getYYYY());
441 assertEquals(2,date.toSerial());
442 }
443
444 public void testCreateInstanceFromSerial() throws Exception {
445 assertEquals(d(1, JANUARY, 1900),createInstance(2));
446 assertEquals(d(1, JANUARY, 1901), createInstance(367));
447 }
448
449 public void testCreateInstanceFromJavaDate() throws Exception {
450 assertEquals(d(1, JANUARY, 1900),
createInstance(new GregorianCalendar(1900,0,1).getTime()));
451 assertEquals(d(1, JANUARY, 2006),
createInstance(new GregorianCalendar(2006,0,1).getTime()));
452 }
453
454 public static void main(String[] args) {
455 junit.textui.TestRunner.run(BobsSerialDateTest.class);
456 }
457 }
Listing B-4 (continued)
BobsSerialDateTest.java
382 Appendix B: org.jfree.date.SerialDate
Listing B-5
SpreadsheetDate.java
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 * SpreadsheetDate.java
29 * --------------------
30 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
31 *
32 * Original Author: David Gilbert (for Object Refinery Limited);
33 * Contributor(s): -;
34 *
35 * $Id: SpreadsheetDate.java,v 1.8 2005/11/03 09:25:39 mungady Exp $
36 *
37 * Changes
38 * -------
39 * 11-Oct-2001 : Version 1 (DG);
40 * 05-Nov-2001 : Added getDescription() and setDescription() methods (DG);
41 * 12-Nov-2001 : Changed name from ExcelDate.java to SpreadsheetDate.java (DG);
42 * Fixed a bug in calculating day, month and year from serial
43 * number (DG);
44 * 24-Jan-2002 : Fixed a bug in calculating the serial number from the day,
45 * month and year. Thanks to Trevor Hills for the report (DG);
46 * 29-May-2002 : Added equals(Object) method (SourceForge ID 558850) (DG);
47 * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
48 * 13-Mar-2003 : Implemented Serializable (DG);
49 * 04-Sep-2003 : Completed isInRange() methods (DG);
50 * 05-Sep-2003 : Implemented Comparable (DG);
51 * 21-Oct-2003 : Added hashCode() method (DG);
52 *
53 */
54
55 package org.jfree.date;
56
57 import java.util.Calendar;
58 import java.util.Date;
59
60 /**
61 * Represents a date using an integer, in a similar fashion to the
62 * implementation in Microsoft Excel. The range of dates supported is
Appendix B: org.jfree.date.SerialDate 383
63 * 1-Jan-1900 to 31-Dec-9999.
64 * <P>
65 * Be aware that there is a deliberate bug in Excel that recognises the year
66 * 1900 as a leap year when in fact it is not a leap year. You can find more
67 * information on the Microsoft website in article Q181370:
68 * <P>
69 * http://support.microsoft.com/support/kb/articles/Q181/3/70.asp
70 * <P>
71 * Excel uses the convention that 1-Jan-1900 = 1. This class uses the
72 * convention 1-Jan-1900 = 2.
73 * The result is that the day number in this class will be different to the
74 * Excel figure for January and February 1900...but then Excel adds in an extra
75 * day (29-Feb-1900 which does not actually exist!) and from that point forward
76 * the day numbers will match.
77 *
78 * @author David Gilbert
79 */
80 public class SpreadsheetDate extends SerialDate {
81
82 /** For serialization. */
83 private static final long serialVersionUID = -2039586705374454461L;
84
85 /**
86 * The day number (1-Jan-1900 = 2, 2-Jan-1900 = 3, ..., 31-Dec-9999 =
87 * 2958465).
88 */
89 private int serial;
90
91 /** The day of the month (1 to 28, 29, 30 or 31 depending on the month). */
92 private int day;
93
94 /** The month of the year (1 to 12). */
95 private int month;
96
97 /** The year (1900 to 9999). */
98 private int year;
99
100 /** An optional description for the date. */
101 private String description;
102
103 /**
104 * Creates a new date instance.
105 *
106 * @param day the day (in the range 1 to 28/29/30/31).
107 * @param month the month (in the range 1 to 12).
108 * @param year the year (in the range 1900 to 9999).
109 */
110 public SpreadsheetDate(final int day, final int month, final int year) {
111
112 if ((year >= 1900) && (year <= 9999)) {
113 this.year = year;
114 }
115 else {
116 throw new IllegalArgumentException(
117 "The 'year' argument must be in range 1900 to 9999."
118 );
119 }
120
121 if ((month >= MonthConstants.JANUARY)
122 && (month <= MonthConstants.DECEMBER)) {
123 this.month = month;
124 }
Listing B-5 (continued)
SpreadsheetDate.java
384 Appendix B: org.jfree.date.SerialDate
125 else {
126 throw new IllegalArgumentException(
127 "The 'month' argument must be in the range 1 to 12."
128 );
129 }
130
131 if ((day >= 1) && (day <= SerialDate.lastDayOfMonth(month, year))) {
132 this.day = day;
133 }
134 else {
135 throw new IllegalArgumentException("Invalid 'day' argument.");
136 }
137
138 // the serial number needs to be synchronised with the day-month-year...
139 this.serial = calcSerial(day, month, year);
140
141 this.description = null;
142
143 }
144
145 /**
146 * Standard constructor - creates a new date object representing the
147 * specified day number (which should be in the range 2 to 2958465.
148 *
149 * @param serial the serial number for the day (range: 2 to 2958465).
150 */
151 public SpreadsheetDate(final int serial) {
152
153 if ((serial >= SERIAL_LOWER_BOUND) && (serial <= SERIAL_UPPER_BOUND)) {
154 this.serial = serial;
155 }
156 else {
157 throw new IllegalArgumentException(
158 "SpreadsheetDate: Serial must be in range 2 to 2958465.");
159 }
160
161 // the day-month-year needs to be synchronised with the serial number...
162 calcDayMonthYear();
163
164 }
165
166 /**
167 * Returns the description that is attached to the date. It is not
168 * required that a date have a description, but for some applications it
169 * is useful.
170 *
171 * @return The description that is attached to the date.
172 */
173 public String getDescription() {
174 return this.description;
175 }
176
177 /**
178 * Sets the description for the date.
179 *
180 * @param description the description for this date (<code>null</code>
181 * permitted).
182 */
183 public void setDescription(final String description) {
184 this.description = description;
185 }
186
Listing B-5 (continued)
SpreadsheetDate.java
Appendix B: org.jfree.date.SerialDate 385
187 /**
188 * Returns the serial number for the date, where 1 January 1900 = 2
189 * (this corresponds, almost, to the numbering system used in Microsoft
190 * Excel for Windows and Lotus 1-2-3).
191 *
192 * @return The serial number of this date.
193 */
194 public int toSerial() {
195 return this.serial;
196 }
197
198 /**
199 * Returns a <code>java.util.Date</code> equivalent to this date.
200 *
201 * @return The date.
202 */
203 public Date toDate() {
204 final Calendar calendar = Calendar.getInstance();
205 calendar.set(getYYYY(), getMonth() - 1, getDayOfMonth(), 0, 0, 0);
206 return calendar.getTime();
207 }
208
209 /**
210 * Returns the year (assume a valid range of 1900 to 9999).
211 *
212 * @return The year.
213 */
214 public int getYYYY() {
215 return this.year;
216 }
217
218 /**
219 * Returns the month (January = 1, February = 2, March = 3).
220 *
221 * @return The month of the year.
222 */
223 public int getMonth() {
224 return this.month;
225 }
226
227 /**
228 * Returns the day of the month.
229 *
230 * @return The day of the month.
231 */
232 public int getDayOfMonth() {
233 return this.day;
234 }
235
236 /**
237 * Returns a code representing the day of the week.
238 * <P>
239 * The codes are defined in the {@link SerialDate} class as:
240 * <code>SUNDAY</code>, <code>MONDAY</code>, <code>TUESDAY</code>,
241 * <code>WEDNESDAY</code>, <code>THURSDAY</code>, <code>FRIDAY</code>, and
242 * <code>SATURDAY</code>.
243 *
244 * @return A code representing the day of the week.
245 */
246 public int getDayOfWeek() {
247 return (this.serial + 6) % 7 + 1;
248 }
Listing B-5 (continued)
SpreadsheetDate.java
386 Appendix B: org.jfree.date.SerialDate
249
250 /**
251 * Tests the equality of this date with an arbitrary object.
252 * <P>
253 * This method will return true ONLY if the object is an instance of the
254 * {@link SerialDate} base class, and it represents the same day as this
255 * {@link SpreadsheetDate}.
256 *
257 * @param object the object to compare (<code>null</code> permitted).
258 *
259 * @return A boolean.
260 */
261 public boolean equals(final Object object) {
262
263 if (object instanceof SerialDate) {
264 final SerialDate s = (SerialDate) object;
265 return (s.toSerial() == this.toSerial());
266 }
267 else {
268 return false;
269 }
270
271 }
272
273 /**
274 * Returns a hash code for this object instance.
275 *
276 * @return A hash code.
277 */
278 public int hashCode() {
279 return toSerial();
280 }
281
282 /**
283 * Returns the difference (in days) between this date and the specified
284 * 'other' date.
285 *
286 * @param other the date being compared to.
287 *
288 * @return The difference (in days) between this date and the specified
289 * 'other' date.
290 */
291 public int compare(final SerialDate other) {
292 return this.serial - other.toSerial();
293 }
294
295 /**
296 * Implements the method required by the Comparable interface.
297 *
298 * @param other the other object (usually another SerialDate).
299 *
300 * @return A negative integer, zero, or a positive integer as this object
301 * is less than, equal to, or greater than the specified object.
302 */
303 public int compareTo(final Object other) {
304 return compare((SerialDate) other);
305 }
306
307 /**
308 * Returns true if this SerialDate represents the same date as the
309 * specified SerialDate.
310 *
Listing B-5 (continued)
SpreadsheetDate.java
Appendix B: org.jfree.date.SerialDate 387
311 * @param other the date being compared to.
312 *
313 * @return <code>true</code> if this SerialDate represents the same date as
314 * the specified SerialDate.
315 */
316 public boolean isOn(final SerialDate other) {
317 return (this.serial == other.toSerial());
318 }
319
320 /**
321 * Returns true if this SerialDate represents an earlier date compared to
322 * the specified SerialDate.
323 *
324 * @param other the date being compared to.
325 *
326 * @return <code>true</code> if this SerialDate represents an earlier date
327 * compared to the specified SerialDate.
328 */
329 public boolean isBefore(final SerialDate other) {
330 return (this.serial < other.toSerial());
331 }
332
333 /**
334 * Returns true if this SerialDate represents the same date as the
335 * specified SerialDate.
336 *
337 * @param other the date being compared to.
338 *
339 * @return <code>true</code> if this SerialDate represents the same date
340 * as the specified SerialDate.
341 */
342 public boolean isOnOrBefore(final SerialDate other) {
343 return (this.serial <= other.toSerial());
344 }
345
346 /**
347 * Returns true if this SerialDate represents the same date as the
348 * specified SerialDate.
349 *
350 * @param other the date being compared to.
351 *
352 * @return <code>true</code> if this SerialDate represents the same date
353 * as the specified SerialDate.
354 */
355 public boolean isAfter(final SerialDate other) {
356 return (this.serial > other.toSerial());
357 }
358
359 /**
360 * Returns true if this SerialDate represents the same date as the
361 * specified SerialDate.
362 *
363 * @param other the date being compared to.
364 *
365 * @return <code>true</code> if this SerialDate represents the same date as
366 * the specified SerialDate.
367 */
368 public boolean isOnOrAfter(final SerialDate other) {
369 return (this.serial >= other.toSerial());
370 }
371
372 /**
373 * Returns <code>true</code> if this {@link SerialDate} is within the
Listing B-5 (continued)
SpreadsheetDate.java
388 Appendix B: org.jfree.date.SerialDate
374 * specified range (INCLUSIVE). The date order of d1 and d2 is not
375 * important.
376 *
377 * @param d1 a boundary date for the range.
378 * @param d2 the other boundary date for the range.
379 *
380 * @return A boolean.
381 */
382 public boolean isInRange(final SerialDate d1, final SerialDate d2) {
383 return isInRange(d1, d2, SerialDate.INCLUDE_BOTH);
384 }
385
386 /**
387 * Returns true if this SerialDate is within the specified range (caller
388 * specifies whether or not the end-points are included). The order of d1
389 * and d2 is not important.
390 *
391 * @param d1 one boundary date for the range.
392 * @param d2 a second boundary date for the range.
393 * @param include a code that controls whether or not the start and end
394 * dates are included in the range.
395 *
396 * @return <code>true</code> if this SerialDate is within the specified
397 * range.
398 */
399 public boolean isInRange(final SerialDate d1, final SerialDate d2,
400 final int include) {
401 final int s1 = d1.toSerial();
402 final int s2 = d2.toSerial();
403 final int start = Math.min(s1, s2);
404 final int end = Math.max(s1, s2);
405
406 final int s = toSerial();
407 if (include == SerialDate.INCLUDE_BOTH) {
408 return (s >= start && s <= end);
409 }
410 else if (include == SerialDate.INCLUDE_FIRST) {
411 return (s >= start && s < end);
412 }
413 else if (include == SerialDate.INCLUDE_SECOND) {
414 return (s > start && s <= end);
415 }
416 else {
417 return (s > start && s < end);
418 }
419 }
420
421 /**
422 * Calculate the serial number from the day, month and year.
423 * <P>
424 * 1-Jan-1900 = 2.
425 *
426 * @param d the day.
427 * @param m the month.
428 * @param y the year.
429 *
430 * @return the serial number from the day, month and year.
431 */
432 private int calcSerial(final int d, final int m, final int y) {
433 final int yy = ((y - 1900) * 365) + SerialDate.leapYearCount(y - 1);
434 int mm = SerialDate.AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH[m];
435 if (m > MonthConstants.FEBRUARY) {
Listing B-5 (continued)
SpreadsheetDate.java
Appendix B: org.jfree.date.SerialDate 389
436 if (SerialDate.isLeapYear(y)) {
437 mm = mm + 1;
438 }
439 }
440 final int dd = d;
441 return yy + mm + dd + 1;
442 }
443
444 /**
445 * Calculate the day, month and year from the serial number.
446 */
447 private void calcDayMonthYear() {
448
449 // get the year from the serial date
450 final int days = this.serial - SERIAL_LOWER_BOUND;
451 // overestimated because we ignored leap days
452 final int overestimatedYYYY = 1900 + (days / 365);
453 final int leaps = SerialDate.leapYearCount(overestimatedYYYY);
454 final int nonleapdays = days - leaps;
455 // underestimated because we overestimated years
456 int underestimatedYYYY = 1900 + (nonleapdays / 365);
457
458 if (underestimatedYYYY == overestimatedYYYY) {
459 this.year = underestimatedYYYY;
460 }
461 else {
462 int ss1 = calcSerial(1, 1, underestimatedYYYY);
463 while (ss1 <= this.serial) {
464 underestimatedYYYY = underestimatedYYYY + 1;
465 ss1 = calcSerial(1, 1, underestimatedYYYY);
466 }
467 this.year = underestimatedYYYY - 1;
468 }
469
470 final int ss2 = calcSerial(1, 1, this.year);
471
472 int[] daysToEndOfPrecedingMonth
473 = AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH;
474
475 if (isLeapYear(this.year)) {
476 daysToEndOfPrecedingMonth
477 = LEAP_YEAR_AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH;
478 }
479
480 // get the month from the serial date
481 int mm = 1;
482 int sss = ss2 + daysToEndOfPrecedingMonth[mm] - 1;
483 while (sss < this.serial) {
484 mm = mm + 1;
485 sss = ss2 + daysToEndOfPrecedingMonth[mm] - 1;
486 }
487 this.month = mm - 1;
488
489 // what's left is d(+1);
490 this.day = this.serial - ss2
491 - daysToEndOfPrecedingMonth[this.month] + 1;
492
493 }
494
495 }
Listing B-5 (continued)
SpreadsheetDate.java
390 Appendix B: org.jfree.date.SerialDate
Listing B-6
RelativeDayOfWeekRule.java
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 * RelativeDayOfWeekRule.java
29 * --------------------------
30 * (C) Copyright 2000-2003, by Object Refinery Limited and Contributors.
31 *
32 * Original Author: David Gilbert (for Object Refinery Limited);
33 * Contributor(s): -;
34 *
35 * $Id: RelativeDayOfWeekRule.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 * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
41 *
42 */
43
44 package org.jfree.date;
45
46 /**
47 * An annual date rule that returns a date for each year based on (a) a
48 * reference rule; (b) a day of the week; and (c) a selection parameter
49 * (SerialDate.PRECEDING, SerialDate.NEAREST, SerialDate.FOLLOWING).
50 * <P>
51 * For example, Good Friday can be specified as 'the Friday PRECEDING Easter
52 * Sunday'.
53 *
54 * @author David Gilbert
55 */
56 public class RelativeDayOfWeekRule extends AnnualDateRule {
57
58 /** A reference to the annual date rule on which this rule is based. */
59 private AnnualDateRule subrule;
60
61 /**
62 * The day of the week (SerialDate.MONDAY, SerialDate.TUESDAY, and so on).
Appendix B: org.jfree.date.SerialDate 391
63 */
64 private int dayOfWeek;
65
66 /** Specifies which day of the week (PRECEDING, NEAREST or FOLLOWING). */
67 private int relative;
68
69 /**
70 * Default constructor - builds a rule for the Monday following 1 January.
71 */
72 public RelativeDayOfWeekRule() {
73 this(new DayAndMonthRule(), SerialDate.MONDAY, SerialDate.FOLLOWING);
74 }
75
76 /**
77 * Standard constructor - builds rule based on the supplied sub-rule.
78 *
79 * @param subrule the rule that determines the reference date.
80 * @param dayOfWeek the day-of-the-week relative to the reference date.
81 * @param relative indicates *which* day-of-the-week (preceding, nearest
82 * or following).
83 */
84 public RelativeDayOfWeekRule(final AnnualDateRule subrule,
85 final int dayOfWeek, final int relative) {
86 this.subrule = subrule;
87 this.dayOfWeek = dayOfWeek;
88 this.relative = relative;
89 }
90
91 /**
92 * Returns the sub-rule (also called the reference rule).
93 *
94 * @return The annual date rule that determines the reference date for this
95 * rule.
96 */
97 public AnnualDateRule getSubrule() {
98 return this.subrule;
99 }
100
101 /**
102 * Sets the sub-rule.
103 *
104 * @param subrule the annual date rule that determines the reference date
105 * for this rule.
106 */
107 public void setSubrule(final AnnualDateRule subrule) {
108 this.subrule = subrule;
109 }
110
111 /**
112 * Returns the day-of-the-week for this rule.
113 *
114 * @return the day-of-the-week for this rule.
115 */
116 public int getDayOfWeek() {
117 return this.dayOfWeek;
118 }
119
120 /**
121 * Sets the day-of-the-week for this rule.
122 *
123 * @param dayOfWeek the day-of-the-week (SerialDate.MONDAY,
124 * SerialDate.TUESDAY, and so on).
Listing B-6 (continued)
RelativeDayOfWeekRule.java
392 Appendix B: org.jfree.date.SerialDate
125 */
126 public void setDayOfWeek(final int dayOfWeek) {
127 this.dayOfWeek = dayOfWeek;
128 }
129
130 /**
131 * Returns the 'relative' attribute, that determines *which*
132 * day-of-the-week we are interested in (SerialDate.PRECEDING,
133 * SerialDate.NEAREST or SerialDate.FOLLOWING).
134 *
135 * @return The 'relative' attribute.
136 */
137 public int getRelative() {
138 return this.relative;
139 }
140
141 /**
142 * Sets the 'relative' attribute (SerialDate.PRECEDING, SerialDate.NEAREST,
143 * SerialDate.FOLLOWING).
144 *
145 * @param relative determines *which* day-of-the-week is selected by this
146 * rule.
147 */
148 public void setRelative(final int relative) {
149 this.relative = relative;
150 }
151
152 /**
153 * Creates a clone of this rule.
154 *
155 * @return a clone of this rule.
156 *
157 * @throws CloneNotSupportedException this should never happen.
158 */
159 public Object clone() throws CloneNotSupportedException {
160 final RelativeDayOfWeekRule duplicate
161 = (RelativeDayOfWeekRule) super.clone();
162 duplicate.subrule = (AnnualDateRule) duplicate.getSubrule().clone();
163 return duplicate;
164 }
165
166 /**
167 * Returns the date generated by this rule, for the specified year.
168 *
169 * @param year the year (1900 <= year <= 9999).
170 *
171 * @return The date generated by the rule for the given year (possibly
172 * <code>null</code>).
173 */
174 public SerialDate getDate(final int year) {
175
176 // check argument...
177 if ((year < SerialDate.MINIMUM_YEAR_SUPPORTED)
178 || (year > SerialDate.MAXIMUM_YEAR_SUPPORTED)) {
179 throw new IllegalArgumentException(
180 "RelativeDayOfWeekRule.getDate(): year outside valid range.");
181 }
182
183 // calculate the date...
184 SerialDate result = null;
185 final SerialDate base = this.subrule.getDate(year);
186
Listing B-6 (continued)
RelativeDayOfWeekRule.java
Appendix B: org.jfree.date.SerialDate 393
187 if (base != null) {
188 switch (this.relative) {
189 case(SerialDate.PRECEDING):
190 result = SerialDate.getPreviousDayOfWeek(this.dayOfWeek,
191 base);
192 break;
193 case(SerialDate.NEAREST):
194 result = SerialDate.getNearestDayOfWeek(this.dayOfWeek,
195 base);
196 break;
197 case(SerialDate.FOLLOWING):
198 result = SerialDate.getFollowingDayOfWeek(this.dayOfWeek,
199 base);
200 break;
201 default:
202 break;
203 }
204 }
205 return result;
206
207 }
208
209 }
Listing B-6 (continued)
RelativeDayOfWeekRule.java
394 Appendix B: org.jfree.date.SerialDate
Listing B-7
DayDate.java (Final)
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.
...
36 */
37 package org.jfree.date;
38
39 import java.io.Serializable;
40 import java.util.*;
41
42 /**
43 * An abstract class that represents immutable dates with a precision of
44 * one day. The implementation will map each date to an integer that
45 * represents an ordinal number of days from some fixed origin.
46 *
47 * Why not just use java.util.Date? We will, when it makes sense. At times,
48 * java.util.Date can be *too* precise - it represents an instant in time,
49 * accurate to 1/1000th of a second (with the date itself depending on the
50 * time-zone). Sometimes we just want to represent a particular day (e.g. 21
51 * January 2015) without concerning ourselves about the time of day, or the
52 * time-zone, or anything else. That's what we've defined DayDate for.
53 *
54 * Use DayDateFactory.makeDate to create an instance.
55 *
56 * @author David Gilbert
57 * @author Robert C. Martin did a lot of refactoring.
58 */
59
60 public abstract class DayDate implements Comparable, Serializable {
61 public abstract int getOrdinalDay();
62 public abstract int getYear();
63 public abstract Month getMonth();
64 public abstract int getDayOfMonth();
65
66 protected abstract Day getDayOfWeekForOrdinalZero();
67
68 public DayDate plusDays(int days) {
69 return DayDateFactory.makeDate(getOrdinalDay() + days);
70 }
71
72 public DayDate plusMonths(int months) {
73 int thisMonthAsOrdinal = getMonth().toInt() - Month.JANUARY.toInt();
74 int thisMonthAndYearAsOrdinal = 12 * getYear() + thisMonthAsOrdinal;
75 int resultMonthAndYearAsOrdinal = thisMonthAndYearAsOrdinal + months;
76 int resultYear = resultMonthAndYearAsOrdinal / 12;
77 int resultMonthAsOrdinal = resultMonthAndYearAsOrdinal % 12 + Month.JANUARY.toInt();
78 Month resultMonth = Month.fromInt(resultMonthAsOrdinal);
79 int resultDay = correctLastDayOfMonth(getDayOfMonth(), resultMonth, resultYear);
80 return DayDateFactory.makeDate(resultDay, resultMonth, resultYear);
81 }
82
83 public DayDate plusYears(int years) {
84 int resultYear = getYear() + years;
85 int resultDay = correctLastDayOfMonth(getDayOfMonth(), getMonth(), resultYear);
86 return DayDateFactory.makeDate(resultDay, getMonth(), resultYear);
87 }
88
89 private int correctLastDayOfMonth(int day, Month month, int year) {
90 int lastDayOfMonth = DateUtil.lastDayOfMonth(month, year);
91 if (day > lastDayOfMonth)
Appendix B: org.jfree.date.SerialDate 395
92 day = lastDayOfMonth;
93 return day;
94 }
95
96 public DayDate getPreviousDayOfWeek(Day targetDayOfWeek) {
97 int offsetToTarget = targetDayOfWeek.toInt() - getDayOfWeek().toInt();
98 if (offsetToTarget >= 0)
99 offsetToTarget -= 7;
100 return plusDays(offsetToTarget);
101 }
102
103 public DayDate getFollowingDayOfWeek(Day targetDayOfWeek) {
104 int offsetToTarget = targetDayOfWeek.toInt() - getDayOfWeek().toInt();
105 if (offsetToTarget <= 0)
106 offsetToTarget += 7;
107 return plusDays(offsetToTarget);
108 }
109
110 public DayDate getNearestDayOfWeek(Day targetDayOfWeek) {
111 int offsetToThisWeeksTarget = targetDayOfWeek.toInt() - getDayOfWeek().toInt();
112 int offsetToFutureTarget = (offsetToThisWeeksTarget + 7) % 7;
113 int offsetToPreviousTarget = offsetToFutureTarget - 7;
114
115 if (offsetToFutureTarget > 3)
116 return plusDays(offsetToPreviousTarget);
117 else
118 return plusDays(offsetToFutureTarget);
119 }
120
121 public DayDate getEndOfMonth() {
122 Month month = getMonth();
123 int year = getYear();
124 int lastDay = DateUtil.lastDayOfMonth(month, year);
125 return DayDateFactory.makeDate(lastDay, month, year);
126 }
127
128 public Date toDate() {
129 final Calendar calendar = Calendar.getInstance();
130 int ordinalMonth = getMonth().toInt() - Month.JANUARY.toInt();
131 calendar.set(getYear(), ordinalMonth, getDayOfMonth(), 0, 0, 0);
132 return calendar.getTime();
133 }
134
135 public String toString() {
136 return String.format("%02d-%s-%d", getDayOfMonth(), getMonth(), getYear());
137 }
138
139 public Day getDayOfWeek() {
140 Day startingDay = getDayOfWeekForOrdinalZero();
141 int startingOffset = startingDay.toInt() - Day.SUNDAY.toInt();
142 int ordinalOfDayOfWeek = (getOrdinalDay() + startingOffset) % 7;
143 return Day.fromInt(ordinalOfDayOfWeek + Day.SUNDAY.toInt());
144 }
145
146 public int daysSince(DayDate date) {
147 return getOrdinalDay() - date.getOrdinalDay();
148 }
149
150 public boolean isOn(DayDate other) {
151 return getOrdinalDay() == other.getOrdinalDay();
152 }
153
Listing B-7 (continued)
DayDate.java (Final)
396 Appendix B: org.jfree.date.SerialDate
154 public boolean isBefore(DayDate other) {
155 return getOrdinalDay() < other.getOrdinalDay();
156 }
157
158 public boolean isOnOrBefore(DayDate other) {
159 return getOrdinalDay() <= other.getOrdinalDay();
160 }
161
162 public boolean isAfter(DayDate other) {
163 return getOrdinalDay() > other.getOrdinalDay();
164 }
165
166 public boolean isOnOrAfter(DayDate other) {
167 return getOrdinalDay() >= other.getOrdinalDay();
168 }
169
170 public boolean isInRange(DayDate d1, DayDate d2) {
171 return isInRange(d1, d2, DateInterval.CLOSED);
172 }
173
174 public boolean isInRange(DayDate d1, DayDate d2, DateInterval interval) {
175 int left = Math.min(d1.getOrdinalDay(), d2.getOrdinalDay());
176 int right = Math.max(d1.getOrdinalDay(), d2.getOrdinalDay());
177 return interval.isIn(getOrdinalDay(), left, right);
178 }
179 }
Listing B-7 (continued)
DayDate.java (Final)
Appendix B: org.jfree.date.SerialDate 397
Listing B-8
Month.java (Final)
1 package org.jfree.date;
2
3 import java.text.DateFormatSymbols;
4
5 public enum Month {
6 JANUARY(1), FEBRUARY(2), MARCH(3),
7 APRIL(4), MAY(5), JUNE(6),
8 JULY(7), AUGUST(8), SEPTEMBER(9),
9 OCTOBER(10),NOVEMBER(11),DECEMBER(12);
10 private static DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();
11 private static final int[] LAST_DAY_OF_MONTH =
12 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
13
14 private int index;
15
16 Month(int index) {
17 this.index = index;
18 }
19
20 public static Month fromInt(int monthIndex) {
21 for (Month m : Month.values()) {
22 if (m.index == monthIndex)
23 return m;
24 }
25 throw new IllegalArgumentException("Invalid month index " + monthIndex);
26 }
27
28 public int lastDay() {
29 return LAST_DAY_OF_MONTH[index];
30 }
31
32 public int quarter() {
33 return 1 + (index - 1) / 3;
34 }
35
36 public String toString() {
37 return dateFormatSymbols.getMonths()[index - 1];
38 }
39
40 public String toShortString() {
41 return dateFormatSymbols.getShortMonths()[index - 1];
42 }
43
44 public static Month parse(String s) {
45 s = s.trim();
46 for (Month m : Month.values())
47 if (m.matches(s))
48 return m;
49
50 try {
51 return fromInt(Integer.parseInt(s));
52 }
53 catch (NumberFormatException e) {}
54 throw new IllegalArgumentException("Invalid month " + s);
55 }
56
57 private boolean matches(String s) {
58 return s.equalsIgnoreCase(toString()) ||
59 s.equalsIgnoreCase(toShortString());
60 }
61
62 public int toInt() {
63 return index;
64 }
65 }
398 Appendix B: org.jfree.date.SerialDate
Listing B-9
Day.java (Final)
1 package org.jfree.date;
2
3 import java.util.Calendar;
4 import java.text.DateFormatSymbols;
5
6 public enum Day {
7 MONDAY(Calendar.MONDAY),
8 TUESDAY(Calendar.TUESDAY),
9 WEDNESDAY(Calendar.WEDNESDAY),
10 THURSDAY(Calendar.THURSDAY),
11 FRIDAY(Calendar.FRIDAY),
12 SATURDAY(Calendar.SATURDAY),
13 SUNDAY(Calendar.SUNDAY);
14
15 private final int index;
16 private static DateFormatSymbols dateSymbols = new DateFormatSymbols();
17
18 Day(int day) {
19 index = day;
20 }
21
22 public static Day fromInt(int index) throws IllegalArgumentException {
23 for (Day d : Day.values())
24 if (d.index == index)
25 return d;
26 throw new IllegalArgumentException(
27 String.format("Illegal day index: %d.", index));
28 }
29
30 public static Day parse(String s) throws IllegalArgumentException {
31 String[] shortWeekdayNames =
32 dateSymbols.getShortWeekdays();
33 String[] weekDayNames =
34 dateSymbols.getWeekdays();
35
36 s = s.trim();
37 for (Day day : Day.values()) {
38 if (s.equalsIgnoreCase(shortWeekdayNames[day.index]) ||
39 s.equalsIgnoreCase(weekDayNames[day.index])) {
40 return day;
41 }
42 }
43 throw new IllegalArgumentException(
44 String.format("%s is not a valid weekday string", s));
45 }
46
47 public String toString() {
48 return dateSymbols.getWeekdays()[index];
49 }
50
51 public int toInt() {
52 return index;
53 }
54 }
Appendix B: org.jfree.date.SerialDate 399
Listing B-10
DateInterval.java (Final)
1 package org.jfree.date;
2
3 public enum DateInterval {
4 OPEN {
5 public boolean isIn(int d, int left, int right) {
6 return d > left && d < right;
7 }
8 },
9 CLOSED_LEFT {
10 public boolean isIn(int d, int left, int right) {
11 return d >= left && d < right;
12 }
13 },
14 CLOSED_RIGHT {
15 public boolean isIn(int d, int left, int right) {
16 return d > left && d <= right;
17 }
18 },
19 CLOSED {
20 public boolean isIn(int d, int left, int right) {
21 return d >= left && d <= right;
22 }
23 };
24
25 public abstract boolean isIn(int d, int left, int right);
26 }
400 Appendix B: org.jfree.date.SerialDate
Listing B-11
WeekInMonth.java (Final)
1 package org.jfree.date;
2
3 public enum WeekInMonth {
4 FIRST(1), SECOND(2), THIRD(3), FOURTH(4), LAST(0);
5 private final int index;
6
7 WeekInMonth(int index) {
8 this.index = index;
9 }
10
11 public int toInt() {
12 return index;
13 }
14 }
Appendix B: org.jfree.date.SerialDate 401
Listing B-12
WeekdayRange.java (Final)
1 package org.jfree.date;
2
3 public enum WeekdayRange {
4 LAST, NEAREST, NEXT
5 }
402 Appendix B: org.jfree.date.SerialDate
Listing B-13
DateUtil.java (Final)
1 package org.jfree.date;
2
3 import java.text.DateFormatSymbols;
4
5 public class DateUtil {
6 private static DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();
7
8 public static String[] getMonthNames() {
9 return dateFormatSymbols.getMonths();
10 }
11
12 public static boolean isLeapYear(int year) {
13 boolean fourth = year % 4 == 0;
14 boolean hundredth = year % 100 == 0;
15 boolean fourHundredth = year % 400 == 0;
16 return fourth && (!hundredth || fourHundredth);
17 }
18
19 public static int lastDayOfMonth(Month month, int year) {
20 if (month == Month.FEBRUARY && isLeapYear(year))
21 return month.lastDay() + 1;
22 else
23 return month.lastDay();
24 }
25
26 public static int leapYearCount(int year) {
27 int leap4 = (year - 1896) / 4;
28 int leap100 = (year - 1800) / 100;
29 int leap400 = (year - 1600) / 400;
30 return leap4 - leap100 + leap400;
31 }
32 }
Appendix B: org.jfree.date.SerialDate 403
Listing B-14
DayDateFactory.java (Final)
1 package org.jfree.date;
2
3 public abstract class DayDateFactory {
4 private static DayDateFactory factory = new SpreadsheetDateFactory();
5 public static void setInstance(DayDateFactory factory) {
6 DayDateFactory.factory = factory;
7 }
8
9 protected abstract DayDate _makeDate(int ordinal);
10 protected abstract DayDate _makeDate(int day, Month month, int year);
11 protected abstract DayDate _makeDate(int day, int month, int year);
12 protected abstract DayDate _makeDate(java.util.Date date);
13 protected abstract int _getMinimumYear();
14 protected abstract int _getMaximumYear();
15
16 public static DayDate makeDate(int ordinal) {
17 return factory._makeDate(ordinal);
18 }
19
20 public static DayDate makeDate(int day, Month month, int year) {
21 return factory._makeDate(day, month, year);
22 }
23
24 public static DayDate makeDate(int day, int month, int year) {
25 return factory._makeDate(day, month, year);
26 }
27
28 public static DayDate makeDate(java.util.Date date) {
29 return factory._makeDate(date);
30 }
31
32 public static int getMinimumYear() {
33 return factory._getMinimumYear();
34 }
35
36 public static int getMaximumYear() {
37 return factory._getMaximumYear();
38 }
39 }
404 Appendix B: org.jfree.date.SerialDate
Listing B-15
SpreadsheetDateFactory.java (Final)
1 package org.jfree.date;
2
3 import java.util.*;
4
5 public class SpreadsheetDateFactory extends DayDateFactory {
6 public DayDate _makeDate(int ordinal) {
7 return new SpreadsheetDate(ordinal);
8 }
9
10 public DayDate _makeDate(int day, Month month, int year) {
11 return new SpreadsheetDate(day, month, year);
12 }
13
14 public DayDate _makeDate(int day, int month, int year) {
15 return new SpreadsheetDate(day, month, year);
16 }
17
18 public DayDate _makeDate(Date date) {
19 final GregorianCalendar calendar = new GregorianCalendar();
20 calendar.setTime(date);
21 return new SpreadsheetDate(
22 calendar.get(Calendar.DATE),
23 Month.fromInt(calendar.get(Calendar.MONTH) + 1),
24 calendar.get(Calendar.YEAR));
25 }
26
27 protected int _getMinimumYear() {
28 return SpreadsheetDate.MINIMUM_YEAR_SUPPORTED;
29 }
30
31 protected int _getMaximumYear() {
32 return SpreadsheetDate.MAXIMUM_YEAR_SUPPORTED;
33 }
34 }
Appendix B: org.jfree.date.SerialDate 405
Listing B-16
SpreadsheetDate.java (Final)
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 *
...
52 *
53 */
54
55 package org.jfree.date;
56
57 import static org.jfree.date.Month.FEBRUARY;
58
59 import java.util.*;
60
61 /**
62 * Represents a date using an integer, in a similar fashion to the
63 * implementation in Microsoft Excel. The range of dates supported is
64 * 1-Jan-1900 to 31-Dec-9999.
65 * <p/>
66 * Be aware that there is a deliberate bug in Excel that recognises the year
67 * 1900 as a leap year when in fact it is not a leap year. You can find more
68 * information on the Microsoft website in article Q181370:
69 * <p/>
70 * http://support.microsoft.com/support/kb/articles/Q181/3/70.asp
71 * <p/>
72 * Excel uses the convention that 1-Jan-1900 = 1. This class uses the
73 * convention 1-Jan-1900 = 2.
74 * The result is that the day number in this class will be different to the
75 * Excel figure for January and February 1900...but then Excel adds in an extra
76 * day (29-Feb-1900 which does not actually exist!) and from that point forward
77 * the day numbers will match.
78 *
79 * @author David Gilbert
80 */
81 public class SpreadsheetDate extends DayDate {
82 public static final int EARLIEST_DATE_ORDINAL = 2; // 1/1/1900
83 public static final int LATEST_DATE_ORDINAL = 2958465; // 12/31/9999
84 public static final int MINIMUM_YEAR_SUPPORTED = 1900;
85 public static final int MAXIMUM_YEAR_SUPPORTED = 9999;
86 static final int[] AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH =
87 {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
88 static final int[] LEAP_YEAR_AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH =
89 {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
90
91 private int ordinalDay;
92 private int day;
93 private Month month;
94 private int year;
95
96 public SpreadsheetDate(int day, Month month, int year) {
97 if (year < MINIMUM_YEAR_SUPPORTED || year > MAXIMUM_YEAR_SUPPORTED)
98 throw new IllegalArgumentException(
99 "The 'year' argument must be in range " +
100 MINIMUM_YEAR_SUPPORTED + " to " + MAXIMUM_YEAR_SUPPORTED + ".");
101 if (day < 1 || day > DateUtil.lastDayOfMonth(month, year))
102 throw new IllegalArgumentException("Invalid 'day' argument.");
103
104 this.year = year;
105 this.month = month;
406 Appendix B: org.jfree.date.SerialDate
106 this.day = day;
107 ordinalDay = calcOrdinal(day, month, year);
108 }
109
110 public SpreadsheetDate(int day, int month, int year) {
111 this(day, Month.fromInt(month), year);
112 }
113
114 public SpreadsheetDate(int serial) {
115 if (serial < EARLIEST_DATE_ORDINAL || serial > LATEST_DATE_ORDINAL)
116 throw new IllegalArgumentException(
117 "SpreadsheetDate: Serial must be in range 2 to 2958465.");
118
119 ordinalDay = serial;
120 calcDayMonthYear();
121 }
122
123 public int getOrdinalDay() {
124 return ordinalDay;
125 }
126
127 public int getYear() {
128 return year;
129 }
130
131 public Month getMonth() {
132 return month;
133 }
134
135 public int getDayOfMonth() {
136 return day;
137 }
138
139 protected Day getDayOfWeekForOrdinalZero() {return Day.SATURDAY;}
140
141 public boolean equals(Object object) {
142 if (!(object instanceof DayDate))
143 return false;
144
145 DayDate date = (DayDate) object;
146 return date.getOrdinalDay() == getOrdinalDay();
147 }
148
149 public int hashCode() {
150 return getOrdinalDay();
151 }
152
153 public int compareTo(Object other) {
154 return daysSince((DayDate) other);
155 }
156
157 private int calcOrdinal(int day, Month month, int year) {
158 int leapDaysForYear = DateUtil.leapYearCount(year - 1);
159 int daysUpToYear = (year - MINIMUM_YEAR_SUPPORTED) * 365 + leapDaysForYear;
160 int daysUpToMonth = AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH[month.toInt()];
161 if (DateUtil.isLeapYear(year) && month.toInt() > FEBRUARY.toInt())
162 daysUpToMonth++;
163 int daysInMonth = day - 1;
164 return daysUpToYear + daysUpToMonth + daysInMonth + EARLIEST_DATE_ORDINAL;
165 }
166
Listing B-16 (continued)
SpreadsheetDate.java (Final)
Appendix B: org.jfree.date.SerialDate 407
167 private void calcDayMonthYear() {
168 int days = ordinalDay - EARLIEST_DATE_ORDINAL;
169 int overestimatedYear = MINIMUM_YEAR_SUPPORTED + days / 365;
170 int nonleapdays = days - DateUtil.leapYearCount(overestimatedYear);
171 int underestimatedYear = MINIMUM_YEAR_SUPPORTED + nonleapdays / 365;
172
173 year = huntForYearContaining(ordinalDay, underestimatedYear);
174 int firstOrdinalOfYear = firstOrdinalOfYear(year);
175 month = huntForMonthContaining(ordinalDay, firstOrdinalOfYear);
176 day = ordinalDay - firstOrdinalOfYear - daysBeforeThisMonth(month.toInt());
177 }
178
179 private Month huntForMonthContaining(int anOrdinal, int firstOrdinalOfYear) {
180 int daysIntoThisYear = anOrdinal - firstOrdinalOfYear;
181 int aMonth = 1;
182 while (daysBeforeThisMonth(aMonth) < daysIntoThisYear)
183 aMonth++;
184
185 return Month.fromInt(aMonth - 1);
186 }
187
188 private int daysBeforeThisMonth(int aMonth) {
189 if (DateUtil.isLeapYear(year))
190 return LEAP_YEAR_AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH[aMonth] - 1;
191 else
192 return AGGREGATE_DAYS_TO_END_OF_PRECEDING_MONTH[aMonth] - 1;
193 }
194
195 private int huntForYearContaining(int anOrdinalDay, int startingYear) {
196 int aYear = startingYear;
197 while (firstOrdinalOfYear(aYear) <= anOrdinalDay)
198 aYear++;
199
200 return aYear - 1;
201 }
202
203 private int firstOrdinalOfYear(int year) {
204 return calcOrdinal(1, Month.JANUARY, year);
205 }
206
207 public static DayDate createInstance(Date date) {
208 GregorianCalendar calendar = new GregorianCalendar();
209 calendar.setTime(date);
210 return new SpreadsheetDate(calendar.get(Calendar.DATE),
211 Month.fromInt(calendar.get(Calendar.MONTH) + 1),
212 calendar.get(Calendar.YEAR));
213
214 }
215 }
Listing B-16 (continued)
SpreadsheetDate.java (Final)
This page intentionally left blank
Bạn đang đọc truyện trên: Truyen247.Pro