C语言实现简单的万年历

2024-05-07 21:09:41 浏览数 (4)

前言

最近在回顾学习C语言时一些想做但没去做的练手小玩意,并且尽量不用一些便利的库函数以此来巩固基础


制作思路

首先建立一个六行七列的数组来存储日历

计算获取今年今月今日然后通过蔡勒公式来获取本月的第一天和最后一天是星期几,通过每月的第一天是星期几来确定第0行的循环从那列开始,从该行该列开始往后遍历到该月的最后一天,并建立一个相同大小的二维数组标记其位置。接着将日历数组空余部分也做标记处理。

通过按键ad来实现月份的加减,并且每次如果返回到本月则高亮显示本日所在位置。


全局变量的定义

结构体定义

struct YMD:定义了一个结构体,用于存储年、月、日的信息。

calander:一个二维数组,用于存储每个月的日历数据。

shader:另一个二维数组,用于存储每个日期的颜色信息,以便在显示时进行高亮处理。

G_nowPos:一个整数变量,用于跟踪当前日期在日历中的位置。

代码语言:c复制
struct YMD {
	int year;
	int mouth;
	int day;
};

int calander[6][7] = { 0 };
//根据坐标着色
int shader[6][7] = { 0 };
//根据Pos确定是否是本月,从而对本月本日特殊颜色输出
int G_nowPos = 0;

相关函数

计算给定年月日对应的星期几

蔡勒公式

代码语言:c复制
int dayOfWeek(int year, int month, int day) {
	//蔡勒公式
	if (month == 1 || month == 2)//判断month是否为1或2 
		year--, month  = 12;
	int c = year / 100;
	int y = year - c * 100;
	int week = y   y / 4   c / 4 - 2 * c   26 * (month   1) / 10   day - 1;
	while (week < 0)week  = 7;
	return week=week%7-1;
}

获取当前日期的年月日

首先使用了C语言的标准库函数time来获取当前时间,并且因为获取到的是从1970年1月1日到现在的秒数,所以我们需要从1970加到现在来确定今年是多少年,然后在通过对剩余天数的处理来获取到今月,最后得到的就是今天了

注意因为我们是北京时间所以需要加上八个小时的时差,并且向上取整。

代码语言:c复制
struct YMD nowDay() {
	time_t current = time(NULL);
	int mouth[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int nowDay = (current   86400 - 1) / 86400;
	int nowYear = 1970;
	int nowMouth = 1;
	while (nowDay > 365) {
		if (nowYear % 400 == 0 || (nowYear % 4 == 0 && nowYear % 100 != 0)) {
			nowDay -= 366;
			nowYear  ;
		}
		else {
			nowDay -= 365;
			nowYear  ;
		}
	}
	//printf("%d", nowYear);
	if (nowYear % 400 == 0 || (nowYear % 4 == 0 && nowYear % 100 != 0))mouth[2] = 29;
	while (nowDay > mouth[nowMouth]) {
		nowDay -= mouth[nowMouth];
		nowMouth  ;
		if (nowMouth >= 13) {
			nowMouth == 1;
			nowYear  ;
		}
	}
	struct YMD res;
	res.year = nowYear;
	res.mouth = nowMouth;
	res.day = nowDay;
	return res;
	//return nowYear * 1000   nowMouth * 10   nowDay;
}

检测按键

代码语言:c复制
void keyInput(struct YMD* day) {
	switch (_getch())
	{
	case'a':
	case'A':
	{
		if (day->mouth != 1) {
			day->mouth--;
		}
		else {
			day->year--;
			day->mouth = 12;
		}
		G_nowPos--;
		break;
	}
	case'd':
	case'D':
	{
		if (day->mouth != 12) {
			day->mouth  ;
		}
		else {
			day->year  ;
			day->mouth = 1;
		}
		G_nowPos  ;
		break;
	}
	default:
		break;
	}
}

日历和渲染初始化

代码语言:c复制
void calanderInit(struct YMD day) {
	int mouth[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (day.year % 400 == 0 || (day.year % 4 == 0 && day.year % 100 != 0))mouth[2] = 29;
	int startWeekDay = dayOfWeek(day.year, day.mouth, 1);
	int endWeekDay = dayOfWeek(day.year, day.mouth, mouth[day.mouth]);
	int lastMouthEnd = 0;
	if (day.mouth != 1) 
	{
		lastMouthEnd = mouth[day.mouth - 1];
	}
	else 
	{
		lastMouthEnd = 31;
	}
	for (int i = startWeekDay -1; i >=0; i--) 
	{
		calander[0][i] = lastMouthEnd--;
		shader[0][i] = 0;
	}
	int ForDay = 1;
	int i = 0;
	int j = startWeekDay;
	while (ForDay <= mouth[day.mouth]) 
	{
		calander[i][j] = ForDay;
		shader[i][j] = 1; //使用1的颜色代码,渲染日历时有用
		//判断是否是本月本日
		if (ForDay == day.day && G_nowPos==0)
		{
			shader[i][j] = 2;
		}
		j  ;
		if (j > 6) 
		{
			j = 0;
			i  ;
		}
		ForDay  ;
	}
	ForDay = 1;
	j = endWeekDay 1;
	while (i < 6) 
	{
		calander[i][j] = ForDay;
		j  ;
		if (j > 6) 
		{
			j = 0;
			i  ;
		}
		ForDay  ;
	}
}

显示日历

printf("33[1;1H33[2J");这是清除之前的页面用的

代码语言:c复制
void calanderShow(struct YMD day) 
{
	calanderInit(day);
	printf("33[1;1H33[2J");
	printf("M年d月      < >n", day.year, day.mouth);
	printf("一 二 三 四 五 六 日n");
	for (int i = 0; i < 6; i  ) 
	{
		for (int j = 0; j < 7; j  ) 
		{
			//printf("d ", calander[i][j]);
			switch (shader[i][j])
			{
			case 0: 
			{
				printf("d ", calander[i][j]);
				break;
			}
			case 1: 
			{
				printf("33[47;32md 33[0m", calander[i][j]);
				break;
			}
			case 2:
			{
				printf("33[47;31md 33[0m", calander[i][j]);
				break;
			}
			default:
				break;
			}
		}
		printf("n");
	}
}

主函数

代码语言:c复制
int main() 
{
	struct YMD dayTime = nowDay();
	//清除控制台光标
	printf("33[?25l");
	while (1) 
	{
		calanderShow(dayTime);
		keyInput(&dayTime);
	}
    return 0;
}

所有代码

代码语言:c复制
#include<Windows.h>
#include<stdio.h>
#include<conio.h>
#include<time.h>

struct YMD {
	int year;
	int mouth;
	int day;
};

int calander[6][7] = { 0 };
//根据坐标着色
int shader[6][7] = { 0 };
//根据Pos确定是否是本月,从而对本月本日特殊颜色输出
int G_nowPos = 0;

int dayOfWeek(int year, int month, int day) {
	//蔡勒公式
	if (month == 1 || month == 2)//判断month是否为1或2 
		year--, month  = 12;
	int c = year / 100;
	int y = year - c * 100;
	int week = y   y / 4   c / 4 - 2 * c   26 * (month   1) / 10   day - 1;
	while (week < 0)week  = 7;
	return week=week%7-1;
}

struct YMD nowDay() {
	time_t current = time(NULL);
	int mouth[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	int nowDay = (current   86400 - 1) / 86400;
	int nowYear = 1970;
	int nowMouth = 1;
	while (nowDay > 365) {
		if (nowYear % 400 == 0 || (nowYear % 4 == 0 && nowYear % 100 != 0)) {
			nowDay -= 366;
			nowYear  ;
		}
		else {
			nowDay -= 365;
			nowYear  ;
		}
	}
	//printf("%d", nowYear);
	if (nowYear % 400 == 0 || (nowYear % 4 == 0 && nowYear % 100 != 0))mouth[2] = 29;
	while (nowDay > mouth[nowMouth]) {
		nowDay -= mouth[nowMouth];
		nowMouth  ;
		if (nowMouth >= 13) {
			nowMouth == 1;
			nowYear  ;
		}
	}
	struct YMD res;
	res.year = nowYear;
	res.mouth = nowMouth;
	res.day = nowDay;
	return res;
	//return nowYear * 1000   nowMouth * 10   nowDay;
}

void keyInput(struct YMD* day) {
	switch (_getch())
	{
	case'a':
	case'A':
	{
		if (day->mouth != 1) {
			day->mouth--;
		}
		else {
			day->year--;
			day->mouth = 12;
		}
		G_nowPos--;
		break;
	}
	case'd':
	case'D':
	{
		if (day->mouth != 12) {
			day->mouth  ;
		}
		else {
			day->year  ;
			day->mouth = 1;
		}
		G_nowPos  ;
		break;
	}
	default:
		break;
	}
}

void calanderInit(struct YMD day) {
	int mouth[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	if (day.year % 400 == 0 || (day.year % 4 == 0 && day.year % 100 != 0))mouth[2] = 29;
	int startWeekDay = dayOfWeek(day.year, day.mouth, 1);
	int endWeekDay = dayOfWeek(day.year, day.mouth, mouth[day.mouth]);
	int lastMouthEnd = 0;
	if (day.mouth != 1) 
	{
		lastMouthEnd = mouth[day.mouth - 1];
	}
	else 
	{
		lastMouthEnd = 31;
	}
	for (int i = startWeekDay -1; i >=0; i--) 
	{
		calander[0][i] = lastMouthEnd--;
		shader[0][i] = 0;
	}
	int ForDay = 1;
	int i = 0;
	int j = startWeekDay;
	while (ForDay <= mouth[day.mouth]) 
	{
		calander[i][j] = ForDay;
		shader[i][j] = 1; //使用1的颜色代码,渲染日历时有用
		//判断是否是本月本日
		if (ForDay == day.day && G_nowPos==0)
		{
			shader[i][j] = 2;
		}
		j  ;
		if (j > 6) 
		{
			j = 0;
			i  ;
		}
		ForDay  ;
	}
	ForDay = 1;
	j = endWeekDay 1;
	while (i < 6) 
	{
		calander[i][j] = ForDay;
		j  ;
		if (j > 6) 
		{
			j = 0;
			i  ;
		}
		ForDay  ;
	}
}

void calanderShow(struct YMD day) 
{
	calanderInit(day);
	printf("33[1;1H33[2J");
	printf("M年d月      < >n", day.year, day.mouth);
	printf("一 二 三 四 五 六 日n");
	for (int i = 0; i < 6; i  ) 
	{
		for (int j = 0; j < 7; j  ) 
		{
			//printf("d ", calander[i][j]);
			switch (shader[i][j])
			{
			case 0: 
			{
				printf("d ", calander[i][j]);
				break;
			}
			case 1: 
			{
				printf("33[47;32md 33[0m", calander[i][j]);
				break;
			}
			case 2:
			{
				printf("33[47;31md 33[0m", calander[i][j]);
				break;
			}
			default:
				break;
			}
		}
		printf("n");
	}
}

int main() 
{
	struct YMD dayTime = nowDay();
	//清除控制台光标
	printf("33[?25l");
	while (1) 
	{
		calanderShow(dayTime);
		keyInput(&dayTime);
	}
    return 0;
}

运行截图

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

1 人点赞