版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、计算给定日期星期几好象是编程都会遇到的问题,最近论坛里也有人提到这个问题,并给出了一个公式:W= (d+2*m+3*(m+1/5+y+y/4-y/100+y/400 mod 7(要求将1、2月当作上一年的13、14月来计算其讲述的过程并不清楚,便想怎样自己推导出一个公式来,花了几个小时,总算是弄出来了,结果跟上面的公式一样:=下面我们完全按自己的思路由简单到复杂一步步进行推导推导之前,先作两项规定:用 y, m, d, w 分别表示 年 月 日 星期(w=0-6 代表星期日-星期六 我们从 公元0年1月1日星期日 开始一、只考虑最开始的 7 天,即 d = 1-7 变换到 w = 0-6很直观
2、的得到:w = d-1二、扩展到整个1月份模7的概念大家都知道了,也没什么好多说的。不过也可以从我们平常用的日历中看出来,在周历里边每列都是一个按7增长的等差数列,如1、8、15、22的星期都是相同的。所以得到整个1月的公式如下:w = (d-1 % 7 - 公式三、按年扩展由于按月扩展比较麻烦,所以将年扩展放在前面说 我们不考虑闰年,假设每一年都是 365 天。由于365是7的52倍多1天,所以每一年的第一天和最后一天星期是相同的。也就是说下一年的第一天与上一年的第一天星期滞后一天。这是个重要的结论,每过一年,公式会有一天的误差,由于我们是从0年开始的,所以只须要简单的加上年就可以修正扩展年
3、引起的误差,得到公式如下:w = (d-1 + y % 7 将闰年考虑进去每个闰年会多出一天,会使后面的年份产生一天的误差。如我们要计算2005年1月1日星期几,就要考虑前面的已经过的2004年中有多少个闰年,将这个误差加上就可以正确的计算了。根据闰年的定义(能被4整但不能被100整除或能被400整 ,得到计算闰年的个数的算式:y/4 - y/100 + y/400。由于我们要计算的是当前要计算的年之前的闰年数,所以要将年减1,得到了如下的公式:w = d-1+y + (y-1/4-(y-1/100+(y-1/400 % 7 -公式现在,我们得到了按年扩展的公式,用这个公式可以计算任一年的1月
4、份的星期四、扩展到其它月考虑这个问题颇费了一翻脑筋,后来还是按前面的方法大胆假才找到突破口。现在我们假设每个月都是28天,且不考虑闰年有了这个假设,计算星期就太简单了,因为28正好是7的整数倍,每个月的星期都是一样的,公式对任一个月都适用 :但假设终究是假设,首先1月就不是28天,这将会造成2月份的计算误差。1月份比28天要多出3天,就是说公式的基础上,2月份的星期应该推后3天。而对3月份来说,推后也是3天(2月正好28天,对3月的计算没有影响 。依此类推,每个月的计算要将前面几个月的累计误差加上。要注意的是误差只影响后面月的计算,因为12月已是最后一个月,所以不用考虑12月的误差天数,同理,
5、1月份的误差天数是0,因为前面没有月份影响它。由此,想到建立一个误差表来修正每个月的计算。=月 误差 累计 模71 3 0 02 0 3 33 3 3 34 2 6 65 3 8 16 2 11 47 3 13 68 3 16 29 2 19 510 3 21 011 2 24 312 - 26 5(闰年时2月会有一天的误差,但我们现在不考虑=我们将最后的误差表用一个数组存放在公式的基础上可以得到扩展到其它月的公式e = 0,3,3,6,1,4,6,2,5,0,3,5w = d-1+y + em-1 + (y-1/4-(y-1/100+(y-1/400 % 7 -公式上面的误差表我们没有考虑闰
6、年,如果是闰年,2月会一天的误差,会对后面的3-12月的计算产生影响,对此,我们暂时在编程时来修正这种情况,增加的限定条件是如果当年是闰年,且计算的月在2月以后,需要加上一天的误差。大概代码是这样的:w = (d-1 + y + em-1 + (y-1/4 - (y-1/100 + (y-1/400; if(m>2 && (y%4=0 && y%100!=0 | y%400=0 && y!=0+w;w %= 7;现在,已经可以正确的计算任一天的星期了。注意:0年不是闰年,虽然现在大都不用这个条件,但我们因从公元0年开始计算,所以这个条件是不
7、能少的。 改进公式中,计算闰年数的子项 (y-1/4-(y-1/100+(y-1/400 没有包含当年,如果将当年包含进去,则实现了如果当年是闰年,w 自动加1。由此带来的影响是如果当年是闰年,1,2月份的计算会多一天误差,我们同样在编程时修正。则代码如下w = (d-1 + y + em-1 + y/4 - y/100 + y/400; - 公式 if(m<3 && (y%4=0 && y%100!=0 | y%400=0 && y!=0-w;w %= 7;与前一段代码相比,我们简化了 w 的计算部分。实际上还可以进一步将常数 -1 合并
8、到误差表中,但我们暂时先不这样做。至此,我们得到了一个阶段性的算法,可以计算任一天的星期了。public class Week public static void main(String argsint y = 2005;int m = 4;int d = 25;int e = new int0,3,3,6,1,4,6,2,5,0,3,5;int w = (d-1+em-1+y+(y>>2-y/100+y/400;if(m<3 && (y&3=0 && y%100!=0 | y%400=0 && y!=0 -w;w %
9、= 7;五、简化现在我们推导出了自己的计算星期的算法了,但还不能称之为公式。所谓公式,应该给定年月日后可以手工算出星期几的,但我们现在的算法需要记住一个误差表才能进行计算,所以只能称为一种算法,还不是公式。下面,我们试图消掉这个误差表=消除闰年判断的条件表达式=由于闰年在2月份产生的误差,影响的是后面的月份计算。如果2月是排在一年的最后的话,它就不能对其它月份的计算产生影响了。可能已经有人联想到了文章开头的公式中为什么1,2月转换为上年的13,14月计算了吧 :就是这个思想了,我们也将1,2月当作上一年的13,14月来看待。由此会产生两个问题需要解决:1>一年的第一天是3月1日了,我们要
10、对 w 的计算公式重新推导2>误差表也发生了变化,需要得新计算推导 w 计算式1> 用前面的算法算出 0年3月1日是星期3前7天, d = 1-7 => w = 3-2得到 w = (d+2 % 7此式同样适用于整个三月份2> 扩展到每一年的三月份d + 2 + y + (y-1/4 - (y-1/100 + (y-1/400 % 7误差表=月 误差 累计 模73 3 0 04 2 3 35 3 5 56 2 8 17 3 10 38 3 13 69 2 16 210 3 18 411 2 21 012 3 23 213 3 26 514 - 29 1=得到扩展到其它月
11、的公式e = 0,3,5,1,3,6,2,4,0,2,5,1w = d+2 + em-3 +y+(y-1/4-(y-1/100+(y-1/400 % 7(3 <= m <= 14我们还是将 y-1 的式子进行简化w = d+2 + em-3 +y+y/4-y/100+y/400 % 7(3 <= m <= 14这个式子如果当年是闰年,会告成多1的误差但我们将1,2月变换到上一年的13,14月,年份要减1,所以这个误差会自动消除,所以得到下面的算法:int e = new int0,3,5,1,3,6,2,4,0,2,5,1;if(m < 3 m += 12;-y;
12、int w = (d+2 + em-3 +y+(y/4-y/100+y/400 % 7; -公式我们可以看到公式与公式几乎是一样的,仅仅是误差天和一个常数的差别常数的区别是由起始日期的星期不同引起的,0年1月1日星期日,0年3日1日星期三,有三天的差别,所以常数也从 -1 变成了 2。现在,我们成功的消除了繁琐的闰年条件判断。=消除误差表=假如存在一种m 到e 的函数映射关系,使得em-3 = f(m则我们就可以用 f(m 取代公式中的子项 em-3,也就消除了误差表。由于误差表只有12个项,且每一项都可以加减 7n 进行调整,这个函数关系是可以拼凑出来的。但是这个过程可能是极其枯燥无味的,我
13、现在不想自己去推导它,我要利用前人的成果。所谓前人栽树,后人乘凉嘛 :文章开头开出的公式中的 2*m+3*(m+1/5 这个子项引起了我的兴趣经过多次试试验,我运行下面的代码for(m=1; m<=14; +m天哪,输出结果与我的误差表不谋而合,成功了,哈哈 2 4 0 any 3 5 key 1 to 3 6 2 4 0 2 5 1 Press continue. 上面就是输出结果,看它后面的 12 项,与我的误差表完全吻合! 现在就简单的,将 f(m = -1 + 2*m + 3*(m+1/5 % 7 代入公式,得到 w = (d+1+2*m+3*(m+1/5+y+(y/4-y/10
14、0+y/400 m=1,m=2 时 m=m+12,y=y-1; -公式 6 约束条件: 现在,我们得到了通用的计算星期的公式,并且“完全”是按自己的思想推导出来的(那个函数映射 关系不算,只要理解了这个推导的步骤,即使有一天忘记了这个公式,也可以重新推导出来! 可能有人会注意到公式与文章开头的公式相差一个常数 只需改变这个常数就可以了。 1,这是因为原公式使用数字 0-6 表 示星期一到星期日, 而我用 0-6 表示星期日到星期六。 实际上是一样, 你可以改成任意你喜欢的表示方法, 六、验证公式的正确性。 一个月中的日期是连续的,只要有一天对的,模 7 的关系就不会错,所以一个月中只须验证一天 就可以了,一天需要验 12 天。由于扩展到年和月只跟是否闰年有关系,就是说至少要验证一个平年和一个 闰年,也就是最少得验证 24 次。 我选择了 测试代码如下: 2005 年和 2008 年,验证每个
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026 年消化内科护理质控缺陷分析与对策
- 2026 年小儿高热惊厥预防及急救护理处置
- 全面解析Android面试题与答案要点
- 安全生产法专项试题及参考答案
- 2026年1+X花卉园艺中级模考试题(含答案)
- 企业保安各类试题及标准答案
- 2026年度全国保密教育线上培训考试局部试题带答案
- 2026年国家开放大学电大《园艺基础》期末真题(考点提分)附答案详解
- 2026年农田水利知识试题及答案
- 2026年小学三年级数学下册期末考试测试卷附答案详解
- GB/T 32682-2026塑料聚乙烯环境应力开裂(ESC)的测定全缺口蠕变试验(FNCT)
- 零售药店医疗保障内部管理制度
- 2026年主管护师真题(含答案)
- 煤矿井下无轨胶轮车安全管理培训
- 2026年广东省中考数学试卷(含详细答案解析)
- 2026中国商业遥感卫星数据定价策略与政府采购偏好研究
- 肿瘤多学科会诊MDT模式介绍
- 2026年上海市杨浦区卫生健康系统人员招聘笔试参考题库及答案解析
- 2026年营养师(注册)考试历年机考真题集(考点提分)附答案详解
- 军用无人机讲解课件
- 保险知识问答题库及答案
评论
0/150
提交评论