公元前 1 年,按公历也是闰年。 因此,对于从公元前 1 年(或公元 0 年)12 月 31 日到某一日子的年份 Y 之间的所有整年 中的闰年数,就等于 [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400], [...]表示只取整数部分。第一项表示需要加上被 4 整除的年份数,第二项表示需要去掉 被 100 整除的年份数,第三项表示需要再加上被 400 整除的年份数。之所以 Y 要减一,这 样,我们就得到了第一个计算某一天是星期几的公式: W = (Y-1)*365 + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D. (1) 其中 D 是这个日子在这一年中的累积天数。算出来的 W 就是公元前 1 年(或公元 0 年)12 月 31 日到这一天之间的间隔日数。把 W 用 7 除,余数是几,这一天就是星期几。比如我们来 算 2004 年 5 月 1 日: W = (2004-1)*365 + [(2004-1)/4] - [(2004-1)/100] + [(2004-1)/400] + (31+29+31+30+1) = 731702, 731702 / 7 = 104528……6,余数为六,说明这一天是星期六。这和事实是符合的。 上面的公式(1)虽然很准确,但是计算出来的数字太大了,使用起来很不方便。仔 细想想,其实这个间隔天数 W 的用数仅仅是为了得到它除以 7 之后的余数。这启发我们是 不是可以简化这个 W 值,只要找一个和它余数相同的较小的数来代替,用数论上的术语 来说,就是找一个和它同余的较小的正整数,照样可以计算出准确的星期数。 显然,W 这么大的原因是因为公式中的第一项(Y-1)*365 太大了。其实, (Y-1)*365 = (Y-1) * (364+1) = (Y-1) * (7*52+1) 2 = 52 * (Y-1) * 7 + (Y-1), 这个结果的第一项是一个 7 的倍数,除以 7 余数为 0,因此(Y-1)*365 除以 7 的余数其实就 等于 Y-1 除以 7 的余数。这个关系可以表示为: (Y-1)*365 ≡ Y-1 (mod 7). 其中,≡是数论中表示同余的符号,mod 7 的意思是指在用 7 作模数(也就是除数)的情 况下≡号两边的数是同余的。因此,完全可以用(Y-1)代替(Y-1)*365,这样我们就得到 了那个著名的、也是最常见到的计算星期几的公式: W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D. (2) 这个公式虽然好用多了,但还不是最好用的公式,因为累积天数 D 的计算也比较麻 烦。是不是可以用月份数和日期直接计算呢?答案也是肯定的。我们不妨来观察一下各 个月的日数,列表如下: 月 天 表: 月 份:1 月 2 月 3 月 4 月 5 月 6 月 7 月 8 月 9 月 10 月 11 月 12 月 份:1 月 2 月 3 月 4 月 5 月 6 月 7 月 8 月 9 月 10 月 11 月 12 月 数: 31 28(29) 31 -------------------------------------------------------------------------30 31 30 31 31 30 31 30 31 如果把这个天数都减去 28(=4*7) ,不影响 W 除以 7 的余数值。这样我们就得到另一张 -----------------------------------------------------------------------剩余天数: 3 平年累积: 3 闰年累积: 3 0(1) 3 3 4 6 7 2 8 9 3 11 12 2 13 14 3 16 17 3 19 20 2 21 22 3 24 25 2 26 27 3 29 30 仔细观察的话,我们会发现除去 1 月和 2 月,3 月到 7 月这五个月的剩余天数值是 3,2,3,2, 3;8 月到 12 月这五个月的天数值也是 3,2,3,2,3,正好是一个重复。相应的累积天数中, 后一月的累积天数和前一月的累积天数之差减去 28 就是这个重复。正是因为这种规律的 存在,平年和闰年的累积天数可以用数学公式很方便地表达: ╭ d; D={ 31 + d; (当 M=1) (当 M=2) (3) (当 M≥3) ╰ [ 13 * (M+1) / 5 ] - 7 + (M-1) * 28 + d + i. 其中[...]仍表示只取整数部分;M 和 d 分别是想算的日子的月份和日数;平年 i=0,闰年 i=1。对于 M≥3 的表达式需要说明一下:[13*(M+1)/5]-7 算出来的就是上面第二个表中的 平年累积值,再加上(M-1)*28 就是想算的日子的月份之前的所有月份的总天数。这是一 个很巧妙的办法,利用取整运算来实现 3,2,3,2,3 的循环。比如,对 2004 年 5 月 1 日,有: D = [ 13 * (5+1) / 5 ] - 7 + (5-1) * 28 + 1 + 1 = 122, 这正是 5 月 1 日在 2004 年的累积天数。 假如,我们再变通一下,把 1 月和 2 月当成是上一年的“13 月”和“14 月” ,不仅仍 然符合这个公式,而且因为这样一来,闰日成了上一“年” (一共有 14 个月)的最后一 天,成了 d 的一部分,于是平闰年的影响也去掉了,公式就简化成: D = [ 13 * (M+1) / 5 ] - 7 + (M-1) * 28 + d. 上面计算星期几的公式,也就可以进一步简化成: W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + [ 13 * (M+1) / 5 ] - 7 + (M-1) * 28 + d. 因为其中的-7 和(M-1)*28 两项都可以被 7 整除,所以去掉这两项,W 除以 7 的余数不变, 公式变成: (3≤M≤14) (4) 3 W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + [ 13 * (M+1) / 5 ] + d. (5) 当然,要注意 1 月和 2 月已经被当成了上一年的 13 月和 14 月,因此在计算 1 月和 2 月的日子 的星期时,除了 M 要按 13 或 14 算,年份 Y 也要减一。比如,2004 年 1 月 1 日是星期四,用这 个公式来算,有: W = (2003-1) + [(2003-1)/4] - [(2003-1)/100] + [(2003-1)/400] + [13*(13+1)/5] +1 = 2002 + 500 - 20 + 5 + 36 + 1 = 2524; 2524 / 7 = 360……4.这和实际是一致的。 公式(5)已经是从年、月、日来算星期几的公式了,但它还不是最简练的,对于年 份的处理还有改进的方法。