AccruedInterestCalculator { public static double getAccruedInterest(final DayCount dayCount, final ZonedDateTime settlementDate, final ZonedDateTime[] nominalDates, final double coupon, final int paymentsPerYear, final boolean isEndOfMonthConvention, final int exDividendDays, final Calendar calendar) { Validate.notNull(dayCount, "day-count"); Validate.notNull(settlementDate, "date"); Validate.noNullElements(nominalDates, "nominalDates"); Validate.notNull(calendar, "calendar"); Validate.isTrue(paymentsPerYear > 0); Validate.isTrue(exDividendDays >= 0); final int i = Arrays.binarySearch(nominalDates, settlementDate); if (i > 0) { return 0; } final int index = -i - 2; final int length = nominalDates.length; Validate.isTrue(index >= 0, "Settlement date is before first accrual date"); Validate.isTrue(index < length, "Settlement date is after maturity date"); final double accruedInterest = getAccruedInterest(dayCount, index, length, nominalDates[index], settlementDate, nominalDates[index + 1], coupon, paymentsPerYear, isEndOfMonthConvention); ZonedDateTime exDividendDate = nominalDates[index + 1]; for (int j = 0; j < exDividendDays; j++) { while (!calendar.isWorkingDay(exDividendDate.toLocalDate())) { exDividendDate = exDividendDate.minusDays(1); } exDividendDate = exDividendDate.minusDays(1); } if (exDividendDays != 0 && exDividendDate.isBefore(settlementDate)) { return accruedInterest - coupon; } return accruedInterest; } private  AccruedInterestCalculator(); static double getAccruedInterest(final DayCount dayCount, final ZonedDateTime settlementDate, final ZonedDateTime[] nominalDates, final double coupon, final int paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final Calendar calendar); static double getAccruedInterest(final DayCount dayCount, final ZonedDateTime settlementDate, final ZonedDateTime[] nominalDates, final double coupon, final double paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final int index, final Calendar calendar); static double getAccruedInterest(final DayCount dayCount, final LocalDate settlementDate, final LocalDate[] nominalDates, final double coupon, final double paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final Calendar calendar); static double getAccruedInterest(final DayCount dayCount, final LocalDate settlementDate, final LocalDate[] nominalDates, final double coupon, final double paymentsPerYear,
      final boolean isEndOfMonthConvention, final int exDividendDays, final int index, final Calendar calendar); static double getAccruedInterest(final DayCount dayCount, final LocalDate settlementDate, final LocalDate[] nominalDates, final LocalDate[] settlementDates, final double coupon,
      final double paymentsPerYear, final boolean isEndOfMonthConvention, final int exDividendDays, final int index, final Calendar calendar); static double getAccruedInterest(final DayCount dayCount, final int index, final int length, final ZonedDateTime previousCouponDate, final ZonedDateTime date,
      final ZonedDateTime nextCouponDate, final double coupon, final double paymentsPerYear, final boolean isEndOfMonthConvention); static double getAccruedInterest(final DayCount dayCount, final int index, final int length, final LocalDate previousCouponDate, final LocalDate date,
      final LocalDate nextCouponDate, final double coupon, final double paymentsPerYear, final boolean isEndOfMonthConvention);  }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullDayCount() { getAccruedInterest(null, DATE1, SCHEDULE1, 0.2, 1, false, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullSettlementDate() { getAccruedInterest(DC1, null, SCHEDULE1, 0.04, 1, false, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullSchedule() { getAccruedInterest(DC1, DATE1, null, 0.02, 1, false, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullElementInSchedule() { getAccruedInterest(DC1, DATE1, new ZonedDateTime[] {null}, 0.02, 1, false, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNegativePaymentsPerYear() { getAccruedInterest(DC1, DATE1, SCHEDULE1, 0.02, -1, false, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testBadDate() { getAccruedInterest(DC1, DateUtils.getUTCDate(2000, 1, 1), SCHEDULE1, 0.02, 1, false, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testActActICMANormalEOM() { getAccruedInterest(new ActualActualICMANormal(), DATE1, SCHEDULE1, 0.02, 1, true, 0, CALENDAR); }
@Test(expectedExceptions = IllegalArgumentException.class) public void testNullCalendar() { getAccruedInterest(DC1, DATE1, SCHEDULE1, 0.4, 1, false, 0, null); }
@Test public void test() { assertEquals(getAccruedInterest(DC1, DATE1, SCHEDULE1, 2.25, 2, true, 0, CALENDAR), 2.25 * 0.5 * 142 / 184, EPS); assertEquals(getAccruedInterest(DC2, DATE2, SCHEDULE2, 7.75, 2, true, 0, CALENDAR), 7.75 * 0.5 * 141 / 180, EPS); }