问题:设 当日 T 的日期是 公元 y 年 m 月 d 日,求 T 是 星期几? 为了方便,我们用 0 到 6 的整数表示星期,0 表示星期日,1 到 6 分别表示 星期一 到 星期六。 (注:以下解答只适用于格里高利历。) 设 T 是 星期 w,公元1年1月1日 的前一天是 Z₀,Z₀ 是 星期 w₀,T 距离 Z₀ 过了 S 天,于是有: w = (w₀ + S) mod 7 ① 其中,mod 为 (w₀ + S) 除以 7 的 余数。 而 S = D' + D 其中, D' 为 y 年 1 月 1 日 的前一天 Z 距离 Z₀ 的累积天数,D 为 T 在 y 年内的 累积天数。 显然,Z 距离 Z₀ 刚好是 过了 y - 1 年。考虑 一个平年有 365 天,再考虑闰年规定:
则 D’ = 365(y-1) + [(y-1)/4] - [(y-1)/100] + [(y-1)/400], 其中 [x] 表示 取 x 的整数部分。 注:[x + 1/2] 就是对 x 四舍五入。 当 T 为 公元2019年1月1日 时,D = 1,D‘ = 737059,查日历知道 公元2019年1月1日 是星期二,即,w = 2 带入 ① 有: 2 = (w₀ + 737059 + 1) mod 7 = (w₀ + 737058 + 1 + 1) mod 7 = (w₀ + 105294 ×7 + 2) mod 7 = (w₀ + 2) mod 7 求得: w₀ = 0 而: (365(y-1)) mod 7 = (364(y-1) + (y-1)) mod 7 = (52×7(y-1) + (y-1)) mod 7 = (y-1) mod 7 所有最终 ① 简化为: w = ((y-1) + [(y-1)/4] - [(y-1)/100] + [(y-1)/400] + D) mod 7 ② 接下来,需要计算 年内 累积天数 D。考虑平年的情况,有: 设, m 月 1日前 累积超出天数 为 P(m) 则: D = P(m) + 28 × (m - 1) + d ④ 接下来,需要求 P(m)。考虑 2 月的特殊性,将 1 月 和 2 月 挪到 12 后面 变成 13 和 14 月,于是得到: 令, 对这些点,进行线性拟合: P(x) = ax + b 使用,最小二乘法, 有: 解方程的得到: 线性拟合图形如下: 由于 2.6 = 13/5,而 P(x) 需要是整数,于是令: P(x) = [13x/5 + b'] 尝试 b' = 0.4 ,将 x = 0 到 11 带入得到序列: 0, 3, 5, 8, 10, 13, 16, 18, 21, 23, 26, 29 这和 (5) 完全一致,于是 b' = 0.4 有效,进而有: P(x) = [13 x / 5 + 0.4] = [13 (x + 4) / 5 - 13 × 4 / 5 + 0.4] = [13 (x + 4) / 5 - 10.4 + 0.4] = [13 (x + 4) / 5 - 10] 即, P(x) = [13 (x + 4) / 5] - 10 ⑥ 令, k = [(14 - m) / 12] 即,当 m 为 1, 2 月 时,k = 1,m 为其它月份时,k = 0; 又令, M = m + 12k; 即,当 m 为 1, 2 月时,M 为 13,14 月,m 为其它月份时,M = m; 于是,有: x + 4 = M + 1 于是 ⑥ 改写为: P(M) = [13 (M + 1) / 5] - 10 但这是 没有考虑 3月前累计天数的情况,根据 (3) 需要加上 3月前累计天数 3 ,于是: P(M) = [13 (M + 1) / 5] - 10 + 3 = [13 (M + 1) / 5] - 7 带入 ④ 得到: D = [13 (M + 1) / 5] - 7 + 28 × (m - 1) + d ④' 再 考虑 ② 式: w = ((y-1) + [(y-1)/4] - [(y-1)/100] + [(y-1)/400] + D) mod 7 由于 1, 2 月份 被计算为 13, 14 月,等于多算了一年,因此 需要再减去 1 年,于是,令: Y = y - k 将 ② 改写为: w = ((Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D) mod 7 ②' 分析对闰年的修正:
最终,将 ④' 带入 ②'’ 有: w = ((Y-1) + [Y/4] - [Y/100] + [Y/400] + [13 (M + 1) / 5] - 7 + 28 × (m - 1) + d) mod 7 最终得到,答案1: w = (Y + [Y/4] - [Y/100] + [Y/400] + [13 (M + 1) / 5] + d - 1) mod 7 ⑦ 上面在进行线性拟合时,也可以选取 (5) 的部分点进行拟合,例如,选取 y 值间距大于等于3 的点: 同样是最小二乘法,计算结果为: 考虑 a ≈ p / q, p = [q × 2.59 + 0.5],筛选 p 较小,|q × 2.59 - p| 也较小 (小于 0.1)的情况,写成JavaScript代码如下: 运行上面的 JavaScript 得到: ['13/5', '31/12', '44/17', '57/22', '70/27'] 第一种情况 13/5 上面已经分析过了,现在考虑 第二种情况 31/12: 令: P(x) = [31x/12 + b'] 尝试让 b' = 1/2,将 x = 0 到 11 带入得到序列: 0, 3, 5, 8, 10, 13, 16, 18, 21, 23, 26, 28 这和 (5) 相比 最后一项 28 偏小,于是尝试让 b'=2/3,将 x = 0 到 11 带入得到序列: 0, 3, 5, 8, 11, 13, 16, 18, 21, 23, 26, 29 第 4 项 11 又偏大,于是令 b' = (1/2 + 2/3) / 2 = 7/12,将 x = 0 到 11 带入得到序列: 0, 3, 5, 8, 10, 13, 16, 18, 21, 23, 26, 29 终于和 (5) 完全吻合,于是 b' = 7/12 有效,进而: P(x) = [31x / 12 + 7/12] = [31x / 12 + (7 + 2×12) / 12 - 2] = [31x / 12 + 31 / 12 - 2] = [31(x + 1) / 12] - 2 令 M' = m + 12k - 2,则 x + 1 = M',再考虑 3月前的累积天数 3,则有: P(M') = [31M'/12] - 2 + 3 = [31M'/12] + 1 于是: D = [31M'/12] + 1 + 28 × (m - 1) + d 带入 ②'’ 有: w = ((Y-1) + [Y/4] - [Y/100] + [Y/400] + [31M'/12] + 1 + 28 × (m - 1) + d) mod 7 最终得到,答案2: w = (Y + [Y/4] - [Y/100] + [Y/400] + [31M'/12] + d) mod 7 ⑦' 考虑 ⑦ 式: w = (Y + [Y/4] - [Y/100] + [Y/400] + [13 (M + 1) / 5] + d - 1) mod 7 设 Y 的世纪 为 c,Y 后两位为 Y' = Y mod 100; 在一个世纪的 100 年里,星期偏移为: (100 + [99 / 4]) mod 7 = 5 如果 世纪最后一年 是 闰年,则 星期偏移 还要 加 1,即: 6 根据上面的计算结果,由于 公元1年1月1日 的前一天是 星期 日,故 公元1年1月1日 是星期 1,进而 公元1年3月1日 是星期 4。 从 公元1年3月1日 开始 每个 世纪元年的 3月1日 星期为: 观察发现 世纪元年的 3月1日 星期序列为 每 4 年循环一次: 4, 2, 0, 5 又,因为 5 mod 7 = 5 mod 7 - 7 mod 7 = (5 - 7) mod 7 = - 2 mod 7, 循环序列可改写为: 4, 2, 0, - 2 它是一个等差数列,令 C = c - 1,则有: D' = 4 - 2(C mod 4) 但是这是 每个世纪元年的 3月1日 的 星期偏差,我们要的是 每个世纪元年的 1月1日 前一天 的 星期偏差,于是 需要减去 3(1月1日 到 3月1日 的星期偏差) + 1(1月1日前一天到1月1日的星期偏差) = 4,即, D' = 4 - 2(C mod 4) - 4 = - 2(C mod 4) 又 C mod 4 = C - 4[C/4],故: D' = - 2(C - 4[C/4]) = 8[C/4] - 2C 由于我们从 3月1日 返回 1月1日 时 移入的 星期偏差 是平年的情况,因此 D'' 作为 每个世纪元年的 1月1日 前一天 的 星期偏差 已经计算了 世纪闰年的情况,于是: Y + [Y/4] - [Y/100] + [Y/400] = D'' + Y' + [Y'/4] = 8[C/4] - 2C + Y' + [Y'/4] 进而有: w = (8[C/4] - 2C + Y' + [Y'/4] + [13 (M + 1) / 5] + d - 1) mod 7 = (7[C/4] + [C/4] - 2C + Y' + [Y'/4] + [13 (M + 1) / 5] + d - 1) mod 7 即, w = ([C/4] - 2C + Y' + [Y'/4] + [13 (M + 1) / 5] + d - 1) mod 7 ⑧ 为了方便计算,改写为: w = ([C/4] - 2C + Y' + [Y'/4] + [26 (M + 1) / 10] + d - 1) mod 7 这就是 蔡勒(Zeller)公式。 答案3:设 当日 T 的日期是 公元 y 年 m 月 d 日,则 T 的 星期数为: w = ([C/4] - 2C + Y' + [Y'/4] + [26 (M + 1) / 10] + d - 1) mod 7 其中,[] 为求整数运算,mod 为取余数运算,C 为 Y 世纪 - 1,Y' 为Y最后两位数;当 m = 1, 2 月份时,Y = y - 1, M = m + 12,当 m 为其它月份时,Y = y, M = m。 |
|