Sakamoto algorithm to calculate day of week
If year is non-negative:
Sakamoto algorithm implementation in C++: 0 = sunday, 1 = monday, ..., 6 = saturday.
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
int dow(int y, int m, int d) {
y -= m<3;
return (d + t[m-1] + y + y/4 - y/100 + y/400) % 7;
}
In Javascript:
// m = 1, 2, ..., 12
// result: 0 = sun, 1 = mon, ..., 6 = sat
function dayOfWeek(y, m, d) {
if (m<3) y--
m = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4][m-1]
return (d + m + y + ~~(y/4) - ~~(y/100) + ~~(y/400)) % 7
}
In javascript: ~
is bitwise not operator. Double bitwise not (~~
) is equivalent to Math.trunc()
.
Testing script for all days from year 0 to year 3000:
for (let x = 0; x < 3000 * 365; x ++) {
const d = new Date((x - 1970 * 365) * 24 * 60 * 60 * 1000)
if ( d.getDay() !== dayOfWeek(d.getFullYear(), d.getMonth() + 1, d.getDate())) {
console.log('wrong', d, d.getFullYear(), d.getMonth(), d.getDate(), d.getDay(), dayOfWeek(d.getFullYear(), d.getMonth() + 1, d.getDate()))
break
}
}
If year can be negative:
- The division must be floor, not truncate
- And, the last modulo operator must be normalized to be non-negative
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
int dow_full(int y, int m, int d) {
double z = m < 3 ? y - 1 : y;
return ((d + t[m-1] + (int)z + (int)floor(z/4) - (int)floor(z/100) + (int)floor(z/400)) % 7 + 7) % 7;
}
function dayOfWeekFull(y, m, d) {
if (m<3) y--
m = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4][m-1]
return ((d + m + y + Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400)) % 7 + 7) % 7
}
Testing script which tests all days from year -3000 to year 3000:
for (let x = -3000; x < 3000 * 365; x ++) {
const d = new Date((x - 1970 * 365) * 24 * 60 * 60 * 1000)
if ( d.getDay() !== dayOfWeekFull(d.getFullYear(), d.getMonth() + 1, d.getDate())) {
console.log('wrong', d, d.getFullYear(), d.getMonth(), d.getDate(), d.getDay(), dayOfWeek(d.dayOfWeekFull(), d.getMonth() + 1, d.getDate()))
break
}
}