Wednesday, December 11, 2013

How many Friday 13ths in a Year in JavaScript

Inspired by a code golf question on codegolf.stackexchange.com asking for code that counted the number of Friday 13ths in a year I came up with this inefficient NodeJS/JavaScript solution. Both the solutions below can be dropped into a .js file and run from the command line by NodeJS.

// To run:
// node friday13.js <2013>
// <2013> is the year which you want a count of Friday 13ths in

// Add a day incrementer to the Date prototype
Date.prototype.addDays = function (num) {
    var value = this.valueOf();
    value += 86400000 * num;
    return new Date(value);
}

var year = process.argv[2];
if(!year){
 console.log('Was year the first param? Received: ' + year);
 return;
}

var startDate = new Date(year,0,1);
console.log(startDate);

var endDate = new Date(year,11,31);
console.log(endDate);

var counter = 0;
while(startDate <= endDate) {
 if(startDate.getDay() === 5 && startDate.getDate() === 13) {
  counter++;
 }
 startDate = startDate.addDays(1);
}

console.log(counter + ' Friday 13ths in ' + year);

Someone else came up with another JavaScript solution which takes advantage of some of the idiosyncrasies of JavaScript which I thought was interesting:

var year = process.argv[2];

var numFridays = function(year) {
 var count=0;
 for(month=12;month--;) {
  count += !new Date(year,month,1).getDay();
 }
 return count;
}

console.log('Number: ' + numFridays(year));

Here are the interesting parts:
  1. The for loop on line 5 relies on the fact that when the value of month hits zero it will evaluate to false.
  2. On line 5 month will be evaluated for truthiness before it's decremented and that it will be decremented before the body of the for loop is evaluated.
  3. We only have to loop through the 12 months of the year as there can only be one Friday 13th in each month so no need to go through every day.
  4. The JavaScript getDay() method of the Date object returns a 0 for Sunday, 1 for Monday etc. If the month has a Friday 13th then by definition the first day of the month is a Sunday. i.e. if the value of getDay() on the 1st of the month is 0 (equivalent to false) then count this month. To do that we ! (not) the return value which gives us true which will evaluate as the value of 1 when added to an integer.

2 comments:

  1. The second one seems like it's trying hard to be clever. I'm not a fan of relying on side effects that could change some day nor do I like having to step through several times to understand what is happening. I changed the significant line to the following, which I think is much clearer:

    count += (new Date(year, month, 13).getDay() === 5) ? 1 : 0;

    ReplyDelete