Bootstrap

C语言:打印月历(日期的计算)

每行按照YYYY-MM格式输入年月,需要你按下图格式打印该月月历。处理到文件结束。(YYYY >= 2000,已知2000年1月1日是周六)

(2022年12月30日)感谢@m0_73173543 同学指出问题,以下是更正

更正的代码:

# include <stdio.h>

int M[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };

int sum(int x)
{
	int s = 0;
	for (int i = 0; i < x; i++) s += M[i];
	return s;
}

int main(void)
{
	int y, m;
	while (scanf_s("%d-%d", &y, &m) != EOF)
	{
		if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
			M[1] = 29;
		else
			M[1] = 28;

		// 改的下一行
		int days = 365 * (y - 2000) + (y-1 - 2000) / 4 - (y-1 - 2000) / 100 + (y-1 - 2000) / 400 + sum(m - 1);
		if (y != 2000) days++;
		int week = (days + 6)%7; 

		printf("\t\t\t%d-%s%d\n", y, m >= 10 ? "" : "0", m);
		printf("Sun.\tMon.\tTue.\tWen.\tTur.\tFri.\tSat.\n");
		int printEnter = week;
		while (week--) printf("\t");
		for (int i = 1; i <= M[m - 1]; i++)
		{
			printEnter++;
			printf("%d%s", i, printEnter % 7 == 0 ? "\n" : "\t");
		}
		if (printEnter % 7 != 0) printf("\n");
	}
	return 0;
}

详细说明:

1.之前的错误原因:在计算从2000至YY-1之间闰年个数的时候错了

由于是计算到YY-1,不是YY,所以把原代码中365 * (y - 2000) + (y - 2000) / 4 - (y - 2000) / 100 + (y - 2000) / 400后三个y改成y-1即可

代码:

		// 计算该月第一天是周几 已知:2000-1-1 sat
		int days = 365 * (y - 2000) + (y-1 - 2000) / 4 - (y-1 - 2000) / 100 + (y-1 - 2000) / 400 + sum(m - 1);
		if (y != 2000) days++;
		int week = (days + 6)%7; //周日就是0,正好0个tab


——————————————原分析以及错误的地方的更改——————————————

分析:

1.首先要知道这个月第一天是周几。先计算2000-1-1至这个月的上一个月的总天数days,然后加6 再mod 7就可以得到是周几(0是周日)

2.days分成两部分:一是2000YYYY-1整年天数,二是YYYY这一年的前MM-1个月天数

3.整年天数 = 365 * (y - 2000) + (y - 2000) / 4 - (y - 2000) / 100 + (y - 2000) / 400(“四年一闰百年不闰四百年又一闰”顺着口诀就写下来啦)

!!!※ 更改为( y -1 - 2000) / 4 - (y -1 - 2000) / 100 + (y -1 - 2000) / 400

注意第一个365 * (y - 2000)不改

4.整月天数用函数sum计算,而一年各个月天数已经提前存到数组M里

5.但是闰年的2月有29天,所以一上来还要先判断YYYY是闰年吗,是就把M[1]改成29(因为是多组输入,所以如果是YYYY是平年的话2月还要改回28~不然只要出现一个YYYY是闰年,之后的多组输入2月都是29天了)

6.计算完成,接下来调格式部分略。

7.但第3步有问题——

8.2000年本身是个闰年,把它当成一个整年计算时少加了1,判断一下加上就行啦。

原代码如下:(有一行不对,新代码在开头)

# include <stdio.h>

int M[] = {31,28,31,30,31,30,31,31,30,31,30,31};

int sum(int x) 
{ 
    int s = 0; 
    for (int i = 0; i < x; i++) s += M[i]; 
    return s; 
}

int main(void)
{
	int y, m;
	while (scanf_s("%d-%d", &y, &m) != EOF)
	{
		if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)
            M[1] = 29;
		else
            M[1] = 28;

		// 计算该月第一天是周几 已知:2000-1-1 sat
		int days = 365 * (y - 2000) + (y - 2000) / 4 - (y - 2000) / 100 + (y - 2000) / 400 + sum(m - 1);
		if (y != 2000) days++;
		int week = (days + 6) % 7; //周日就是0,正好0个tab

		printf("\t\t\t%d-%s%d\n", y, m >= 10 ? "" : "0", m);
		printf("Sun.\tMon.\tTue.\tWen.\tTur.\tFri.\tSat.\n");
		int printEnter = week;
		while (week--) printf("\t");
		for (int i = 1; i <= M[m - 1]; i++)
		{
			printEnter++;
			printf("%d%s", i, printEnter % 7 == 0?"\n":"\t");
		}
		if (printEnter % 7 != 0) printf("\n");
	}
	return 0;
}

;