Ga direct naar


Calculate ISO 8601 week and year in javascript

calendarWednesday 22 April 2009 14:18 For one of our projects I needed to be able to calculate the current weeknumber and corresponding year of a given date... in javascript. Not really a big deal, just calculate the number of weeks between the requested date and the 1st of January that year and you're done, right? Wrong!
By Taco van den Broek

Why do we use ISO week numbering?

In our framework (including modules) we use the ISO 8601 standard for week numbering. We've chosen this standard because it is very related to western european workweeks: weeks start on monday and the first week of the year is the first week with a workday in it. Our clients are mostly businesses operating in western europe and therefore this standard is the most obvious choice.

Why this article?

Our framework is built using PHP. In PHP requesting the week and / or year number according to this standard is easy:

// Week and year number using date()
$w = date('W');
$y = date('o');

// Week and year number using strftime()
$w = strftime('%V');
$y = strftime('%G');

But in javascript no built-in methods are available to calculate these values.

ISO 8601 week numbering

This (part of the) standard primarily defines two rules:

  1. Weeks start on monday
  2. The first week of the year is the week with the first thursday of that year

An alternative to the second rule is that the first week of the year is the week with the 4th of January in it. This rule is mostly more convenient in coding.

As a result of this second rule the week with the 1st of January isn't always week number 1. Another result is that some years have 53 weeks instead of 52.

Extending the javascript Date class

To be able to get the week and year numbers in javascript we extend the Date class with two methods: getWeek() and getWeekYear().

Extending a class in javascript can be done by adding properties to the prototype object of that class. In the code below we define Date.prototype.getWeek() and Date.prototype.getYearWeek(), these new methods can be called directly on instances of the Date class:

var today = new Date();
alert("The current week number is: " + today.getWeek());

Date.getWeek()

First, take a look at the code below:

/**
* Get the ISO week date week number
*/
Date.prototype.getWeek = function () {
// Create a copy of this date object
var target = new Date(this.valueOf());

// ISO week date weeks start on monday
// so correct the day number
var dayNr = (this.getDay() + 6) % 7;

// Set the target to the thursday of this week so the
// target date is in the right year
target.setDate(target.getDate() - dayNr + 3);

// ISO 8601 states that week 1 is the week
// with january 4th in it
var jan4 = new Date(target.getFullYear(), 0, 4);

// Number of days between target date and january 4th
var dayDiff = (target - jan4) / 86400000;

// Calculate week number: Week 1 (january 4th) plus the
// number of weeks between target date and january 4th
var weekNr = 1 + Math.ceil(dayDiff / 7);

return weekNr;
}

The first thing we do is find out the difference in days between the requested date and the 4th of January that same (calendar) year. We subtract the two Date objects, which will result in a number of milliseconds, and divide that by the number of milliseconds in a day: 86400000. Since weeks always start on monday (rule #1) we are more interested in the difference in days between January 4th and the monday of the target week, so we correct this day difference. Next we convert this amount of days to weeks and add one (since it was the difference between week #1 and the target date).

This was the general part of the method, next we need to correct for the exceptions (remember that the 1st of January might be in a week of the previous year?). If the result of our method is less than 1, we know this date belongs to the last week of the previous year, simply return the result of the getWeek() method for December 31st of the previous year.

On the other hand the last few days of the year might belong to a week of the next year. Since at most 3 days can belong to the next year (remember that the first week is the week with January 4th) we only need to check this exception when the date is after December 28th. We return 1 when the monday of the requested week is after the 28th of December.

Date.getWeekYear()

That was the getWeek method, the most important one of the two. The getWeekYear() method uses getWeek() to determine what year to return.

This method is very simple, just return the calendar year except when:

  1. The requested date is in January but the getWeek() method returns 52 or 53
  2. The requested date is in December but the getWeek() method returns 1

The code below (and it's comments) speak for itself ;)

/**
* Get the ISO week date year number
*/
Date.prototype.getWeekYear = function ()
{
// Create a new date object for the thursday of this week
var target = new Date(this.valueOf());
target.setDate(target.getDate() - ((this.getDay() + 6) % 7) + 3);

return target.getFullYear();
}

So that's about all you'll need to calculate ISO 8601 year and week numbers in javascript, happy coding!


Optimisation

After reading the site from Dr J R Stockton that Rick recommended in his post I stole a simple trick to make the code a little shorter. Instead of handling the edge cases I first change the date to the thursday of the requested week so the week year number equals the calendar year. I did keep the code more verbose than Stockton did though, just so you understand what exactly happens.

Tags

«Back

Reactions on "Calculate ISO 8601 week and year in javascript"

Jim
Placed on: 04-23-2009 21:21Quote
Nice post!One can find it very useful while developing some web calender's,or designing motgage projects.
Rick
Placed on: 04-24-2009 04:05Quote
Take a look at Dr J R Stockton Merlyn pages... quite a few javascript date functions: http://www.merlyn.demon.co.uk/js-date8.htm#YWD
Takkie
Placed on: 04-24-2009 17:23Quote
Taco van den Broek
User icon
@Jim: Thanks!

@Rick: That's a nice collection indeed, little bit too much information for a blogpost though Wink I did steal some little tricks from that site though, see the optimisation at the end of my article.
Edited
Takkie has edited this message on: 04-24-2009 17:23
Jonas
Placed on: 06-07-2009 22:18Quote
Changing the target to the thursday of the current week helped move me forward quite a bit.

Unfortunatly your version doesn't quite work. Take a look at for example the 4th of Jan 2010 as your target date.

I'm not entirely sure I've grasped all the concepts but I think it works with 2009 because jan4 happens to be a thursday. I believe you need to change the jan4 reference to the thursday of the week with jan4 in it as was done with the target.

I added this and it seems to work with the limited tests I've done.
var jan4DayNr = (jan4.getDay() + 6) % 7;
jan4.setDate(jan4.getDate() - jan4DayNr + 3);

You also need to do floor instead of ceil if you do it this way.

Thanks for all the help.
Martin
Placed on: 07-13-2009 09:44Quote
@Jonas: You're right about 2010. Week 1 of that year seems to be missing!

But your solution can be quite confusing also... You're setting the variable jan4 to another date than Januray 4th. :-S
Martin
Placed on: 07-14-2009 08:57Quote
@Jonas: I guess your solution still needs a little bit of testing too. It may be right about the first week of 2010. But after week 12/2010, comes another week 12. This is the case for 2011 also...
Andre Foeken
Placed on: 08-14-2009 14:30Quote
Your forgot to Math.abs the DayDiff and use floor then
zajjar
Placed on: 01-04-2010 10:06Quote
Yes, it's true :-/ Function getWeek() gives wrong results :-/
Here is the other solution. It runs perfect for me:

http://www.merlyn.demon.co.uk/weekcalc.htm#JS

ahhhahahaha
Placed on: 01-07-2010 05:56Quote
the prototype is in here now pokemon
Ted Cowan
Placed on: 08-14-2010 23:07Quote
Is your getWeek() function now correct as shown above or does it still have bugs as some have suggested?
New post

Procurios zoekt PHP webdevelopers. Werk aan het Procurios Webplatform en klantprojecten! Zie http://www.procurios.nl/webdeveloper.


Hello!

We are employees at Procurios, a full-service webdevelopment company located in the Netherlands. We are experts at building portals, websites, intranets and extranets, based on an in-house developed framework. You can find out more about Procurios and our products, might you be interested.

This weblog is built and maintained by us. We love to share our ideas, thoughts and interests with you through our weblog. If you want to contact us, please feel free to use the contact form!

Contact us!


Showcase

  • Klantcase: Bestseller
  • Klantcase: de ChristenUnie
  • Klantcase: Evangelische Omroep
  • Klantcase: de Keurslager
  • Klantcase: New York Pizza
  • Klantcase: Verhage

Snelkoppelingen