在写程序的过程中,需要判断两个日期是否处在一个星期之内,如果用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 }