#include <stdio.h>
// 检测当前年分是闰年还是平年
// Input: int year: 判断年份
// Output: 1:闰年 0:平年
int IsLeapYear(int year)
{
int ret = 0;
// 检测当前输入参数是否合法
// 支持公元1 - 2100年
if(year <= 0 || year > 2100){
ret = -1; // 年 参数错误
}
// 普通闰年:能被4整除但不能被100整除的年份为普通闰年
// 世纪闰年:能被400整除的为世纪闰。
if(((year%4 == 0) && (year%100 != 0)) || // 普通闰年
(year%400 == 0)){ // 世纪闰年
ret = 1; // 闰年
}
return ret;
}
// 检测当前年月最大日期
// 判断该月一共有几天?
// input: int year: 当前年份
// int month: 当前月份
// output: -1: 年份输入错误
// -2: 月份输入错误
// 其他:正确结果
int FindDate(int year, int month)
{
int ret = 0;
// 检测年份参数是否合法
// 并判断年份是闰年还是平年
ret = IsLeapYear(year);
if(ret < 0){ // 参数错误
goto err;
}
// 此处检测月份参数是否合法
if(month <= 0 || month >12){
ret = -2; // 年与月参数错误
goto err;
}
// 月份检测
switch(month){
case 2: // 2月
if(ret == 1){ // 闰年是29天
ret = 29;
}else{
ret = 28; // 平年是28天
}
break;
case 4:
case 6:
case 9:
case 11: // 4月 6月 9月 11月 固定30天
ret = 30;
break;
default: ret = 31; // 1月 3月 5月 7月 8月 10月 12月固定31天
}
err:
return ret;
}
// 实现输入日期,计算当前是周几
// input : int year 当前查询的年份
// int month 当前查询的月份
// int day 查询的日期
// output: 0-周一 1-周二 ... 6-周日
int CalendarConvertWeek(int year, int month, int day)
{
int week;
// 由于日期已经检测是否合法,这里不做检测
// 基姆拉尔森计算公式
// W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7
// 基本思想:把1月和2月看成是上一年的13月和14月
if((month == 1) || (month == 2)){
year--;
month += 12;
}
// %7: 不用做参数范围判断
week = (day + 2*month + 3*(month+1)/5 + \
year + year/4 - year/100 + year/400)%7;
return week;
}
// 实现:2.Print a month's calendar
// input : int year 当前查询的年份
// int month 当前查询的月份
// int maxday 当月最大有多少天
void PrintfCalendarAMonth(int year, int month, int maxday)
{
int i, j;
int week;
int day = 1;
printf("%04d-%02d\n", year, month); // 打印测试
// 检测当前打印日期的起始位置(即周几?)
week = CalendarConvertWeek(year, month, day);
//printf("%04d-%02d-%02d 是星期%d\n", year, month, 1, week+1); // 测试函数
// 当前\tXXX 为一组,共七组
printf("\tMon\tTue\tWed\tThu\tFri\tSat\tSun\n");
// 计算当前起始位置:礼拜一是第一列
j = week%7;
// 起始第一行的偏移量
for(i=0; i<j; i++){
printf("\t\0\0\0");
}
// 打印剩余的day,注意换行
for(i=1; i<=maxday; i++,j++){
if((j%7) == 0){ // 打印换行
printf("\n");
}
printf("\t%d", i); // 打印日期
}
}
// 实现:1.Print a year's calendar
// input : int year 当前查询的年份
// int type 0 = 平年 1 = 闰年
void PrintfCalendarYear(int year, char type)
{
int i;
char sday[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
// 不用做参数范围判断
if(type){
sday[1] = 29; // 闰年是29天,默认是28天
}
// 打印12个月份的日历
// 使用空间换取时间
for(i=1; i<=12; i++){
PrintfCalendarAMonth(year, i, sday[i-1]);
printf("\n");
}
}
// 实现第三题测试
void Test03_PrintfCalendar(void)
{
int rec;
int year, month;
for(;;){
// 打印人机交互界面
printf("*********************Please chose*************************\n");
printf("*************1.Print a year's calendar *******************\n");
printf("*************2.Print a month's calendar*******************\n");
printf("*************0.Quit calendar *****************************\n");
printf("**********************************************************\n");
// 接收选择字符 -> 1 2 0
printf("your chose:(1 or 2) -> ");
// 问题:假若输入字符或字符串后,就一直执行,停不下
// 20200229已解决该问题,添加清空缓冲区,但输入多个字符仍出现此类问题
setbuf(stdin,NULL); // 清空缓冲区
scanf("%d", &rec);
// 先实现2.Print a month's calendar
// 在以上的基础上拓展1.Print a year's calendar
switch(rec){
case 0: return; // 退出操作
case 1: { // 打印某一整年的日历
printf("input Year(2100>Year>0) -> ");
scanf("%d", &year); // 输入年份
// 检测年份参数是否合法
// 并判断年份是闰年还是平年
rec = IsLeapYear(year);
if(rec < 0){ // 参数错误
printf("\nInput err, please try again.\n\n");
break;
}
PrintfCalendarYear(year, rec); // 打印整年日历
}return;
case 2: { // 打印某一年某个月的日历
printf("input Year and Month (eg:2020,2) -> ");
scanf("%d,%d", &year, &month); // 输入年份月份
// 检测当前年月输入是否正确
// 并返回当前月份最大是多少天
rec = FindDate(year, month);
if(rec < 0){ // 参数错误并返回
printf("\nInput err, please try again.\n\n");
break;
}
PrintfCalendarAMonth(year, month, rec); // 执行打印月份日历
}return;
default: printf("\nInput err, please try again.\n");
}
printf("\n");
rec = 0;
sleep(1); // 延迟显示下一帧,增强体验感
}
}
// 主函数
int main(int argc, const char *argv[])
{
#if 1
// 使用上题中的两个函数
// 思想: 1.先做选择-人机交互界面
// 2.接收选择字符 -> 1或者2
// 3.先实现2.Print a month's calendar
// 4.检测当前打印日期的起始位置(即周几?),此处按照win10日历样式显示,与例程稍不一样。
// 5.计算当前起始位置:礼拜一是第一列
// 6.打印起始第一行的偏移量
// 7.打印当前月的所有day(到周日后就换行显示)
// 8.在7的基础上拓展1.Print a year's calendar
// 测试完成,效果符合题目要求
// 已解决的问题:在人机交互界面选择1 or 2时,假若输入字符或字符串后,就一直执行,停不下。
Test03_PrintfCalendar();
// 打印效果:
// 2020-02
// Mon Tue Wed Thu Fri Sat Sun
// 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
#endif
printf("\n");
return 0;
}
3.实现printf日历
猜你喜欢
转载自blog.csdn.net/TurboTab/article/details/104606319
今日推荐
周排行