GS

被sgao忘记的东西都在这里。
随笔 - 19, 文章 - 8, 评论 - 3
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

总天数以及星期几的计算算法

Posted on 2015-08-14 13:48  sgao  阅读(755)  评论(0编辑  收藏

在写程序的过程中,需要判断两个日期是否处在一个星期之内,如果用C++类库CTime,则只能计算1970年之后的日期,之前的日期就会报错,于是研究了几个星期计算算法,改写出一个计算从1年1月1日起到输入日期之间的天数,如果他们的除数相同,则表明他们在一个星期之内(原理参见参考文章《蔡勒算法》),同时该方法也可以计算两个日期之间的天数差。

日期计算关于《1582年10月4日和1752年9月3日 》这两个日期都有特殊的历史,蔡勒公式和基姆拉尔森公式也都给出了在特殊日期前后的计算方式,如计算的日期在这两个日期之前,需要特殊计算。

  1 // CDate.cpp : 定义控制台应用程序的入口点。
  2 
  3 #include "stdafx.h"
  4 #include "atltime.h"
  5 #include<iostream>
  6 #include<string>
  7 using namespace std;
  8 
  9 int GetTotalDays(int y,int m, int d);
 10 int ZellerWeekDay(int y,int m, int d);
 11 int CaculateWeekDay(int y,int m,int d);
 12 int GetWeekDay(int y,int m,int d);
 13 string GetWeekStr(int w);
 14 bool is_valid(int m,int d,int y);
 15 
 16 int _tmain(int argc, _TCHAR* argv[])
 17 {
 18     int month,day,year;
 19     while(true)
 20     {
 21         cout<<"输入一个日期:yyyy mm dd: ";
 22         cin>>year>>month>>day;
 23         if(is_valid(month,day,year))
 24         {
 25             int nTotalDays = GetTotalDays(year,month,day);
 26             string strWeek = GetWeekStr((nTotalDays - 1) % 7);
 27             cout<<"总天数:"<<nTotalDays<<"    星期"<<strWeek<<endl;
 28 
 29             int nWeek = ZellerWeekDay(year,month,day);
 30             strWeek = GetWeekStr(nWeek);
 31             cout<<"Zeller公式计算结果:星期"<<strWeek<<endl;
 32 
 33             nWeek = CaculateWeekDay(year,month,day);
 34             strWeek = GetWeekStr(nWeek);
 35             cout<<"基姆拉尔森公式计算结果:星期"<<strWeek<<endl;
 36 
 37             nWeek = GetWeekDay(year,month,day);
 38             strWeek = GetWeekStr(nWeek);
 39             cout<<"类库函数计算结果:星期"<<strWeek<<endl;
 40             cout<<endl;
 41         }
 42         else
 43         cout<<year<<"-"<<month<<"-"<<day<<"是一个错误的日期."<<endl;
 44     }
 45 }
 46 
 47 //改写算法计算总天数,可以计算日期处在第几周
 48 int GetTotalDays(int y,int m, int d)
 49 {
 50     //下面是根据蔡勒(Zeller)公式改写的算法
 51     int  leap= 0;
 52     if(m==1){m=13;y--;}
 53     if(m==2){m=14;y--;}
 54     if (y > 0 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
 55             leap++;
 56     y--;
 57     //计算从1.1.1日起至当前日期的天数
 58     int nTotalDays = 365*y + y/4 - y/100 + y/400 + 13*(m+1)/5 - 7 + 28*(m-1)+d + leap;    
 59     return  nTotalDays;
 60 }
 61 
 62 //蔡勒公式
 63 int ZellerWeekDay(int y,int m, int d)
 64 {
 65     int week = 0;
 66     if(m==1){m=13;y--;}
 67     if(m==2){m=14;y--;}
 68     int c = y / 100;
 69     y = y % 100;
 70     week = y + y/4 + c/4 - 2*c + (13*(m+1))/5 + d - 1;
 71     week = (week -1) % 7;
 72     return week;
 73 }
 74 
 75 //基姆拉尔森公式计算星期几
 76 int CaculateWeekDay(int y,int m, int d)
 77 {
 78     int week;
 79     if(m==1){m=13;y--;}
 80     if(m==2){m=14;y--;}
 81     //if((y<1752)||((y==1752)&&(m<9))||((y==1752)&&(m==9)&&(d<3))) //判断是否在1752年9月3日之前
 82     //    week =(d+2*m+3*(m+1)/5+y+y/4+5)%7; //1752年9月3日之前的公式
 83     //else
 84         week =(d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7; //1752年9月3日之后的公式
 85     return week;
 86 }
 87 
 88 //获取星期几用于验算
 89 int GetWeekDay(int y,int m,int d)
 90 {
 91     int week = -1;
 92     if (y > 1900)
 93     {
 94         CTime tm(y,m,d,0,0,0);
 95         week = tm.GetDayOfWeek();
 96         week = (week + 5) % 7;
 97     }
 98     return week;
 99 }
100 
101 string GetWeekStr(int w)
102 {
103     string weekstr;
104     switch(w)
105     {
106     case 0: {weekstr=""; break;}
107     case 1: {weekstr=""; break;}
108     case 2: {weekstr=""; break;}
109     case 3: {weekstr=""; break;}
110     case 4: {weekstr=""; break;}
111     case 5: {weekstr=""; break;}
112     case 6: {weekstr=""; break;}
113     }
114     return weekstr;
115 }
116 
117 bool is_valid(int m,int d,int y)
118 {
119 if(m<0||m>12||d<0||d>31||y<0)
120 return false;
121 return true;
122 }