前言: 文章不足之处请麻烦评论指正!
总体设计:
1,显示菜单提示用户进行输入并执行对应函数
2,获取当前日期:获取系统时间作为默认值,显示所在年月的月历并突出当天日期
3,显示全年年历:显示所在年份的全年日历,并突出当天日期
4,查询日期:输入指定日期并突出显示,用户可选择显示全年日历或月历
5,调整日期:用户输入可修改时间的默认值,且检查到无效日期时可以重置为系统时间
一,预备知识
1. 关于 struct tm 结构体
struct tm
是C语言中的一个结构体,定义在头文件<time.h>
中。它用于存储时间和日期的信息,我们只需要在程序中包含<time.h>头文件,就可以使用此结构体中的信息,能够更方便地操作和处理时间。结构体的定义如下:struct tm { int tm_sec; // 秒,范围从 0 到 59 int tm_min; // 分,范围从 0 到 59 int tm_hour; // 时,范围从 0 到 23 int tm_mday; // 一个月中的日,范围从 1 到 31 int tm_mon; // 月份,范围从 0 到 11 int tm_year; // 年份,从 1900 开始 int tm_wday; // 一周中的日,范围从 0 (周日) 到 6 (周六) int tm_yday; // 一年中的日,范围从 0 到 365 int tm_isdst; // 夏令时标识 };
2. 计算 星期几 的方式
公式:int w = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
(其中d表示日,m表示月,y表示年;其中w+1表示星期几)
w 的值将是 0 到 6 之间的一个整数,分别代表一周的不同天,再加 1 准确表示周几。
3. 输出不同颜色的字体
·演示效果:
`其中 \33[0m 为关闭所有属性.
·根据上面的演示,我们可以直接得出结论:在输出时候加上 \033[ 参数 …… \033[0m 即可使得在一句打印语句中输出的字体是有颜色的。(使用ANSI转义码控制文本属性)
---
·格式解析: \033[ 参数1;参数2 是样式的开始, \33[参数 是样式的结束,如果不结束则代表着后续的输出字符也套用其中的格式。(更多关于c语言字体颜色的内容可自行搜索)
二,代码分段解析
1. 头文件和定义的全局变量
#include"head.h" //包含头文件head.h time_t t; //定义time_t类型的变量t struct tm* today; //创建结构体指针变量today int choice = 0; //用于键盘输入选择菜单选项 int year, month, day; //全局变量用于记录当前的时间信息 int year1, month1, day1; //全局变量用于记录输入要查询的时间
全局变量可以为本文件中其它函数所共用,它的作用域为从定义变量的位置开始到本源文件结束。定义为全局变量可方便函数直接调用,而不需要再进行传参.
2. 头文件head.h
#pragma once #include<stdio.h> #include<time.h> //菜单 void menu(); //判断给定年份是否是闰年 int isLeapYear(int y); //这个函数用于计算返回该月的天数 int daysInMonth(int y, int m); //这个函数用于计算给定日期是星期几 int dayOfWeek(int y, int m, int d); //可突出显示当前指定年月的月历 void displayCalendar(int y, int m, int currentDay); //这个函数用于显示指定年份 year 的全年日历 void displayYearCalendar(int y); //这个函数用于验证给定的日期是否有效 int isValidDate(int y, int m, int day); //查询指定日期的月历并突出显示 void queryDate(int y, int m, int day); //允许用户通过键盘输入来调整日期 void adjustDate(int y, int m, int d); //重置时间为当前系统时间 void resetTime();
如果使用的是Microsoft Visual Studio进行编写代码,请在代码开头添加:
#define _CRT_SECURE_NO_WARNINGS
3. 主函数main
int main() { int year2, month2, day2; t = time(NULL);//time(&t),获取当前时间戳(秒数) //将时间戳(秒数)转换为 struct tm 结构体,对应本地时区 today = localtime(&t); year = today->tm_year + 1900;//年份从1900开始 month = today->tm_mon + 1; //月份从1开始 day = today->tm_mday; //一个月中的日,0-31 do { //获取对应日期为星期几 int week = dayOfWeek(year, month, day); //打印菜单,并进行输入选择 printf(">>>\033[36;5mNOW: %d-%d-%d · 周%d\033[0m\n", year, month, day, week); menu(); printf("\033[1m请输入选择的操作: \033[0m"); scanf("%d", &choice); switch (choice) { case 1: //显示当前的月历,并突出显示今天的日期 displayCalendar(year, month, day); break; case 2: system("cls");//清空已有内容 displayYearCalendar(year); break; case 3: printf("请输入要查询的日期(YYYY MM DD): "); scanf("%4d %2d %2d", &year1, &month1, &day1); queryDate(year1, month1, day1); break; case 4: printf("请输入修改后的日期(YYYY MM DD): "); scanf("%4d %2d %2d", &year2, &month2, &day2); adjustDate(year2, month2, day2); break; case 0: printf("已退出万年历系统!\n"); break; default: printf("输入错误,请重试!\n"); break; } } while (choice); return 0; }
主要根据用户使用键盘进行输入选择,然后通过switch语句执行对应的函数。
三,代码中使用到的函数
1,展示选择菜单
void menu()
{
printf("\033[36m| 1, 获取当前日期 |\033[0m\n");
printf("\033[36m| 2, 显示全年日历 |\033[0m\n");
printf("\033[36m| 3, 查询日期 |\033[0m\n");
printf("\033[36m| 4, 调整日期 |\033[0m\n");
printf("\033[36m| 0, 退出 |\033[0m\n");
printf("\n");
}
2,判断给定年份是否为闰年
int isLeapYear(int y)
{
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
return 1;//返回1,代表闰年
else
return 0;//返回0,代表平年
}
计算闰年的方式: ①:年份可以被4整除但是不能被100整除; ②:年份能被400整除。
3,计算返回给定月份的天数
int daysInMonth(int y, int m)
{
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (m == 2 && isLeapYear(y))
{
days[2] = 29;
}
return days[m];
}
定义一个长度为13的整型数组存放月份的天数(为了提高代码的可读性,在0索引处置0,则后续的每个索引都可以代表其对应月份的天数),判断给定的年份是否为闰年,是闰年则将2月的天数置为29天,最后返回对应月份的天数。
4,计算给定日期是星期几
int dayOfWeek(int y, int m, int d)
{
if (m < 3)
{
m += 12;
y--;
}
int h = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
//h+1表示某时间是星期几
return h + 1;
}
在“预备知识”部分已介绍了根据给定的日期计算星期的方法!
5,显示当前指定日期的月历
void displayCalendar(int y, int m, int currentDay)
{
printf("\033[33m================== %4d 年 %2d 月 =================\033[0m\n", y,m);
printf("日\t一\t二\t三\t四\t五\t六\n");
printf("--------------------------------------------------\n");//6*6+2*7
int first_day = dayOfWeek(y, m, 1); //获取每月1号是周几
int ofday = daysInMonth(y, m); //获取一个月有多少天
int count = first_day;
for (int i = 0; i <= ofday; i++)
{
//使日期能对齐对应的星期
if (i == 0)
{
for (int j = 0; j < count % 7; j++)
{
printf("\t");
}
}
else if (i == currentDay)
{
//突出显示日期(当m等于要查询的时间或等于当前的时间)
if (m == month || m == month1)
{
printf("\033[31m%2d\033[0m\t", i);
count++;
}
else
{
printf("%2d\t", i);
count++;
}
}
else
{
printf("%2d\t", i);
count++;
}
//循环打印一周后换行
if (count % 7 == 0)
{
printf("\n");
}
}
printf("\n");
}
参数中的currentDay表示需要进行突出显示的日期。
月历打印格式的逻辑:
① 获取到每个月的一号是星期几和每个月共有多少天,一号是周几则在前面打印对应数量的制表符或空格;
② 使用一个变量记录一号是周几,每当打印一天的时候这个变量则进行自增++,当到周日(7)时则进行换行后再打印日期,直到一个月中所有天数都打印完成。
③ 在打印所有的天数中可进行判断当前要打印的天数是否等于currentDay,如果等于则进行突出显示,不等于则进行普通打印。
6,显示指定年份的全年日历
void displayYearCalendar(int y)
{
int i = 0;
for (i = 1; i <= 12; i++)
{
displayCalendar(y, i, day);
printf("\n");
}
}
在循环中调用打印月历的函数即可打印出对应日期的年历
7,验证给定的日期是否有效
int isValidDate(int y, int m, int d)
{
if (y < 1900 || (m < 1 || m >12) || (d < 1 || d > daysInMonth(y, m)))
return 0;//返回0,代表格式错误
else
return 1;//返回1,代表格式正确
}
8,查询指定日期的月历并突出显示
void queryDate(int y, int m, int d)
{
int choice = 0;
int flag = isValidDate(y, m, d);
if (flag)
{
printf("请选择: \033[36m| 1.月历 - 2.年历 |\033[0m\n");
scanf("%d", &choice);
if (choice == 1)
{
displayCalendar(y, m, d);
}
else if(choice == 2)
{
//将关于日期的全局变量修改为指定的日期,在突出显示后再修改回系统值.
day = d;
month = m;
displayYearCalendar(y);
day = today->tm_mday;
month = today->tm_mon + 1;
}
else
printf("请重新选择!\n");
}
else
printf("无效的日期!\n");
}
9,重置时间为当前系统时间
void resetTime()
{
year = today->tm_year+1900;
month = today->tm_mon+1;
day = today->tm_mday;
printf("\033[31m已重置为系统时间!\033[0m\n");
}
当输入无效的日期时,将时间信息重置为初始时间(此程序为当前系统时间)。
10,将当前日期调整为新输入的日期,无效则重置时间
void adjustDate(int y, int m, int d)
{
int flag = isValidDate(y, m, d);
if (flag)
{
year = y;
month = m;
day = d;
printf("当前的时间已修改为:%d年%d月%d日\n", y, m, d);
}
else
{
printf("无效的日期!\n");
//输入日期无效则进行重置时间
resetTime();
}
}

四,全部代码
希望文章对你有所帮助。有问题和建议可评论区一起讨论!
以下代码可直接粘贴进编辑器运行。2个文件( .h 和 .c )的代码在 “全部代码” 中已经整合为一个文件。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#include<windows.h>
//菜单
void menu();
//判断给定年份是否是闰年
int isLeapYear(int y);
//这个函数用于计算返回该月的天数
int daysInMonth(int y, int m);
//这个函数用于计算给定日期是星期几
int dayOfWeek(int y, int m, int d);
//可突出显示当前指定年月的月历
void displayCalendar(int y, int m, int currentDay);
//这个函数用于显示指定年份 year 的全年日历
void displayYearCalendar(int y);
//这个函数用于验证给定的日期是否有效
int isValidDate(int y, int m, int day);
//查询指定日期的月历并突出显示
void queryDate(int y, int m, int day);
//允许用户通过键盘输入来调整日期
void adjustDate(int y, int m, int d);
//重置时间为当前系统时间
void resetTime();
//定义全局变量
time_t t;
struct tm* today;
int choice = 0;
int year, month, day;
int year1, month1, day1;
int main()
{
int year2, month2, day2;
t = time(NULL);//time(&t),获取当前时间戳(秒数)
//将时间戳(秒数)转换为 struct tm 结构体,对应本地时区
today = localtime(&t);
year = today->tm_year + 1900;//年份从1900开始
month = today->tm_mon + 1; //月份从1开始
day = today->tm_mday;
do
{
int week = dayOfWeek(year, month, day);
printf(">>>\033[36;5mNOW: %d-%d-%d · 周%d\033[0m\n", year, month, day, week);
menu();
printf("\033[1m请输入选择的操作: \033[0m");
scanf("%d", &choice);
switch (choice)
{
case 1:
//显示当前的月历,并突出显示今天的日期
displayCalendar(year, month, day);
break;
case 2:
system("cls");//清空已有内容
displayYearCalendar(year);
break;
case 3:
printf("请输入要查询的日期(YYYY MM DD): ");
scanf("%4d %2d %2d", &year1, &month1, &day1);
queryDate(year1, month1, day1);
break;
case 4:
printf("请输入修改后的日期(YYYY MM DD): ");
scanf("%4d %2d %2d", &year2, &month2, &day2);
adjustDate(year2, month2, day2);
break;
case 0:
printf("已退出万年历系统!\n");
break;
default:
printf("输入错误,请重试!\n");
break;
}
} while (choice);
return 0;
}
//菜单
void menu()
{
printf("\033[36m| 1, 获取当前日期 |\033[0m\n");
printf("\033[36m| 2, 显示全年日历 |\033[0m\n");
printf("\033[36m| 3, 查询日期 |\033[0m\n");
printf("\033[36m| 4, 调整日期 |\033[0m\n");
printf("\033[36m| 0, 退出 |\033[0m\n");
printf("\n");
}
//判断给定年份 year 是否是闰年
int isLeapYear(int y)
{
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0)
return 1;//闰年
else
return 0;//平年
}
//用于计算返回该月的天数
int daysInMonth(int y, int m)
{
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (m == 2 && isLeapYear(y))
{
days[2] = 29;
}
return days[m];
}
//计算给定日期的星期几
int dayOfWeek(int y, int m, int d)
{
if (m < 3)
{
m += 12;
y--;
}
int h = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
/*余数的值将是0(星期日)到6(星期六)之间的一个整数,
分别代表一周的不同天,再加1准确表示周几)*/
//h+1表示某时间是星期几
return h + 1;
}
//显示当前指定年月的月历
void displayCalendar(int y, int m, int currentDay)
{
printf("\033[33m================== %4d 年 %2d 月 =================\033[0m\n", y,m);
printf("日\t一\t二\t三\t四\t五\t六\n");
printf("--------------------------------------------------\n");//6*6+2*7
int first_day = dayOfWeek(y, m, 1);//获取每月1号的周数
int ofday = daysInMonth(y, m);//获取一个月有多少天
int count = first_day;
for (int i = 0; i <= ofday; i++)
{
//使日期能对齐对应的星期
if (i == 0)
{
for (int j = 0; j < count % 7; j++)
{
printf("\t");
}
}
else if (i == currentDay)
{
//突出显示日期
if (m == month || m == month1)
{
printf("\033[31m%2d\033[0m\t", i);
count++;
}
else
{
printf("%2d\t", i);
count++;
}
}
else
{
printf("%2d\t", i);
count++;
}
//循环打印一周后换行
if (count % 7 == 0)
{
printf("\n");
}
}
printf("\n");
}
//这个函数用于显示指定年份的全年日历
void displayYearCalendar(int y)
{
int i = 0;
for (i = 1; i <= 12; i++)
{
displayCalendar(y, i, day);
printf("\n");
}
}
//验证给定的日期是否有效
int isValidDate(int y, int m, int d)
{
if (y < 1900 || (m < 1 || m >12) || (d < 1 || d > daysInMonth(y, m)))
return 0;//格式错误
else
return 1;//格式正确
}
//查询指定日期的月历并突出显示
void queryDate(int y, int m, int d)
{
int choice = 0;
int flag = isValidDate(y, m, d);
if (flag)
{
printf("请选择: \033[36m| 1.月历 - 2.年历 |\033[0m\n");
scanf("%d", &choice);
if (choice == 1)
{
displayCalendar(y, m, d);
}
else if(choice == 2)
{
//将关于日期的全局变量修改为指定的日期,在突出显示后再修改回系统值.
day = d;
month = m;
displayYearCalendar(y);
day = today->tm_mday;
month = today->tm_mon + 1;
}
else
printf("请重新选择!\n");
}
else
printf("无效的日期!\n");
}
//将当前日期调整为新输入的日期,无效则重置时间
void adjustDate(int y, int m, int d)
{
int flag = isValidDate(y, m, d);
if (flag)
{
year = y;
month = m;
day = d;
printf("当前的时间已修改为:%d年%d月%d日\n", y, m, d);
}
else
{
printf("无效的日期!\n");
//输入日期无效则进行重置时间
resetTime();
}
}
//重置时间为当前系统时间
void resetTime()
{
year = today->tm_year+1900;
month = today->tm_mon+1;
day = today->tm_mday;
printf("\033[31m已重置为系统时间!\033[0m\n");
getchar();
Sleep(1300);
system("cls");
}