计算公元某年某月某日是星期几

我们知道,公历的平年是365天,闰年是366天,置闰的方法是能被4整除的年份在2月加一天,但能被100整除的不闰,能被400整除的又闰;因此,像1600、2000、2400年都是闰年,而1700、1800、1900、2100年都是平年,公元前1年,按公历也是闰年。因此,对于从公元前1年(或公元0年)12月31日到某一日子的年份Y之间的所有整年中的闰年数,就等于  
  [(Y-1)/4] – [(Y-1)/100] + [(Y-1)/400]   
  […]表示只取整数部分,第一项表示需要加上被4整除的年份数,第二项表示需要去掉被100整除的年份数,第三项表示需要再加上被400整除的年份数;之所以Y要减一是为了去掉输入的这一年。这样,我们就得到了第一个计算某一天是星期几的公式:   
  W = (Y-1)*365 + [(Y-1)/4] – [(Y-1)/100] + [(Y-1)/400] + D. (1)   
  其中D是这个日子在这一年中的累积天数,算出来的W就是公元前1年(或公元0年)12月31日到你输入的这一天之间的间隔日数;把W用7除,余数是几,这一天就是星期几。比如我们来算2004年5月1日:   
  W = (2004-1)*365 + [(2004-1)/4] – [(2004-1)/100] + [(2004-1)/400] + (31+29+31+30+1) = 731702   
  731702 / 7 = 104528……6,余数为六,说明这一天是星期六,这和事实是符合的。   
  上面的公式(1)虽然很准确,但是计算出来的数字太大了,使用起来很不方便。仔细想想,其实这个间隔天数W的用数仅仅是为了得到它除以7之后的余数。这启发我们是不是可以简化这个W值,只要找一个和它余数相同的较小的数来代替,用数论上的术语来说,就是找一个和它同余的较小的正整数,照样可以计算出准确的星期数。   
  显然,W这么大的原因是因为公式中的第一项(Y-1)*365太大了。其实,(Y-1)*365 = (Y-1) * (364+1) = (Y-1) * (7*52+1)= 52 * (Y-1) * 7 + (Y-1)   
  这个结果的第一项是一个7的倍数,除以7余数为0,因此(Y-1)*365除以7的余数其实就等于Y-1除以7的余数。这个关系可以表示为:(Y-1)*365 ≡ Y-1 (mod 7)
  其中,≡是数论中表示同余的符号,mod 7的意思是指在用7作模数(也就是除数)的情况下≡号两边的数是同余的。因此,完全可以用(Y-1)代替(Y-1)*365,这样我们就得到了那个著名的、也是最常见到的计算星期几的公式:   
  W = (Y-1) + [(Y-1)/4] – [(Y-1)/100] + [(Y-1)/400] + D. (2)
W除以7所得的余数是几那一天就是星期几。

 

//计算某年某月某日是星期几 //计算公式:(year-1+(year-1)/4 -(year-1)/100 +(year-1)/400+n)%7 //公式说明:year为年份,n为该天是该年的第几天(包括该天) #include<stdio.h> void main() { int y,d,s=0,i,m,x; int mm[12]={31,0,31,30,31,30,31,31,30,31,30,31}; char *week[]={“星期日”,”星期一”,”星期二”,”星期三”,”星期四”,”星期五”,”星期六”}; printf(“输入年月日(格式:年月日之间以空格隔开):”); scanf(“%d %d %d”,&y,&m,&d); x = y%100==0 ? y%400 : y%4; mm[1] = (x==0 ? 29 : 28); for(i=0;i<m-1;++i) s=s+mm[i]; printf(“/n/n%d年%d月%d日/n/n”,y,m,d); printf(“第%d天/n/n”,s+d); y–; x = (y+y/4-y/100+y/400+s+d)%7; printf(“%s/n/n”,week[x]);//套用公式 }

点赞