#### Algorithms for the ISO Calendar

Computer algorithms for implementing the ISO calendar can be found in the literature mentioned here and at the following websites:

The following JavaScript is valid for all Gregorian calendar years:

function gregdaynumber(year,month,day){

// computes the day number since 0 January 0 CE (Gregorian)

y=year;
m=month;
if(month < 3) y=y–1;
if(month < 3) m=m+12;
return Math.floor(365.25*y)–Math.floor(y/100)+Math.floor(y/400)+Math.floor(30.6*(m+1))+day–62;
}

function isocalendar1(){

// computes the ISO calendar date from the current Gregorian date

var today = new Date();

year=today.getFullYear();
month=today.getMonth(); // 0=January, 1=February, etc.
day=today.getDate();
wday=today.getDay();

weekday=((wday+6)%7)+1; // weekdays will be numbered 1 to 7

isoyear=year;

d0=gregdaynumber(year,1,0);
weekday0=((d0+4)%7)+1;

d=gregdaynumber(year,month+1,day);
isoweeknr=Math.floor((d–d0+weekday0+6)/7)–Math.floor((weekday0+3)/7);

// check whether the last few days of December belong to the next year's ISO week

if((month == 11) && ((day–weekday) > 27)){
isoweeknr=1;
isoyear=isoyear+1;
}

// check whether the first few days of January belong to the previous year's ISO week

if((month == 0) && ((weekday–day) > 3)){
d0=gregdaynumber(year–1,1,0);
weekday0=((d0+4)%7)+1;
isoweeknr=Math.floor((d–d0+weekday0+6)/7)–Math.floor((weekday0+3)/7);
isoyear=isoyear–1;
}

if(isoweeknr < 10) return isoyear+"–W0"+isoweeknr+"–"+weekday;
if(isoweeknr > 9) return isoyear+"–W"+isoweeknr+"–"+weekday;
}

An alternative JavaScript algorithm, based on a method suggested by John R. Stockton, is also valid for all Gregorian years:

function gregdaynumber(year,month,day){

// computes the day number since 0 January 0 CE (Gregorian)

y=year;
m=month;
if(month < 3) y=y–1;
if(month < 3) m=m+12;
return Math.floor(365.25*y)–Math.floor(y/100)+Math.floor(y/400)+Math.floor(30.6*(m+1))+day–62;
}

function isocalendardaynumber(isoyear,isoweeknr,isoweekday){

// computes the day number since 0 January 0 CE (Gregorian) from the ISO 8601 calendar date

q=Math.floor(isoyear/400);
z=isoyear–400*q;
weeksum=20871*q+52*z+Math.floor((5*z+7–4*Math.floor((z–1)/100))/28)+isoweeknr;
return 7*weeksum+isoweekday–5;
}

function isocalendar2(){

// computes the ISO calendar date from the current Gregorian date

var today = new Date();

year=today.getFullYear();
month=today.getMonth()+1; // 1=January, 2=February, etc.
day=today.getDate();

daynumber=gregdaynumber(year,month,day);

isoyear=Math.floor(daynumber/365.2425)+2;

for(var i=0;i<3;i++){
daynumber0=isocalendardaynumber(isoyear–i,1,1);
if(daynumber > daynumber0){
break;
}
}

isoyear=isoyear–i;
isoweeknr=Math.floor((daynumber–daynumber0)/7)+1;
isoweekday=(daynumber–daynumber0)–7*(isoweeknr–1)+1;

if(isoweeknr < 10) return isoyear+"–W0"+isoweeknr+"–"+isoweekday;
if(isoweeknr > 9) return isoyear+"–W"+isoweeknr+"–"+isoweekday;
}

The following Mathematica procedure, written in 2001 by Fons van Hees of the High Performance Computing Group of the Department of Physics and Astronomy of the Utrecht University, may also be useful:

<<Miscellaneous'Calendar'

WeeksInISOYear[year_]:= 52
WeeksInISOYear[year_]:= 53 /;
DayOfWeek[{year,1,1}] == Thursday ||
DayOfWeek[{year,12,31}] == Thursday

WeekOfISOYear[date_]:= Module[{year,days,startDate},
year = date[];
days = {{year–1,12,29},
{year–1,12,30},
{year–1,12,31},
{year,1,1},
{year,1,2},
{year,1,3},
{year,1,4}};
startDate = Select[days,DayOfWeek[#] == Monday &] [];
week = Ceiling[(1+DaysBetween[date,startDate])/7];
If[week > WeeksInISOYear[year],week = 1];
week]

N.B. Several Microsoft programs (such as Access 2000 and Excel 2000) support a week numbering scheme through the WEEKNUM function that can be set to number weeks starting either on Sunday or on Monday. Note that the Microsoft week numbers are not always the same as the ISO week numbers. Microsoft defines the first week in the year as the week that contains the 1st of January.