Doomsday Algorithm — 心算任意日期是星期几
by Gralliry
你不需要手机日历。只要能做简单加减法,就能在 10 秒内心算任意日期是星期几。
Doomsday Algorithm 由英国数学家 John Conway 推广,核心思想只有一个:记住每个月的”锚点日期”(doomsday),它们都在同一天。算出那天的星期数,就能推算当月任何一天。
变量说明
| 变量 | 含义 | 示例值 |
|---|---|---|
| c | 世纪数 — 年份的前两位 | 20 |
| y | 年内年份 — 年份的后两位 | 26 |
| m | 月份 | 07 |
| d | 日期 | 09 |
For example, 2026-07-09
c = 20, y = 26, m = 07, d = 09
历法基础:儒略历与格里高利历
儒略历 (Julian)
由尤利乌斯·凯撒于公元前 45 年颁布,古罗马数学家索西琴尼设计。规则简单:每 4 年一闰,平均年长 365.25 天。
但实际回归年约为 365.2422 天,儒略历每年多出约 0.0078 天(11 分 14 秒)。每 128 年就会积攒约 1 天误差。到 16 世纪,春分日已从 3 月 21 日漂移到 3 月 11 日,影响了复活节的推算。
格里高利历 (Gregorian)
1582 年,教皇格里高利十三世采纳了医生兼天文学家阿洛伊修斯·利利乌斯的方案,进行改革:
- 删掉 10 天:1582 年 10 月 4 日(星期四)之后,直接跳到 10 月 15 日(星期五),抹平积累的误差。
- 改进闰年规则:能被 4 整除为闰年,但逢百不闰(不能被 400 整除的世纪年除外)。即:
(y % 4 == 0 && y % 100 != 0) || y % 400 == 0。 - 平均年长 365.2425 天,约 3300 年才会偏差 1 天。
| 历法 | 闰年规则 | 平均年长 | 误差累积 |
|---|---|---|---|
| 儒略历 | 每 4 年一闰 | 365.2500 天 | 约 128 年偏 1 天 |
| 格里历 | 400 年 97 闰 | 365.2425 天 | 约 3300 年偏 1 天 |
Century-Anchor
儒略历 (Julian)
Century-Anchor = 6 * c
格里高利历 (Gregorian)
Century-Anchor = [2, 0, 5, 3][c % 4]
Year-Offset
通用计算,儒略历与格里高利历均可使用,后文差异仅由 Century-Anchor 体现。
Year-Offset = y + y // 4
# 人类记法
# 00 28 56 84
# 十个一组
# 0, 1, 2, 3, 5, 6, 0, 1, 3, 4,
# 5, 6, 1, 2, 3, 4, 6, 0, 1, 2,
# 4, 5, 6, 0, 2, 3, 4, 5
Year-Offset = [
0, 1, 2, 3,
5, 6, 0, 1,
3, 4, 5, 6,
1, 2, 3, 4,
6, 0, 1, 2,
4, 5, 6, 0,
2, 3, 4, 5
][y % 28]
格里高利历 (Gregorian)
仅适用于格里高利历的替代算法,数学上等价于上方查找表,但无需预查数组。
从 y + y // 4 出发,利用带余除法拆解:
y = 12 * q + r 其中 q = y // 12, r = y % 12
y + y // 4 = 12q + r + (12q + r) // 4
= 12q + r + 3q + r // 4
= 15q + r + r // 4
= q + r + r // 4
(因为 15q ≡ q (mod 7), 15 ≡ 1 mod 7)
为简化还可以再做一次映射:
yo = y % 28
Year-Offset = yo // 12 + yo % 4 + (yo % 12) // 4
Doomsday
Doomsday = (Century-Anchor + Year-Offset) % 7
Doomsday 的值 <0..6> 映射到周日到周六。在已知当月 doomsday 日期后,利用差值可推算任意日期是星期几。
Weekday 推算
全局 doomsday 确定后,结合下表推算具体日期:
| 月份 | 平年 | 闰年 | 记忆口诀 |
|---|---|---|---|
| 1 月 | 1/3 | 1/4 | 一生一世 |
| 2 月 | 2/28 | 2/29 | 二月最后一天 |
| 3 月 | 3/14 | 3/14 | 圆周率日 |
| 4 月 | 4/4 | 4/4 | 双四 |
| 5 月 | 5/9 | 5/9 | 朝九晚五 |
| 6 月 | 6/6 | 6/6 | 双六 |
| 7 月 | 7/11 | 7/11 | 七一一 |
| 8 月 | 8/8 | 8/8 | 双八 |
| 9 月 | 9/5 | 9/5 | 朝五晚九 |
| 10 月 | 10/10 | 10/10 | 双十 |
| 11 月 | 11/7 | 11/7 | 七一一(倒) |
| 12 月 | 12/12 | 12/12 | 双十二 |
计算示例
关于
% 7:公式本身只要求最后做一次(Century-Anchor + Year-Offset) % 7。 中间提前取模利用了同余性质:(a + b) % 7 = (a % 7 + b % 7) % 7。 之所以在中间步骤就% 7,是因为 Centry-Anchor(如6 * c)或 Year-Offset(如y + y // 4)可能会比较大,提前缩小数字可以降低心算难度。如果数字小可以直接算,最后再% 7也一样。
1. 数据
2026-07-09
c = 20, y = 26, m = 7, d = 9
2026 不能被 4 整除 → 平年
2. 格里高利历 (Gregorian)
Century-Anchor = [2, 0, 5, 3][20 % 4]
= [2, 0, 5, 3][0]
= 2
Year-Offset = y + y // 4
= 26 + 6
= 32 → 32 % 7 = 4
Doomsday = (2 + 4) % 7 = 6
Doomsday = 6 → 星期六
7 月的 doomsday 日期是 7/11 → 7 月 11 日是星期六。
7 月 9 日 = 7 月 11 日 - 2
= 星期六 - 2
= 星期四
结果:2026-07-09 是星期四。
3. (对照) 儒略历 (Julian)
Century-Anchor = 6 * c = 6 * 20 = 120 → 120 % 7 = 1
Year-Offset = 4 (同上)
Doomsday = (1 + 4) % 7 = 5
Doomsday = 5 → 星期五
因儒略历每 128 年偏 1 天,到 2026 年已累积约 14 天偏差,同一日期比公历晚 1 个星期。
tags: doomsday - calendar - mental-math