正确的坂本algorithmfind星期几

我使用Sakamoto的algorithm来查找给定date的星期几。 有人可以告诉我这个algorithm的正确性吗? 我只是想从2000年到2099年。

给出了维基百科的algorithm供参考。

int dow(int y, int m, int d) { static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; } 

那么,你可以通过查看它是正确的…假设t[]数组是正确的,你可以用12次抽查(使用任何一天/一年的每月一次)来validation。

y -= m < 3是一个很好的把戏。 它创build了一个“虚拟年”,从3月1日开始,到2月28日(或29日)结束,将额外的一天(如果有的话)放在年底 。 或者说,在去年年底。 例如,2011年3月1日开始虚拟年,2月29日结束,2012年虚拟年将从3月1日开始,到2月28日结束。

通过在虚拟年份的末尾添加闰年的附加date,其余的expression式被大量简化。

我们来看一下总和:

 (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7 

正常的一年有365天。 这是52周加1天。 所以一般来说,一周的每一天都是每天转一天。 这就是y这个词的贡献。 它每年增加一个。

但是每四年都是一个闰年。 那些每四年贡献一天。 由于使用了虚拟年份,我们可以只添加y/4来计算y年内发生了多less次闰日。 (请注意,这个公式假设整数除法。)

但这不太对,因为每一百年都不是闰年。 所以我们必须减去y/100

除了每四百年又是一个闰年。 所以我们必须添加y/400

最后,我们只是添加月份d和取决于月份的表格的偏移量(因为年份内的月份边界是相当随意的)。

然后把整个事情模7,因为这是一个星期是多久。

(例如,如果星期是八天,那么这个公式中会有什么变化?显然,这将是mod 8,同样y也需要是5*y ,因为365%8 == 5。 t[]需要调整,就是这样)。

顺便说一下,维基百科的日历“9999之前的好”是完全随意的。 无论是十年,一百年,一千年还是一百万年,这个公式对我们来说都是有好处的。

[编辑]

上述论点本质上是归纳certificate。 也就是说, 假设公式适用于特定的(y,m,d),则certificate它适用于(y + 1,m,d)和(y,m,d + 1)。 (其中y是3月1日开始的“虚拟年份”)。所以关键问题是,从一年到下一年,这个总和是否会变化正确? 在了解闰年规则的情况下,以及在年末有额外一天的“虚拟年份”,它是微不足道的。

最近我在这里写了关于这个algorithm的博客文章。

algorithm背后的基本思想是在2月份和1月份从上一年的 12月31日算起。 其他所有月份我们将从当前年度12月31日的星期几开始计算。我们先用两个步骤先计算本月前一个月的最后一天的星期几,然后再加上d模七。

31 Dec 1 BC是星期天,编码为0,星期一是1等,所以我们有: 0 + y + y/4 - y/100 + y/400这个用y -= m < 3计算星期几31当年或去年的12月(取决于月份)。 注意: 365 % 7 == 1这解释了为什么我们写的是y而不是365*y 。 最后一个组件d是明显的,因为我们从上个月的上一个星期的星期几开始计数。

最后一部分需要解释的是数值,前两个值是从去年12月31日到本月开始的天数% 7 。 在剩下的几个月中,他们将从前一个月的月末到今年的十二月31日以七天为单位进行否定 。 换句话说,我们通过加模7来减去天数,例如(ab)%7 = (a+(7-b%7))%7

你可能会在我的博客文章中find更多的解释。