Chào các bạn! Vì nhiều lý do từ nay Truyen2U chính thức đổi tên là Truyen247.Pro. Mong các bạn tiếp tục ủng hộ truy cập tên miền mới này nhé! Mãi yêu... ♥

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 &lt;= year &lt;= 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

Tags: #khoahoc