public Date getEndOfNextNthPeriod(Date now, int numPeriods) {
    Calendar cal = this;
    cal.setTime(now);

    roundDownTime(cal, this.datePattern);

    switch (this.periodicityType) {
      case TOP_OF_MILLISECOND:
        cal.add(Calendar.MILLISECOND, numPeriods);
        break;

      case TOP_OF_SECOND:
        cal.add(Calendar.SECOND, numPeriods);
        break;

      case TOP_OF_MINUTE:
        cal.add(Calendar.MINUTE, numPeriods);
        break;

      case TOP_OF_HOUR:
        cal.add(Calendar.HOUR_OF_DAY, numPeriods);
        break;

      case TOP_OF_DAY:
        cal.add(Calendar.DATE, numPeriods);
        break;

      case TOP_OF_WEEK:
        cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
        cal.add(Calendar.WEEK_OF_YEAR, numPeriods);
        break;

      case TOP_OF_MONTH:
        cal.add(Calendar.MONTH, numPeriods);
        break;

      default:
        throw new IllegalStateException("Unknown periodicity type.");
    }

    return cal.getTime();
  }
@Test
  public void roundsDateWithMissingMonthUnits() throws ParseException {
    final Date REF_DATE = parseDate("yyyy-MM-dd HH:mm:ss.SSS", "2000-12-25 09:30:49.876");
    Calendar cal = getEndOfNextNthPeriod("yyyy-dd", REF_DATE, -1);

    assertEquals(2000, cal.get(Calendar.YEAR));
    assertEquals(Calendar.JANUARY, cal.get(Calendar.MONTH));
    assertEquals(24, cal.get(Calendar.DAY_OF_MONTH));
    assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
    assertEquals(0, cal.get(Calendar.MINUTE));
    assertEquals(0, cal.get(Calendar.SECOND));
    assertEquals(0, cal.get(Calendar.MILLISECOND));
  }