Preface

偶然做到日期相关题目,了解到Zeller公式。不甘心停留在使用阶段,便想掌握其推导过程。

只适用于格利戈里历法,也就是现今的公历。

1. Zeller公式

  • 标准形式

  • 计算1582年10月4日或之前日期 (罗马教皇决定在1582年10月4日后使用格利戈里历法)

  • w:星期; w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
  • c:世纪(注:一般情况下,在公式中取值为已经过的世纪数,也就是年份除以一百的结果,而非正在进行的世纪,也就是现在常用的年份除以一百加一;不过如果年份是公元前的年份且非整百数的话,c应该等于所在世纪的编号,如公元前253年,是公元前3世纪,c就等于-3)
  • y:年(一般情况下是后两位数,如果是公元前的年份且非整百数,y应该等于cMOD100+100)
  • m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
  • d:日
  • [ ]代表取整,即只要整数部分。

注意:编程中MOD运算 ≠ 数学中MOD的运算, 所以若D为负数,则在求W之前可对D进行7的倍数的自增运算,让其成为正数,最后对7求余得到结果。

思考: 如何将给定日期换算成星期数呢?

  1. 找已知日期(年月日,周几)作为源
  2. 计算目标日期与源的间隔天数
  3. 将间隔天对7取余获取偏移量
  4. 将源的week加上偏移量
  5. 得到目标星期数

2. 推导过程

如你所想,Zeller公式并不神秘。通过以上思想的优化和扩展后,便得到Zeller公式。

从以上思想开始扩展。

1. 如何获取间隔天数?

D = D1 + D2 + D3 

  1. D1:从原点到原点所在年份末尾的天数。
  2. D2:原点所在年份和目标日期所在年份之间所有年份的天数和。
  3. D3:目标日期所在年份的第一天到目标日期的天数。

优化:

1. 若我们把源设定为12月31日则可省去D1的计算。于是 D = D2 + D3

2. 若源点正好是周日就正好了 可以省去偏移量的计算。

巧了: 我们发现公元元年的前一年12月31日恰好是周日,这是一个完美的源。

D2:

假设目标日期是y-m-d, 我们可以很简单的得出D2

因一年至少有365天,此外,闰年比平年多一天,所以需加上闰年中多出来的天数。

闰年规则: 四年一闰, 百年不闰, 四百年闰。故:

至此:D1 D2 解决

D3:先不考虑闰年,因2月份天数28天最少,因此,我们不妨把每个月的天数看作 “28 + Excess”的模式,m 月之前所有月份的 Excess 之和为 Accum(m),则 D3=28×(m−1)+Accum(m)+d,并且我们可以得到这样一张表格:

月份表
月份 1 2 3 4 5 6 7 8 9 10 11 12
天数 31 28 31 30 31 30 31 31 30 31 30 31
Excess 3 0 3 2 3 2 3 3 2 3 2 3
Accum 0 3 3 6 8 11 13 16 19 21 24 26

通过上表可发现Excess 3 月份开始是 3、2、3、2、3 的循环,因此,当 m≥3m≥3 时,Accum(m)的值的增幅也是 3、2、3、2、3 的循环。因为每 5 个月增加 13,所以把  作为系数;因为 Accum(m) 的值是离散的(都是整数),所以我们用取整运算符,得到:

将x的取值为1,2,3... 得到表

x 4 5 6 7 8 9 10 11 12 13 14
f(x) 10 13 15 18 20 23 26 28 31 33 36

可以发现,x≥4时 增幅也是3、2、3、2、3 的循环,也就是说x≥4 f(x)== m≥3 Accum(m) 的增幅相同,这意味着他们之间只相差一个常数。代值计算:

f(4)−Accum(3)=10−3=7

得到这个常数7,由此可得,当m≥3时 Accum(m) = f(m+1) - 7 = 

但这里考虑的是m≥3,我们可以通过分段函数来列式

D3 = d (m=1)

D3 = 31 + d (m=2)

D3 = (m-1) * 28 + [13(m-1)/5] - 7 + d + i (m >= 3)

闰年i = 1 平年则 i = 0。

继续优化D3算法:

我们继续分析,从 3 月份到 12 月份的 Excess 正好是两个 3、2、3、2、3 的循环,那么假如有第 13 月,想要继续保持这种循环规律,13 月的 Excess 值应该是 3。而 1 月份的 Excess 的值恰好是 3,所以我们不妨变通一下,把每年的 1 月、2月当作上一年的 13月、14 月。这样不仅仍然符合公式,而且 2 月份变成了上一年的最后一个月,也就是公式中 dd 的部分,于是平闰年的影响也去掉了,D3 的公式简化成了:

D3=(m−1)×28+[13(m+1)5]−7+d, 3≤m≤14

由D = D2 + D3, 得

但!

注意!这个公式离正确形式还差一小步。因为在当前的公式中,每年的 1 月和 2 月被当作上一年的 13 月和 14 月计算,因此当前公式中计算闰日的部分([y−14]−[y−1100]+[y−1400])存在错误。举一个具体的例子,比如计算公元 4 年(闰年)3 月 1 日的星期数。在当前公式中,公元 4 年的 2 月被算作了公元 3 年的 14 月(换句话说公元 3 年变成了闰年),而公式中计算闰日的部分没有考虑这点,依然将公元 3 年当成平年计算,因此少算了一天。因此,计算闰日的部分应当改进,公式如下:

计算出D的值后,对7取模则可得到星期数。

根据同余定理,D 除以 7 所得的余数等于 D 式的各项分别除以 7 所得余数之和(余数之和大于等于 7 时,再对 7 取余),因此可以消去 D 式中能被 7 整除的项,进行化简:

对以上公式再次简练,对年份进行处理。通过上面公式计算出每个世纪第一年3月1日的星期数,得出下表

年份 1,401,801,..2001 101, 501, 901, … , 2101 201, 601, 1001, … , 2201 301, 701, 1101, … ,2301
星期 4 2 0 5

又发现,每隔四个世纪,星期就会重复。因为在数学上-2 和 5 除以 7 的余数相同,所以我们不妨把这个重复序列中的 5 改为 -2。这样,4、2、0、-2 恰好构成了一个等差数列。利用等差公式,我们可以得到计算每个世纪第一年的 3 月 1 日星期数的公式

W = 4 - 2 (c mod 4) // 其中c是世纪数 - 1

将此公式与上面公式联立,带入特定日期 3月1日 得出

利用同余原理 ,变换。

故此,我们可以知道在每个世纪的第一年,(y−1)+[y−1 / 4]−[y−1 / 100]+[y−1 / 400]可以被 −2(cmod4) 同余替换。进而计算 D的公式得到如下形式:

注意!现在的计算公式只能适用于每个世纪的第一年。但是,有个这个公式,再加上计算一个世纪中闰日的部分,我们就可以很容易地得到计算这个世纪其他年份的日期的星期数的公式了。令 c 等于世纪数减一,y 等于世纪中的年份数(如 1994 年,则 c = 19,y = 94)。因为一个世纪中只有一百年,所以不用考虑“四百年又闰”的情况;因为每百年,即每个世纪最后一年的 y = 00,而 [y/4](y=0)=0,所以 [y4] 既可以计算四年一闰的情况,又满足百年不闰的要求 。综合这些情况,与得到公式(2)的过程类似,我们可以得到:

c是年份的前两位-1,y是年份的后两位

最后,我们来把公式中的取模运算改成四则运算。设商为 q,余数为 r,则:

4q + r = c

又∵ q = [c/4] , r = c mod 4

所以 c mod 4  = c - 4 * [c / 4]

带入公式, 最后得出 Zeller公式

3. 例子

下面以中华人民共和国成立100周年纪念日那天(2049年10月1日)来计算是星期几,过程如下:
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
 =49+[49/4]+[20/4]-2×20+[26×(10+1)/10]+1-1
 =49+[12.25]+5-40+[28.6]
 =49+12+5-40+28
 =54 (除以7余5)
即2049年10月1日(100周年国庆)是星期五。
再比如计算2013年3月7日,过程如下:
w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1
 =13+[13/4]+[20/4]-2*20+[26*(3+1)/10]+7-1
 =-3 (除以7余4,注意对负数的取模运算!)

文章引用:

例子

推导

百度百科

蔡勒(Zeller)公式理解Get(√)相关推荐

  1. C语言——蔡勒(Zeller)公式:快速将任意日期转换为星期数

    蔡勒公式 情景引入 公式介绍 公式细节 代码实现 情景引入   在日常生活中,我们有时候会遇到这样的问题:看到一个日期想知道这一天是星期几.对于这个问题,如果用编程的方式,应该怎么实现呢?你可能已经有 ...

  2. arctanx麦克劳林公式推导过程_蔡勒(Zeller)公式及其推导:快速将任意日期转换为星期数...

    0. 本文的初衷及蔡勒公式的用处 前一段时间,我在准备北邮计算机考研复试的时候,做了几道与日期计算相关的题目,在这个过程中我接触到了蔡勒公式.先简单的介绍一下蔡勒公式是干什么用的. 我们有时候会遇到这 ...

  3. c语言根据日期算星期几入门,c语言详解  蔡勒(Zeller)公式计算某一天是星期几  极其方便...

    /* 蔡勒(Zeller)公式计算某一天是星期几 w:星期:c:(年份前两位):y:年(年份后两位):m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1.2月要看作上一年的13.14月 来计 ...

  4. c语言求某年某月1日是星期几,蔡勒(Zeller)公式:根据日期推算是星期几

    Zeller's Congruence: w=y + [y/4] + [c/4] - 2c + [26(m+1)/10] + d - 1 公式中的符号含义如下: w:星期: w对7取模得:0-星期日, ...

  5. 蔡勒公式 java,C/C++根据年月日计算星期几(蔡勒公式篇)

    蔡勒公式  蔡勒(Zeller)公式:是一个计算星期的公式. 随便给一个日期,就能用这个公式推算出是星期几. 蔡勒公式如下: W = [C/4] - 2C + y + [y/4] + [13 * (M ...

  6. 蔡勒(Zeller)公式:是一个计算星期的公式。

    蔡勒(Zeller)公式:是一个计算星期的公式. 随便给一个日期,就能用这个公式推算出是星期几. 蔡勒公式如下: W = [C/4] - 2C + y + [y/4] + [13 * (M+1) / ...

  7. 【蔡勒公式 】根据给定的年月日求出对应星期几

    蔡勒公式 蔡勒(Zeller)公式,是一个计算星期的公式,随便给一个日期,就能用这个公式推算出是星期几.时间复杂度:O(1).具体的在红书P229有. 若要计算的日期是在1582年10月4日或之前,公 ...

  8. 牛客多校第六场 G Is Today Friday? 蔡勒公式/排列

    题意: 有一堆日期,这些日期都是星期五,但是数字被映射成了字母A~J,现在让你求逆映射,如果存在多种答案,输出字典序最小的那个. 题解: 用蔡勒公式解决关于星期几的问题. 对于映射,可以用笔者刚刚学会 ...

  9. HDU 6112 今夕何夕【2017百度之星】【日期模拟计算】【基姆拉尔森计算公式】【蔡勒公式】

    今夕何夕 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

最新文章

  1. cstring 比较_属牛人和属蛇人姻缘婚配关系比较和谐
  2. Bitbucket Pipes发布,带来30+自动化CI/CD管道的方法
  3. auve子表单中只读不好用
  4. MonitorService-监控服务类2
  5. char和byte的区别
  6. win32 临界区和简单实例Demo(win32版)
  7. java 压缩jar 仓库,java服务安装(一):使用java service wrapper及maven打zip包
  8. c语言 静态链表插入排序,数据结构 - 表插入排序 具体解释 及 代码(C++)
  9. 基于HTML5的WebGL结合Box2DJS物理应用 1
  10. java统计单机次数_java流类,快速统计出字符次数+++
  11. c语言指针经典例,C语言指针应用简单实例
  12. Jenkins File Matrix 对于label设置环境变量
  13. 【C++】重定义,重载,重写
  14. Spring核心功能之控制反转(IOC)
  15. 日期相关(类与方法)
  16. Dreamweaver之简单实现网站布局、图片漂浮、区域跳转、登陆注册及图片查看器
  17. 手把手教你搭建使用NuGet私有源
  18. Vue3能用到生产环境了吗?
  19. causalml 因果推断
  20. vod系统必须要用服务器吗,流媒体VOD 需要什么样的服务器

热门文章

  1. kolla-ansible在ubuntu部署openstack
  2. 喜茶/农夫山泉/星巴克/这些成功案例,有些人仿佛已经嗅到了什么
  3. 2025年前装搭载率突破30%,资本/车企持续加码新赛道
  4. 前端页面的pdf导出(h2c,jsPDF)
  5. html 绘制气球,html – 圈子div气球
  6. 【冰爪编程】LintCode 解码大全 —— 872 终止进程
  7. 成功解决:wget下载GitHub资源慢的问题
  8. 一把油纸伞惊艳米兰城,还成淘宝神店镇店之宝
  9. 过三点的二次贝塞尔曲线及其升阶
  10. mpaas如何实现视频播放