Skip to content

Commit

Permalink
issue #8 First cut at the getNumberOfBusinessDaysBetween
Browse files Browse the repository at this point in the history
issue #8 First cut at the getNumberOfBusinessDaysBetween method.
  • Loading branch information
benoitx committed May 27, 2019
1 parent cd649bc commit 1c0281f
Show file tree
Hide file tree
Showing 12 changed files with 236 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,18 @@ public interface DateCalculator<E> extends BaseCalculator<E> {
* @param increment
*/
DateCalculator<E> setCurrentIncrement(int increment);

/**
* Number of non weekend, non holidays days between d1 and d2, using the Holiday Handler type to match
* what the method moveByBusinessDays requires.
* Note that moveByBusinessDays could give the same answer with some holiday handlers like modified forward or modified preceding;
* this getNumberOfBusinessDaysBetween should give the first (smallest) answer.
* @param d1 start date
* @param d2 end date
* @return d2 - d1 -numberOfWeekendDays - numberOfHolidays (matching what moveByBusinessDays requires)
* @since 1.4.3
*/
int getNumberOfBusinessDaysBetween(E d1, E d2);
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,11 @@ public void testMoveByTenorOvernightTwoDaysToSpot() {
checkMoveByTenor("2006-08-28", StandardTenor.OVERNIGHT, 2, "2006-08-25", HolidayHandlerType.BACKWARD);
}
*/

public void testBusinessDaysCalc() {
super.testBusinessDaysCalcBack(HolidayHandlerType.BACKWARD);
}

}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,97 @@ protected void checkMoveByTenor(final String startDate, final Tenor tenor, final
cal.setStartDate(newDate(startDate));
checkDate("Move start:" + startDate + " tenor:" + tenor, cal.moveByTenor(tenor), expectedDate);
}

/**
* Checks that the calendar moveByBusinessDays works but also that the
* getNumberOfBusinessDays matches the calculation.
* @param holidayHandlerType holiday handler e.g. Forward.
*/
protected void testBusinessDaysCalcBack(String holidayHandlerType) {
// with weekend
checkMoveAndNumberOfBusinessDays("2006-01-02", 0, "2006-01-02", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", -1, "2005-12-30", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", -4, "2005-12-27", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", -5, "2005-12-26", holidayHandlerType);
// with holidays
checkMoveAndNumberOfBusinessDays("2006-08-24", -1, "2006-08-23", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-24", -2, "2006-08-22", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-24", -5, "2006-08-17", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-28", 0, -1, "2006-08-25", holidayHandlerType); // holiday
checkMoveAndNumberOfBusinessDays("2006-08-28", -1, -2, "2006-08-24", holidayHandlerType);
}

/**
* Checks that the calendar moveByBusinessDays works but also that the
* getNumberOfBusinessDays matches the calculation.
* @param holidayHandlerType holiday handler e.g. Forward.
*/
protected void testBusinessDaysCalcBackModif(String holidayHandlerType) {
// with weekend
checkMoveAndNumberOfBusinessDays("2006-01-02", 0, "2006-01-02", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", -1, 0, "2006-01-02", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", -4, 0, "2006-01-02", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", -5, 0, "2006-01-02", holidayHandlerType);
// with holidays
checkMoveAndNumberOfBusinessDays("2006-08-24", -1, "2006-08-23", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-24", -2, "2006-08-22", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-24", -5, "2006-08-17", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-28", 0, -1, "2006-08-25", holidayHandlerType); // holiday
checkMoveAndNumberOfBusinessDays("2006-08-28", -1, -2, "2006-08-24", holidayHandlerType);
}

/**
* Checks that the calendar moveByBusinessDays works but also that the
* getNumberOfBusinessDays matches the calculation.
* @param holidayHandlerType holiday handler e.g. Forward.
*/
protected void testBusinessDaysCalc(String holidayHandlerType) {
// with weekend
checkMoveAndNumberOfBusinessDays("2006-01-02", 0, "2006-01-02", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", 1, "2006-01-03", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", 4, "2006-01-06", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-01-02", 5, "2006-01-09", holidayHandlerType);
// with holidays
checkMoveAndNumberOfBusinessDays("2006-08-24", 1, "2006-08-25", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-24", 2, "2006-08-29", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-24", 5, "2006-09-01", holidayHandlerType);
checkMoveAndNumberOfBusinessDays("2006-08-28", 0, "2006-08-29", holidayHandlerType); // holiday
checkMoveAndNumberOfBusinessDays("2006-08-28", 1, "2006-08-30", holidayHandlerType);
}

private void checkMoveAndNumberOfBusinessDays(String start, int days, String expectedDate, final String holidayHandlerType) {
final DateCalculator<E> cal = newDateCalculator("bla", holidayHandlerType);
final HolidayCalendar<E> holidays = newHolidaysCalendar();
Assert.assertEquals("Name", "bla", cal.getName());
cal.setHolidayCalendar(holidays);
Assert.assertEquals("Holidays", holidays.getHolidays(), cal.getHolidayCalendar().getHolidays());
Assert.assertEquals("Holidays size", 3, cal.getHolidayCalendar().getHolidays().size());

E startDate = newDate(start);
cal.setCurrentBusinessDate(startDate);
// E calc = cal.moveByBusinessDays(days).getCurrentBusinessDate();
checkDate("Move " + days + " BD", cal.moveByBusinessDays(days), expectedDate);

Assert.assertEquals(days, cal.getNumberOfBusinessDaysBetween(startDate, newDate(expectedDate)));
Assert.assertEquals(-days, cal.getNumberOfBusinessDaysBetween(newDate(expectedDate), startDate));
}

private void checkMoveAndNumberOfBusinessDays(String start, int days, int expectedDays, String expectedDate, final String holidayHandlerType) {
final DateCalculator<E> cal = newDateCalculator("bla", holidayHandlerType);
final HolidayCalendar<E> holidays = newHolidaysCalendar();
Assert.assertEquals("Name", "bla", cal.getName());
cal.setHolidayCalendar(holidays);
Assert.assertEquals("Holidays", holidays.getHolidays(), cal.getHolidayCalendar().getHolidays());
Assert.assertEquals("Holidays size", 3, cal.getHolidayCalendar().getHolidays().size());

E startDate = newDate(start);
cal.setCurrentBusinessDate(startDate);
// E calc = cal.moveByBusinessDays(days).getCurrentBusinessDate();
checkDate("Move " + days + " BD", cal.moveByBusinessDays(days), expectedDate);

Assert.assertEquals(expectedDays, cal.getNumberOfBusinessDaysBetween(startDate, newDate(expectedDate)));
Assert.assertEquals(-expectedDays, cal.getNumberOfBusinessDaysBetween(newDate(expectedDate), startDate));
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,15 @@ public void testMoveByBusinessDays() {
Assert.assertEquals("Holidays", holidays.getHolidays(), cal.getHolidayCalendar().getHolidays());
Assert.assertEquals("Holidays size", 3, cal.getHolidayCalendar().getHolidays().size());

cal.setStartDate(newDate("2006-08-24"));
checkDate("Move 0 BD", cal.moveByBusinessDays(0), "2006-08-24");

cal.setStartDate(newDate("2006-08-24"));
checkDate("Move 1 BD", cal.moveByBusinessDays(1), "2006-08-25");

cal.setStartDate(newDate("2006-08-24"));
checkDate("Add 1 week", cal.moveByDays(7), "2006-08-31");

cal.setStartDate(newDate("2006-08-24"));
checkDate("Move by 1W with 1 bank holiday", cal.moveByBusinessDays(7), "2006-09-05");

Expand Down Expand Up @@ -487,6 +491,10 @@ public void testCalculateTenorsTwoDaysToSpot() {
assertEquals("Move start:" + startDate + " tenor:" + tenor, expected.next(), it.next());
}
}

public void testBusinessDaysCalc() {
super.testBusinessDaysCalc(HolidayHandlerType.FORWARD);
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@ public void testCalculateTenorsTwoDaysToSpot() {
assertEquals("Move start:" + startDate + " tenor:" + tenor, expected.next(), it.next());
}
}

public void testBusinessDaysCalc() {
super.testBusinessDaysCalc(HolidayHandlerType.FORWARD_UNLESS_MOVING_BACK);
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,11 @@ public void testCalculateTenorsTwoDaysToSpot() {
assertEquals("Move start:" + startDate + " tenor:" + tenor, expected.next(), it.next());
}
}

public void testBusinessDaysCalc() {
super.testBusinessDaysCalc(HolidayHandlerType.MODIFIED_FOLLOWING);
}

}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ public void testMoveByTenorOvernightTwoDaysToSpot() {
checkMoveByTenor("2006-08-28", StandardTenor.OVERNIGHT, 2, "2006-08-25", HolidayHandlerType.MODIFIED_PRECEDING);
}
*/

public void testBusinessDaysCalc() {
super.testBusinessDaysCalcBackModif(HolidayHandlerType.MODIFIED_PRECEDING);
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public CalendarDateCalculator(final String name, final Calendar startDate, final
}
}

@Override
public DateCalculator<Calendar> setWorkingWeek(final WorkingWeek week) {
workingWeek = week;
return this;
Expand All @@ -77,6 +78,7 @@ public DateCalculator<Calendar> setWorkingWeek(final WorkingWeek week) {
/**
* is the date a non-working day according to the WorkingWeek?
*/
@Override
public boolean isWeekend(final Calendar date) {
assert workingWeek != null;
return !workingWeek.isWorkingDay(date);
Expand All @@ -90,6 +92,7 @@ public boolean isWeekend(final Calendar date) {
//
// -----------------------------------------------------------------------

@Override
public CalendarDateCalculator moveByDays(final int days) {
setCurrentIncrement(days);
getCurrentBusinessDate().add(Calendar.DAY_OF_MONTH, days);
Expand Down Expand Up @@ -158,6 +161,30 @@ protected Calendar clone(final Calendar date) {
cal.setTime(date.getTime());
return cal;
}

@Override
public int getNumberOfBusinessDaysBetween(final Calendar d1, final Calendar d2) {
if (d1 == null || d2 == null) {
return 0;
}
final boolean d1B4d2 = !d1.after(d2);
Calendar start = d1B4d2 ? d1 : d2;
final Calendar end = d1B4d2 ? d2 : d1;
if (getHolidayHandler() != null) {
start = getHolidayHandler().adjustDate(start, 1, this);
}

int count = 0;

while (start.before(end)) {
if (!isNonWorkingDay(start)) {
count++;
}
start.add(Calendar.DATE, 1);
}
return d1B4d2 ? count : -count;
}

}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public DateDateCalculator(final String name, final Date startDate, final Holiday
// -----------------------------------------------------------------------

// TODO throw an exception if the type is incorrect
@Override
public DateCalculator<Date> setWorkingWeek(final WorkingWeek week) {
delegate.setWorkingWeek(week);
return this;
Expand All @@ -94,13 +95,15 @@ public DateCalculator<Date> setWorkingWeek(final WorkingWeek week) {
/**
* is the date a non-working day according to the WorkingWeek?
*/
@Override
public boolean isWeekend(final Date date) {
if (date != null && delegate != null) {
return delegate.isWeekend(Utils.getCal(date));
}
return false;
}

@Override
public DateCalculator<Date> moveByDays(final int days) {
setCurrentIncrement(days);
delegate.setCurrentIncrement(days);
Expand Down Expand Up @@ -167,6 +170,29 @@ protected void checkBoundary(final Date date) {
protected Date clone(final Date date) {
return new Date(date.getTime());
}

@Override
public int getNumberOfBusinessDaysBetween(final Date d1, final Date d2) {
if (d1 == null || d2 == null) {
return 0;
}
final boolean d1B4d2 = !d1.after(d2);
Calendar start = Utils.getCal(d1B4d2 ? d1 : d2);
final Calendar end = Utils.getCal(d1B4d2 ? d2 : d1);
if (getHolidayHandler() != null) {
start = Utils.getCal(getHolidayHandler().adjustDate(start.getTime(), 1, this));
}

int count = 0;

while (start.before(end)) {
if (!isNonWorkingDay(start.getTime())) {
count++;
}
start.add(Calendar.DATE, 1);
}
return d1B4d2 ? count : -count;
}
}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,29 @@ protected void checkBoundary(final LocalDate date) {
protected LocalDate clone(final LocalDate date) {
return date;
}

@Override
public int getNumberOfBusinessDaysBetween(final LocalDate d1, final LocalDate d2) {
if (d1 == null || d2 == null) {
return 0;
}
final boolean d1B4d2 = !d1.isAfter(d2);
LocalDate start = d1B4d2 ? d1 : d2;
LocalDate end = d1B4d2 ? d2 : d1;
if (getHolidayHandler() != null) {
start = getHolidayHandler().adjustDate(start, 1, this);
}

int count = 0;
// start = start.plusDays(1);
while (start.isBefore(end)) {
if (!isNonWorkingDay(start)) {
count++;
}
start = start.plusDays(1);
}
return d1B4d2 ? count : -count;
}
}

/*
Expand Down

0 comments on commit 1c0281f

Please sign in to comment.