The first thing we need to do to get JavaScript to extract the week of the year that a particular date is in is to first decide when a week starts and finishes and second to decide how we will determine which is the first week of the year. There is an ISO standard for this but before we look at how to retrieve the ISO week number, let's first consider what the alternatives are as the ISO week may not suit your particular needs and so by considering the alternatives of how to define the week number we can create code to handle any alternative (and this will also make it easier to see how the code for the ISO version is derived).

There are three generally accepted alternatives for the first of these. When the week was first created it started on Saturday and ended on Friday. The actual ordering of the names of the days of the week are based on associations with the seven "planets" known at that time (which is why the week is a fixed seven days rather than alternating between seven and eight to match the phases of the moon). Originally each of the twenty four hours of the day were named after the "planets" in order from slowest to fastest moving (apparent speed as seen from Earth) and each day then got the name based on the "planet" associated with the first hour of that day (thus jumbling the names so that they no longer appear to run from slowest to fastest unless you put back the other twenty three values in between. Some parts of the world still use this original ordering of the days of the week with Friday as the last day.

The second alternative (and the one JavaScript uses) is to have the day start on Sunday and end on Saturday. The Babylonians who invented the week held a special festival on the first day of the week (Saturday) and the Jews in exile there at the time had to come up with their own reason for making Saturday special. The way that they did this made Saturday the last day of their week and much of the world has inherited their definition of the week from the Jews.

The third alternative has the week run from Monday to Sunday. Early Christians wanting to distinguish themselves from the Jews shifted their special day of the week from the last day (Saturday) to the first day (Sunday). Some groups of Christians having overlooked that the special day was moved realigned their week to make Sunday the last day of the week so that their day of celebration is on the last day of the week (Sunday).

Regardless of the historical reasons for why the week can start on any of three days, the easiest week to use with JavaScript is the second - from Sunday to Saturday because the JavaScript getDay() method on all Dates returns a number between 0 and 6 corresponding to Sunday through Saturday respectively. So we'll start with considering this variant of the week and save the other two until afterwards.

The other thing we need to decide is how to define the first week of the year. Since the year can start on any day of the week the first week of the year will only be the first through seventh of January in one year out of seven. For the other six out of seven years we need to decide how we will handle those days preceding the first Sunday of the year.

There are a number of ways that we could handle this but let's start with the one that requires the least amount of code. We will define the days from 1st January to the first Saturday of the year (regardless of whether that contains one day or seven days) as week one and then number the weeks from there. This will give us 53 weeks in the year (or 54 in leap years starting on a Saturday) with the last week also possibly containing fewer than seven days. To get the week number when specifying it this way we simply determine the current day of the year and add he number of days that week one falls short of the seven days. We then simply divide by seven and round up to give us the week number.

Date.prototype.getWeek = function() {

var onejan = new Date(this.getFullYear(),0,1);

return Math.ceil((((this - onejan) / 86400000) + onejan.getDay()+1)/7);

}

var onejan = new Date(this.getFullYear(),0,1);

return Math.ceil((((this - onejan) / 86400000) + onejan.getDay()+1)/7);

}

That's about the simplest variant of all the different ways that we can define how to count the weeks within a year.

Let's now consider if we wanted to use one of the other alternative definitions of the week. To be able to process either of these we need to produce our own version of the getDay method that returns 0 through 6 for whichever of those other two week definitions we want to use and then substitute that method for the getDay method in our code. To do this we need to move Sunday to the appropriate day of the week. This means we have to add one if the week should start from Saturday and add six if it should start from Monday. We use modulo seven on the result to wrap those numbers greater than six back to the appropriate day of the week numbers. Note that we add rather than subtract as there is a bug in some versions of JavaScript where using the modulo operator doesn't return the correct result for negative numbers.

Date.prototype.getSDay = function() {

return (this.getDay() + 1) %7;

}

Date.prototype.getMDay = function() {

return (this.getDay() + 6) %7;

}

return (this.getDay() + 1) %7;

}

Date.prototype.getMDay = function() {

return (this.getDay() + 6) %7;

}

Using one of these two methods we can change our getWeek method to work with any of the three possible definitions for when each week starts and finishes simply by substituting a call to one of these two methods for the getDay method we use when the week starts on Sunday.

The other part of the definition of the week that we may want to change is how we define week one. In the above code we defined week two as the first complete week commencing after the 1st January. There are a range of alternative ways we could define week one, each of which involves more complicated code to work it out. In some instances (such as with the ISO definition) we might even define a part week from one year as actually being a part of a week in a different year.

The ISO standard for week numbering uses the Monday through Sunday week and defines week one as the week containing the first Thursday in January. This means that the first week will always contain at least four days from the current year. It also defines each week as being exactly seven days and effectively moves up to three days from one year into another to enforce this. So dates between the 29th and 31st December might be considered to be part of week one of the following year or dates between 1st and 3rd January might be considered to be part of the last week of the previous year. To cater for when this happens we need to retrieve not only the week number but also the year that the week belongs to.

To convert our original single getWeek method to handle the ISO standard week we need the getMDay method to retrieve the day of the week starting from Monday, we need a method to retrieve the year in which the nearest Thursday to the current date belongs, and we need to change our week number calculation to use the year of that nearest Thursday as our starting point, substitute the getMday call for getDay to realign the week to start from Monday, and if 1st January of the year the week belongs to is on Friday, Saturday, or Sunday we need to subtract a week (as in that instance that date will be the last week of the prior year).

Date.prototype.getMDay = function() {

return (this.getDay() + 6) %7;}

Date.prototype.getISOYear = function() {

var thu = new Date(this.getFullYear(), this.getMonth(), this.getDate()+3-this.getMDay());

return thu.getFullYear();}

Date.prototype.getISOWeek = function() {

var onejan = new Date(this.getISOYear(),0,1);

var wk = Math.ceil((((this - onejan) / 86400000) + onejan.getMDay()+1)/7);

if (onejan.getMDay() > 3) wk--;return wk;}

return (this.getDay() + 6) %7;}

Date.prototype.getISOYear = function() {

var thu = new Date(this.getFullYear(), this.getMonth(), this.getDate()+3-this.getMDay());

return thu.getFullYear();}

Date.prototype.getISOWeek = function() {

var onejan = new Date(this.getISOYear(),0,1);

var wk = Math.ceil((((this - onejan) / 86400000) + onejan.getMDay()+1)/7);

if (onejan.getMDay() > 3) wk--;return wk;}

*This article written by Stephen Chapman, Felgall Pty Ltd.*