Determining the next payment renewal date
An interesting question..

I am assuming that the values of PAYMENTS_PER_YEAR can only be these:

var paymentFrequencies = [ 1 , 2 , 3 , 4 , 6 , 12 ];


If that is the case, then the renewalyear can only be todays year or tomorrows year.

I would create a cache that pre-calculates for each month and each payment frequency what the next payment month is, and whether a year will be skipped.

Then you can simply use a look up to determine when the next payment month is, there should be no faster way than that. 

I am currently looking into building just that, it is definitely possible, but slightly harder than expected ;)

This is what I have, I tested it a bit, the principal should be clear:



function createCache( monthsOffset ){
  var cache = {},
      paymentFrequencies = [ 1 , 2 , 3 , 4 , 6 , 12 ],
      todaysMonth = (new Date ()).getMonth() + monthsOffset,
      renewalYear, renewalMonth, targetMonth, frequency, monthsShort, nextYear, term;
  for( var month = 0 ; month &lt; 12 ; month++ ){
    cache[month] = {};
    for( var i = 0 ; i &lt; paymentFrequencies.length ; i++ ){
      frequency = paymentFrequencies[i];
      term = 12 / frequency;
      targetMonth = todaysMonth &lt; month ? todaysMonth + 12 : todaysMonth;
      monthsShort = ( targetMonth - month ) % term;
      cache[month][frequency] = todaysMonth + (monthsShort ? term - monthsShort : 0);
      
    }
  }
  return cache;
}

var stillThisMonth = createCache( 0 ),
    nextMonth = createCache(1);

function determineRenewalDate( startDate , paymentsPerYear  ){

    var today = new Date(),
        todaysYear =  today.getFullYear();
        startMonth =  startDate.getMonth();
  /*Compare the days, if we renew say monthly, and we start on the 15th, 
    but today is the 20, then we need to renew for next month, if we are the
    the 8th then you can stick to this month */    
  var todaysDayOfTheMonth = today.getDate(),
      startDayOfTheMonth = startDate.getDate();
  //One more cool thing, `setFullYear` and `new Date` will roll over the year if you set the month too high
  if( todaysDayOfTheMonth &gt; startDayOfTheMonth  ){
     return new Date( todaysYear, nextMonth[startMonth][paymentsPerYear], startDayOfTheMonth );
  } else {
     return new Date( todaysYear, stillThisMonth[startMonth][paymentsPerYear], startDayOfTheMonth );
  }    
}


document.write(  determineRenewalDate( new Date(2010 , 1 , 1 ) , 12 ) + '&lt;br&gt;' );
document.write(  determineRenewalDate( new Date(2010 , 1 , 2 ) , 2 ) + '&lt;br&gt;' );