20 Jan 2014

Getting a date's week number in JavaScript

JavaScript's Date object doesn't seem to have a built-in function to get the week number of a date. There are many JS libraries that do have support for this, but I needed to get the week number in an environment where including libraries is awkward (in a TiddlyWiki 5 macro, if you really want to know). So I decided to make my own function.

A search on StackOverflow revealed plenty of ways to do this, but they all seemed to use date subtractions based on the fact that a date is represented internally as the number of milliseconds since 1 January 1970. To me that fact feels like an internal implementation detail, so I don't really like to use it. Also, I don't (want to) know how things like leap seconds would influence the reliability of these subtractions. No choice then but to reinvent the wheel and come up with my own algorithm and implementation.

The ISO 8601 standard says that week 1 of a year is the first week with a Thursday in that year. Based on that, I came up with the following "algorithm":

  1. Given a date d, adapt this date to Thursday of the same week.
  2. Subtract 1 week from this date and repeat this until the result is in the previous year.
  3. The week number for date d is the number of subtractions needed in the previous step to get to the previous year.
This surely isn't the fastest way to do it, but it takes a maximum of 53 subtractions, so it does have constant time complexity. Note that it does use subtractions, so we might end up using those milliseconds again, except that subtracting days can also be done by using the fact that JavaScript's setDate function has a kind of "underflow" protection: if 0 or a negative value is passed, it adapts the date to the correct month. So we can delegate the subtractions to an internal JS function and assume that it works well.

All these considerations led me to the following JavaScript function. Please let me know if there are any flaws anywhere in the function, or in the considerations.


function getWeekNumber(date) {
  var addDays = 0, dayOfWeek = date.getDay(), 
    modifiedDate = new Date(date);
  // move to Thursday in same week as date
  if (dayOfWeek == 0) {
    addDays = -3;
  }
  else {
    addDays = 4 - dayOfWeek;
  }
  modifiedDate.setDate(modifiedDate.getDate() + addDays);
   
  // count weeks going back in time one week at a time
  // until we reach previous year
  var year = modifiedDate.getFullYear(), weekCount = 0;
  do {
    modifiedDate.setDate(modifiedDate.getDate() - 7);
    weekCount++;
  } while (modifiedDate.getFullYear() == year);
  return weekCount;
}

Note: the code assumes weeks start on Mondays. In some countries (and in JavaScript) weeks start on Sundays, so there the first if statement would not be needed.

Since we're on a web page, let's test the function:

Today we are in week

No comments:

Post a Comment