核心算法:星期(0~6)=(年份系数+月份系数+日期)%7;
其中,年份系数我以2007年做参照,已知2007年,年份系数是0,往前往后分别是递减和递增。增减规律:非闰年为±1,闰年1~2月-2或+1,闰年3~12月+2或者-1。
其中,12个月份系数对应:0,3,3,6,1,4,6,2,5,0,3,5。
根据以上规律,只要利用循环,就可以的到对应系数和星期。
日历实现翻页功能,按键盘左右方向键可以翻译查看当年其他月份,按向上方向键可以返回菜单。
下面是代码:
#include
#include
#include
#include
#include
#include
#define XY 2007
#define X07 0//以2007年年系数0做参照
int isLeapYear(int year);//判断是否是闰年,是返回1,否返回0
int addyx(int yx,int n);//年系数自增,0~6,n:自增的跨度,返回自增后的年系数
int getYX(int year,int month);//获得年系数0~6
int getMX(int month);//获得月系数
int getWeek(int yx,int mx,int day);//通过年月系数(yx:年系数;mx:月系数)及日期获取星期
char *getStrWeek(int yx,int mx,int day);//通过年月系数(yx:年系数;mx:月系数)及日期获取星期对应的中文字符串
int getMaxDay(int year,int month);//通过年月获取当月最大天数
void prCalendar(int year,int month);//打印日历
int showMeun();//打印主菜单
int getDuration(int year,int month,int day);//通过日期获取距今天数
int calendar[6][7];
int main()
{
//int year,month,day,yx,mx;
while(1)
{
if(!showMeun())
break;
}
return 0;
}
int showMeun()//打印主菜单
{
int n,year,month,day,yx,mx;
while(1)
{
system("cls");
printf("1、输入年份,显示该年每个月的日历\n");
printf("2、输入年月,显示该月的天数\n");
printf("3、输入日期,显示距离今天的天数\n");
printf("4、输入日期,查询这一天是星期几\n");
printf("0、结束程序\n");
n=-1,year=0,month=0,day=0;
while(n<0 || n>4)
{
printf("请输入选择的菜单序号:");
scanf("%d",&n);
}
switch(n)
{
case 1:while(year<=0 || year>9999)
printf("请输入年份:"),scanf("%d",&year);
prCalendar(year,1);
break;
case 2:while(year<=0 || year>9999 || month<=0 || month>12)
printf("请输入年份及月份:"),scanf("%d%d",&year,&month);
printf("%4d年%2d月共有%d天\n按任意键继续。。。。。。\n",year,month,getMaxDay(year,month)),getch();
break;
case 3:while(year<=0 || year>9999 || month<=0 || month>12 || day<0 || day>getMaxDay(year,month))
printf("请输入日期:"),scanf("%d%d%d",&year,&month,&day);
printf("距离今日有%d天\n按任意键继续。。。。。。\n",getDuration(year,month,day)),getch();
break;
case 4:while(year<=0 || year>9999 || month<=0 || month>12 || day<0 || day>getMaxDay(year,month))
printf("请输入日期:"),scanf("%d%d%d",&year,&month,&day);
yx=getYX(year,month);
mx=getMX(month);
printf("%4d年%2d月%2d日是%s\n按任意键继续。。。。。。\n",year,month,day,getStrWeek(yx,mx,day)),getch();
break;
case 0:return 0;
}
}
return n;
}
void prCalendar(int year,int month)//打印日历
{
char c1,c2;
int i,j,*p=NULL,yx,mx,cnt,w,maxDay;
while(1)
{
p=&calendar[0][0];
yx=getYX(year,month),mx=getMX(month);
cnt=0,w=getWeek(yx,mx,1);
maxDay=getMaxDay(year,month);
for(i=0;i<6;i++)
for(j=0;j<7;j++)
{
if(cnt p++,cnt++; calendar[i][j]=0; } for(i=1;i<=maxDay;i++) *p=i,p++; system("cls"); printf(" %4d 年%2d月 \n",year,month); printf("日 一 二 三 四 五 六\n"); for(i=0;i<6;i++,printf("\n")) for(j=0;j<7;j++) if(calendar[i][j]==0) printf(" "); else printf("%2d ",calendar[i][j]); printf("<- 按方向键向左或向右翻页 ->\n"); printf(" 按向上方向键返回主菜单\n"); c1=getch(); c2=getch(); if(c1==-32 && c2==75)//左键 { if(month==1) month=12; else month--; } if(c1==-32 && c2==77)//右键 { if(month==12) month=1; else month++; } if(c1==-32 && c2==72)//上键 { showMeun(); break; } } } int getDuration(int year,int month,int day)//通过日期获取距今天数 { int i,y,m,d,sum=0,sum2=0,minY,maxY,minM,maxM,minD,maxD; time_t tt; struct tm *tmp; time(&tt); tmp=localtime(&tt); y=1900+tmp->tm_year,m=1+tmp->tm_mon,d=tmp->tm_mday;//获取当前日期的年月日 if(year minY=year,maxY=y,minM=month,maxM=m,minD=day,maxD=d; if(year>y) minY=y,maxY=year,minM=m,maxM=month,minD=d,maxD=day; if(year!=y) { for(i=minY;i if(isLeapYear(i)) sum+=366;//闰年 else sum+=365; for(i=1;i sum-=getMaxDay(minY,i); sum-=minD;//扣除左端当月已过天数 for(i=1;i sum+=getMaxDay(maxY,i); sum+=maxD;//累加右端当月已过天数 } else//如果年份相同,累加两边一年内已过天数,求差值 { for(i=1;i sum+=getMaxDay(month,i); sum+=day; for(i=1;i sum2+=getMaxDay(m,i); sum2+=d; return abs(sum2-sum); } return sum; } int getMaxDay(int year,int month)//通过年月获取当月最大天数 { int days[12]={31,28,31,30,31,30,31,31,30,31,30,31}; if(isLeapYear(year) && month==2) return days[month-1]+1; return days[month-1]; } char *getStrWeek(int yx,int mx,int day)//通过年月系数(yx:年系数;mx:月系数)及日期获取星期对应的中文字符串 { int w; static char week[7]; memset(week,0,7); strcpy(week,"星期"); w=getWeek(yx,mx,day); switch(w) { case 0:strcat(week,"日");break; case 1:strcat(week,"一");break; case 2:strcat(week,"二");break; case 3:strcat(week,"三");break; case 4:strcat(week,"四");break; case 5:strcat(week,"五");break; case 6:strcat(week,"六");break; } return week; } int getWeek(int yx,int mx,int day)//通过年月系数(yx:年系数;mx:月系数)及日期获取星期对应的数值0~6 { return (yx+mx+day)%7; } int getMX(int month)//获得月系数 { int xmonth[12]={0,3,3,6,1,4,6,2,5,0,3,5};//月系数:1-12月,每月的系数。 return xmonth[month-1]; } int getYX(int year,int month)//获得年系数0~6 { int yx=0,nyear=XY,isly,flag; if(nyear==year) return 0; if(nyear flag=0,nyear++; else flag=1,nyear--; while(1) { isly=isLeapYear(nyear); if(!isly){//非闰年年系数累加1 if(!flag) yx=addyx(yx,1); else yx=addyx(yx,-1); } if(isly && month>=1 && month<=2){//闰年1~2月年系数累加1,3`12月年系数累加2 if(!flag) yx=addyx(yx,1); else yx=addyx(yx,-2); } else if(isly && month>=3 && month<=12){ if(!flag) yx=addyx(yx,2); else yx=addyx(yx,-1); } if(nyear==year) break; if(!flag && nyear nyear++; if(flag && nyear>year) nyear--; } return yx; } int addyx(int yx,int n)//年系数自增,0~6,n:自增的跨度,返回自增后的年系数 { if(n>0) { if(yx+n<=6) return yx+n; if(yx+n>6) return yx+n-7; } if(n<0) { if(yx+n>=0) return yx+n; if(yx+n<0) return yx+n+7; } return -1; } int isLeapYear(int year)//判断是否是闰年,是返回1,否返回0 { if((year%4==0 && year%100!=0)||(year%400==0)) return 1; return 0; }