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 testVaryingNumberOfHourlyPeriods() {
    RollingCalendar rc = new RollingCalendar("yyyy-MM-dd_HH");

    long MILLIS_IN_HOUR = 3600 * 1000;

    for (int p = 100; p > -100; p--) {
      long now = 1223325293589L; // Mon Oct 06 22:34:53 CEST 2008
      Date result = rc.getEndOfNextNthPeriod(new Date(now), p);
      long expected = now - (now % (MILLIS_IN_HOUR)) + p * MILLIS_IN_HOUR;
      assertEquals(expected, result.getTime());
    }
  }