ISO8601 Week Number Format

Introduction

The ISO8601 defines how to calculate the week number from a gregorian date. The week number is used in industry or any important organisations to manage projects and ressources. You can find more information about this format on wikipedia [1].

Update 02/12/2008: Thanks to Guido’s bug fixes. You can see a demo page using this code here

Implementation

I come up with my own implementation, as I cannot find any clean JS code and reliable code to generate the week number. The JS code is based on the algorythm defined by Rick McCarty [2].

/**  
 * Author : Thomas Rabaix  
 *  
 * return the Week Number of a gregorian date using the ISO 8601 format  
 * Algorithm from http://personal.ecu.edu/mccartyr/ISOwdALG.txt , Rick McCarty, 1999  
 *  
 * ISO 8601 specifies that Week 01 of the year is the week containing  
 * the first Thursday; Monday is Weekday 1, Sunday is Weekday 7;  
 * WeekNumber requires two digits (W01, W02, etc.; "W" is optional)  
 */  
var isoHelper = {  
    getWeekNumber: function(date) {  
        // 1. Convert input to Y M D  
        var Y = date.getFullYear();  
        var M = date.getMonth();  
        var D = date.getDay();  

        // 4. Find the DayOfYearNumber for Y M D  
        var DayOfYearNumber = isoHelper.findDayOfYearNumber(date);  

        // 5. Find the Jan1Weekday for Y (Monday=1, Sunday=7)  
        var Jan1Weekday = isoHelper.findJan1Weekday(date);  

        // 6. Find the Weekday for Y M D  
        var WeekDay = isoHelper.findDayWeek(date);  

        // 7. Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53  
        var YearNumber = Y;  
        var WeekNumber = 0;  
        if((DayOfYearNumber <= (8 - Jan1Weekday)) && (Jan1Weekday > 4)) {  
            YearNumber = Y - 1  
            if((Jan1Weekday == 5) || (Jan1Weekday == 6 && isoHelper.isLeapYear(date))) {  
                WeekNumber = 53;  
            } else {  
                WeekNumber = 52;  
            }  
        }  

        // 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1  
        if(YearNumber == Y) {  
            var I;  
            if(isoHelper.isLeapYear(date)) {  
                I = 366;  
            } else {  
                I = 365  
            }  

            if ((I - DayOfYearNumber) < (4 - WeekDay)) {  
                YearNumber = Y + 1;  
                WeekNumber = 1;  
            }  
        }  

        // 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53  
        if(YearNumber == Y) {  
            var J;  
            J = DayOfYearNumber + (7 - WeekDay) + (Jan1Weekday - 1)  
            WeekNumber = J / 7;  
            if(Jan1Weekday > 4 ) {  
                WeekNumber -= 1;  
            }  
        }  

        return WeekNumber;  
    },  
    isLeapYear: function(date) {  
       if ((Y % 4) == 0 && (Y % 100) != 0) {  
           return true;  
       }  
       if((Y % 400) == 0) {  
           return true;  
       }  
       return false;  
    },  
    findDayOfYearNumber: function(date) {  
        var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];  

        var day = date.getDate() + months[date.getMonth()];  

        if(isoHelper.isLeapYear(date) && date.getMonth() > 1) {  
            day++;  
        }  

        return day;  
    },  
    findJan1Weekday: function(date) {  
        var d = new Date(date.getFullYear(), 0, 1);  
        return isoHelper.findDayWeek(d);  
    },  
    findDayWeek: function (date) {  
        var WeekDay = date.getDay();  
        if(WeekDay == 0) {  
            WeekDay = 7;  
        }  

        return WeekDay;  
    }  
}

Usage

var startDate = new Date(); // get the current date  
var numWeek = isoHelper.getWeekNumber(startDate);  

alert(numWeek);

References