打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
如何计算星期几的简单公式?

问题:设 当日 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 天,再考虑闰年规定:

  • 普通闰年:能被 4 整除但不能被 100 整除的年份为普通闰年;

  • 世纪闰年:能被 400 整除的为世纪闰年,

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 ②'

分析对闰年的修正:

  • 当 y 是闰年, m = 1, 2 月份 时,Y = y - 1,这时无需考虑 闰年 情况,因为 当 m = 2 , d = 29 时 自然 就包括了 闰年。

  • 当 y 是闰年时, m ≥ 3 月份,则 Y= y,这时,因为, 根据 (3) ,在考虑 3月前累计天数 时,是按照 平年计算的,因此并没有考虑 Y 是是否是闰年,于是计算闰年偏差时需要附带上 Y,于是 将 ②' 继续改写为:

    w = ((Y-1) + [Y/4] - [Y/100] + [Y/400] + D) mod 7 ②'

    改写后,因为 1 的情况 Y = y-1,刚好避开了 闰年的计算,因此 1 不受 ②' 改写为 ②'’ 影响,故 ②' 对于 1 同样有效。

  • 当 y 是闰年 + 1,m = 1, 2 月份 时,Y = y - 1,这时 Y 是闰年,于是和 2 的情况相似,于是 ②' 有效。

  • 其他情况,均不受 ②' 改写为 ②'’ 影响。

最终,将 ④' 带入 ②'’ 有:

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。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
万年历设计
蔡勒Zeller公式(计算星期的方法) - jx的日志 - 网易博客
星期、干支、二十八宿计算公式
60秒轻松计算出任意一年任意一天星期几?
万年星期计算方法
三年级下数学年月日
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服