公历历法::星期算法C++源码

公历历法::星期算法

【引】

《创世纪》

创世在宇宙天地尚未形成之前,黑暗笼罩着无边无际的空虚混饨,上帝那孕育着生命的灵运行其中,投入其中,施造化之工,展成就之初,使世界确立,使万物齐备。

上帝用七天创造了天地万物。这创造的奇妙与神秘非形之笔墨所能写尽,非诉诸言语所能话透。

第一日,上帝说:“要有光!”便有了光。上帝将光与暗分开,称光为昼,称暗为夜。于是有了晚上,有了早晨。

第二日,上帝说:“诸水之向要有空气隔开。”上帝便造了空气,称它为天。

……

第七日,天地万物都造齐了,上帝完成了创世之功。在这一天里,他歇息了,并赐福给第七天,圣化那一天为特别的日子,因为他在那一天完成了创造,歇工休息。就这样星期日也成为人类休息的日子。

“造化钟神秀,阴阳割分晓。”上帝就是这样开辟鸿蒙,创造宇宙万物的。


以上来自《圣经》,现在还有一些基督教徒每个礼拜天去教堂朝拜,可见一个星期七天就源于此,这正是我讨论的中心,如何计算哪年哪月哪日是星期几。

【公历历法】
公历历法很简单,年有润年(LeapYear)和平年之分,平年每月天数恒为:
月份 一 二 三 四 五 六 七 八 九 十 十一 十二
天数 31 28 31 30 31 30 31 31 30 31  30   31
共365天。润年366天,二月多一天,29天。

【润年判断】
如果年份数能被4整除但不能被100整除或者能被400整除者,为润年。

【400年刚好一个轮回】
很容易想到每400年内的润年数相等,即刚好一个轮回,400年有多少个润年?被4整除的有100个,被100整除的有4个,被400整除的只有1个,所以一共有100-4+1=97个润年,所以400年共有(365*400+97)天,即146097天,除7余0!
也就是说2001年1月1日的星期数与1年1月1日的星期数相同,翻出日历一看,星期一,我不知道上帝什么时候造的人,或许是1年1月1日。这样一来,任何一个日期我们都可以把它折算到0~399年之内的日期来算,0年的说法不准确,或许没有,但不影响这个数学结论,我们只是借它来推一推而已。

【起初的400年】
如果每一年都是平年,即365天,除7余1,也就是说如果不遇上润年,每往下一年就会使星期数增一。同样的道理,如果遇上润年,则多增一。我们要算的也就是把润年数算出来就行了,很容易,如果是y年(0<=y<400),则遇到的润年数为[y/4]-[y/100]+1,为什么要+1,因为0年也是润年(被400整除),然后把y自己身加起来就得到年指数:(y+[y/4]-[y/100])%7,它影响着星期的轮转。(其中[]表示取整,%表示取余,%7表示除以7得到的余数)

【月份的变迁】
月份的天数也不一定,所以不好直接用数学公式来表示,所以列一个表,表中对应数为星期的月指数。前面有数据:(假设为平年)
月份 一 二 三 四 五 六 七 八 九 十 十一 十二
天数 31 28 31 30 31 30 31 31 30 31  30   31
每月对应前面过去的天数:
月份 一 二 三    ……
天数 0  31 31+28 ……
对天数对7除取余得:
月份 一 二 三 四 五 六 七 八 九 十 十一 十二
天数  0  3  3  6  1  4  6  2  5  0   3    5
用一个数组保存下来:
R[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};
设月为m,则月份的影响指数为R[m],它影响着星期的轮转。

【全部加起来取7的余数】
最后剩下天指数,这很容易,直接加起来就行了,所以最后得到一个总的表达式:(先把年对400除取其余数:Year=Year%400)
Week=(Year+[Year/4]-[Year/100]+R[Month]+Day+C)%7
最后有一个常数C,如何确定这个常数,拿一个平年的正常日期数代进来,和星期数比较就可以确定C。
如2001年1月1日是星期一,所以(1+0-0+0+1+C)%7=1,即(2+C)%7=1 ==> C=6。

【遇到润年C会变】
如果没有拿足够的数据来验证,我不敢说C是常数。举几个例子:
2000年1月1日星期六,如果C=6,按公式算出来:(0+0-0+0+1+6)%7=0,星期天,错了一天,哪里错了?
前面算月指数的时候是按平年来算的,如果遇到润年,多的一天是在2月29日,如果在这之前的日期,润年不润,所以年指数会多算一天,如果在这之后,润年已润,年指数已经计算在内,所以月指数同样按平年来算不误,如2000年5月1日星期一,按公式:(0+0-0+1+1+6)%7=1,完全正确。
所以改进的做法是先判断是否是在润年而且月份数小于3,如果是,则C=5,否则C=6。

C++源码:
#include<iostream.h>
#include<string.h>
int week(int y,int m,int d)
{
    static int r[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};
    int c,w;
    y%=400;
    if((y==0||y%4==0&&y%100!=0)&&m<3)c=5;
    else c=6;
    w=(y+y/4-y/100+r[m]+d+c)%7;
    return w;
}
void main()
{
    char wk[15]="天一二三四五六";
    int y,m,d,w;
    cin>>y>>m>>d;
    w=week(y,m,d);
    cout<<y<<"年"<<m<<"月"<<d<<"日 星期"<<wk[w*2]<<wk[w*2+1]<<endl;
}
 

来个简单的  
  用了C++的cin和cout,直接改用scanf,和printf就可以了  
  #include<iostream>  
  using   namespace   std;  
   
  const   int   mon[2][12]={31,28,31,30,31,30,31,31,30,31,30,31,31,29,31,30,31,30,31,31,30,31,30,31};  
   
  int   Is_Leap(int   year){  
  if(year%400==0||(year%4==0&&year%100!=0))   return   1;  
  return   0;  
  }  
   
  void   output(int   fir,int   n){  
  int   i,j;  
  cout<<endl;  
  for(i=1;i<=12;i++){  
  cout<<i<<"月↓"<<endl<<"----------------------------"<<endl<<"     一     二     三     四     五     六     日"<<endl;  
  for(j=1;j<fir;j++)   printf("         ");  
  for(j=1;j<=mon[n][i-1];j++){  
  printf("%4d",j);  
  fir++;  
  if(fir==8){  
  cout<<endl;  
  fir=1;  
  }  
  }  
  if(fir!=1)   cout<<endl;  
  cout<<"----------------------------"<<endl;  
  }  
  cout<<endl;  
  }  
   
  int   main()  
  {  
  int   year,t;  
  while(cout<<"请输入要查询的年号(input   0   to   end):   "&&cin>>year&&year>0){  
  t=year-1;  
  t=(1+t+t/4-t/100+t/400)%7;  
  if(t==0)   t=7;  
  output(t,Is_Leap(year));  
  }  
  return   0;  
  }

结果如下:  
   
  请输入要查询的年号(input   0   to   end):   1985  
   
  1月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                1       2       3       4       5       6  
        7       8       9     10     11     12     13  
      14     15     16     17     18     19     20  
      21     22     23     24     25     26     27  
      28     29     30     31  
  ----------------------------  
  2月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                        1       2       3  
        4       5       6       7       8       9     10  
      11     12     13     14     15     16     17  
      18     19     20     21     22     23     24  
      25     26     27     28  
  ----------------------------  
  3月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                        1       2       3  
        4       5       6       7       8       9     10  
      11     12     13     14     15     16     17  
      18     19     20     21     22     23     24  
      25     26     27     28     29     30     31  
  ----------------------------  
  4月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
        1       2       3       4       5       6       7  
        8       9     10     11     12     13     14  
      15     16     17     18     19     20     21  
      22     23     24     25     26     27     28  
      29     30  
  ----------------------------  
  5月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                        1       2       3       4       5  
        6       7       8       9     10     11     12  
      13     14     15     16     17     18     19  
      20     21     22     23     24     25     26  
      27     28     29     30     31  
  ----------------------------  
  6月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                                1       2  
        3       4       5       6       7       8       9  
      10     11     12     13     14     15     16  
      17     18     19     20     21     22     23  
      24     25     26     27     28     29     30  
  ----------------------------  
  7月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
        1       2       3       4       5       6       7  
        8       9     10     11     12     13     14  
      15     16     17     18     19     20     21  
      22     23     24     25     26     27     28  
      29     30     31  
  ----------------------------  
  8月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                1       2       3       4  
        5       6       7       8       9     10     11  
      12     13     14     15     16     17     18  
      19     20     21     22     23     24     25  
      26     27     28     29     30     31  
  ----------------------------  
  9月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                                        1  
        2       3       4       5       6       7       8  
        9     10     11     12     13     14     15  
      16     17     18     19     20     21     22  
      23     24     25     26     27     28     29  
      30  
  ----------------------------  
  10月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                1       2       3       4       5       6  
        7       8       9     10     11     12     13  
      14     15     16     17     18     19     20  
      21     22     23     24     25     26     27  
      28     29     30     31  
  ----------------------------  
  11月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                        1       2       3  
        4       5       6       7       8       9     10  
      11     12     13     14     15     16     17  
      18     19     20     21     22     23     24  
      25     26     27     28     29     30  
  ----------------------------  
  12月↓  
  ----------------------------  
      一     二     三     四     五     六     日  
                                                        1  
        2       3       4       5       6       7       8  
        9     10     11     12     13     14     15  
      16     17     18     19     20     21     22  
      23     24     25     26     27     28     29  
      30     31  
  ----------------------------  

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值