文章目录
- 万年历简述
- 代码
万年历简述
万年历——就是输入一个日期可以查询是星期几,这个功能看起来很普通,但是如果用程序时间的话,还是药费一番周折:
- 我们需要保存一个固定的日期,存放它是星期几,输入一个自定义的日期,通过二者的日期差推断出输入日是星期几
- 我们需要考虑每一年是闰年还是平年,这个关系我们的日期差到底是几。所以需要创建一个返回bool型变量的函数
bool isleapyear(int year)
。 - 我们使用的语言是C语言不是Visual Basic。在VB里面是有日期类型(date)的变量的,加减非常方便,但是C里面没有,我们可以通过结构体定义一个
typedef struct{int year;typedef struct{int year;int month;int day;enum Weekdays weekday;} Date;
将一个时间点的年、月、日、星期建立联系,方便我们后面的输出和查找。
- 每个月的天数是不一样的,而这个日期的分布规律又过于复杂,我们不妨设一个数组来存放月份的天数。2月份的天数初始化的时候可以设为28,如果
isleapyear(int year)==true
,再将2月份天数改为29,否则设为28。 - 计算两个日期的日期差,如果两个日期的年份>2,则需要通过闰年判断函数对每个年份判断,并确定应该分别加多少,而对零头(也就是一年中的哪一天),我们需要另外设一个函数
int count_days(int *days,Date *datetime);
,通过传递days月份天数数组和一个日期,来计算该日期在该年是哪一天。假设参考日期在所在年的天数是day1,所在年天数为year1,输入日期在所在年的天数是day2,所在年天数为year2,两年所隔的年份总天数为是years,则相隔日期Δ\DeltaΔdays=year1-day1+years+day2; - 我们在程序里面设计一个逻辑性变量bool next,每次运行完一个循环都扫描一下逻辑变量的值,如果用户输入1代表继续(其实非零值均可),输入0代表结束,整个过程使用do…whie循环控制,并且在循环体末尾要加上扫描是否继续的选择到next逻辑变量中的语句,即:
do{
...
printf("\n是否继续?(是:1,否:0): ")
scanf("%d",&next);
fflush(stdin);//在循环中使用scanf必须要清空输入缓存区,否则执行完1次循环会跳过循环体中的第一个scanf
)while(next);
使用一个判断是否继续的变量可以更好地实现人机交互的功能,同时也可以一次性多次测试代码的正确性。
7. 由于日期差值是负的还是整的关系到我们的计算结果,直接不管正负地模7取余是有问题的,所有我们保存7个参考日期,如果相减可以被7整除就代表是星期几。
代码
#include <stdio.h>
#include <stdbool.h>
#include <malloc.h>
#include <math.h>
#define LEN sizeof(Date)
enum Weekdays{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};//定义weekday枚举型变量
typedef struct {int year;int month;int day;enum Weekdays weekday;
}Date;//定义日期的结构体变量
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};//平年的日期,可以借助modify_year修改
Date refdate[7];//定义7个参考日期,依次为周一到周日
int datedistract(Date date1,Date date2); //日期相减的函数
bool isleapyear(int year);//判断闰年的函数
void modify_days(int *days,int year);//通过闰年对月份日期修改的函数
void findweekday(Date *datetime);
void weekdayprint(enum Weekdays weekday);
int count_days(int *days,Date *datetime); //计算结构体日期变量在一年中处于哪一天
int main()
{printf("************日期计算实验****************\n");bool next;//是否继续do{Date *datetime=malloc(LEN);//定义Date类型的结构体指针datetime,同时开辟一段内存(不开辟内存会使程序崩溃)int i;for(i=0;i<7;i++){refdate[i].year=2018;refdate[i].month=12;refdate[i].day=10+i;}//refdate结构体数组存放了2018/12/20~2018/12/26的7个日期,他们正好是周一到周日 printf("请输入一个日期(year/month/day): ");scanf("%d/%d/%d",&datetime->year,&datetime->month,&datetime->day);printf("该日期所在年份中的天数为%d\t",count_days(days,datetime)); findweekday(datetime);weekdayprint(datetime->weekday);printf("\n是否继续?(是:1,否:0): ");//是否继续的判断如下scanf("%d",&next); fflush(stdin);//刷新标准输入流,否则循环的时候会跳过第一个scanf } while(next);return 0;
}
bool isleapyear(int year)
{if(year%4==0){if(year%100==0){if(year%400==0)return true;else return false;}else return true;}else return false;
}
//闰年修改函数
void modify_days(int *days,int year)
{if(isleapyear(year)==true)days[1]=29;else days[1]=28;
}
int count_days(int *days,Date *datetime)//将该年各月份日期已经结构体变量录入,计算在该年的天数
{int i,count=0;modify_days(days,datetime->year);for(i=0;i<datetime->month-1;i++)count+=days[i];count+=datetime->day;return count;
}
int datedistract(Date date1,Date date2)
{int year,month,day,count=0;bool cmp;//比较两个日期哪个在前面,方便写循环Date temp;//作为交换变量的中间变量if(date1.year>date2.year)cmp=true;else if(date1.year<date2.year)cmp=false;else if(date1.month>date2.month)cmp=true;else if(date1.month<date2.month)cmp=false;else if(date1.day>date2.day)cmp=true;else cmp=false;if(cmp){temp=date1;date1=date2;date2=temp;}//如果date1在date2后面,则交换二者,保证date1始终比date2小for(year=date1.year;year<date2.year;year++)count+=isleapyear(year)?366:365;//按照是否为闰年书累加count+=count_days(days,&date2)-count_days(days,&date1);//计算零头return abs(count);//返回所差日期
}
void findweekday(Date *datetime)
{int i;for(i=0;i<7;i++){if(datedistract(*datetime,refdate[i])%7==0){datetime->weekday=i;break;}}
}
void weekdayprint(enum Weekdays weekday)
{switch(weekday){case 0:printf("星期一");break;case 1:printf("星期二");break;case 2:printf("星期三");break;case 3:printf("星期四");break;case 4:printf("星期五");break;case 5:printf("星期六");break;case 6:printf("星期日");break;}
}
输出结果如下图,可以多次输入,一次性查找多个日期: