2006-07-27 - 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

Comments

comments powered by Disqus