Gralliry's Blog

记录学习与生活

2026/07/09

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 年,教皇格里高利十三世采纳了医生兼天文学家阿洛伊修斯·利利乌斯的方案,进行改革:

历法 闰年规则 平均年长 误差累积
儒略历 每 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