下面是一份可直接用于实训报告的“万年历实训结果与分析——万年历推算”内容,可根据你的实际程序运行结果进行适当修改。
万年历实训结果与分析
一、实训结果
本次实训完成了一个万年历推算程序,能够根据用户输入的年份和月份,自动判断该年份是否为闰年,并正确输出该月的日历信息。程序可以显示指定月份的公历日历,包括星期排列、每月天数以及日期对应关系。
程序运行后,用户输入年份和月份,系统首先判断输入年份是否为闰年,然后确定该月份的天数,最后根据日期推算算法计算出该月1日是星期几,并按照日历格式输出完整月份信息。
例如输入:
```text
请输入年份:2024
请输入月份:2
```
程序输出结果如下:
```text
2024年2月
日 一 二 三 四 五 六
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
```
由于2024年是闰年,因此2月份有29天,程序能够正确显示。
再如输入:
```text
请输入年份:2025
请输入月份:6
```
输出结果:
```text
2025年6月
日 一 二 三 四 五 六
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 30
```
由运行结果可以看出,程序能够正确推算指定年月的日历,并按照星期顺序规范显示。
二、万年历推算原理
万年历推算的核心是确定某年某月1日是星期几,然后根据该月天数依次输出日期。
1. 闰年判断
公历闰年的判断规则如下:
1. 能被4整除但不能被100整除的年份是闰年;
2. 能被400整除的年份也是闰年;
3. 其他年份为平年。
判断公式可表示为:
```c
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
leap = 1;
else
leap = 0;
```
例如:
- 2024年能被4整除且不能被100整除,是闰年;
- 1900年能被100整除但不能被400整除,不是闰年;
- 2000年能被400整除,是闰年。
2. 每月天数确定
平年和闰年的区别主要体现在2月份:
| 月份 | 天数 |
|||
| 1月 | 31天 |
| 2月 | 平年28天,闰年29天 |
| 3月 | 31天 |
| 4月 | 30天 |
| 5月 | 31天 |
| 6月 | 30天 |
| 7月 | 31天 |
| 8月 | 31天 |
| 9月 | 30天 |
| 10月 | 31天 |
| 11月 | 30天 |
| 12月 | 31天 |
程序中通常使用数组保存每月天数:
```c
int monthDays[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (leap && month == 2)
days = 29;
else
days = monthDays[month - 1];
```
3. 星期推算方法
本次实训中可采用“累计天数法”进行星期推算。
以某一已知日期为基准,例如规定:
```text
1900年1月1日是星期一
```
然后计算从1900年1月1日到目标年份目标月份1日之间经过的总天数。
计算步骤如下:
1. 计算从1900年到目标年份前一年经过的总天数;
2. 计算目标年份中从1月到目标月份前一个月经过的天数;
3. 将总天数对7取余,得到目标月份1日对应的星期。
如果以星期日为一周第一天,则可根据余数调整输出位置。
示例公式:
```c
totalDays = 0;
for (i = 1900; i < year; i++) {
if (isLeapYear(i))
totalDays += 366;
else
totalDays += 365;
}
for (i = 1; i < month; i++) {
totalDays += getMonthDays(year, i);
}
week = (totalDays + 1) % 7;
```
`1900年1月1日`是星期一,如果用0表示星期日,1表示星期一,则:
```text
week = (totalDays + 1) % 7
```
即可得到目标月份1日的星期。
三、程序实现分析
本程序主要包括以下几个功能模块:
1. 输入模块
用于接收用户输入的年份和月份。
```c
printf("请输入年份:");
scanf("%d", &year);
printf("请输入月份:");
scanf("%d", &month);
```
为了保证程序稳定性,应对输入数据进行判断,例如月份应在1到12之间,年份应为正整数。
2. 闰年判断模块
通过函数判断某一年是否为闰年,提高程序结构清晰度。
```c
int isLeapYear(int year) {
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
return 1;
else
return 0;
}
```
3. 获取月份天数模块
根据年份和月份返回该月实际天数。
```c
int getMonthDays(int year, int month) {
int days[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (month == 2 && isLeapYear(year))
return 29;
else
return days[month - 1];
}
```
4. 星期计算模块
计算目标年月1日是星期几。
```c
int getWeekday(int year, int month) {
int totalDays = 0;
int i;
for (i = 1900; i < year; i++) {
totalDays += isLeapYear(i) ? 366 : 365;
}
for (i = 1; i < month; i++) {
totalDays += getMonthDays(year, i);
}
return (totalDays + 1) % 7;
}
```
5. 日历输出模块
根据计算出的星期位置输出空格,然后依次输出日期。
```c
void printCalendar(int year, int month) {
int days = getMonthDays(year, month);
int week = getWeekday(year, month);
int i;
printf(" %d年%d月\n", year, month);
printf("日 一 二 三 四 五 六\n");
for (i = 0; i < week; i++) {
printf(" ");
}
for (i = 1; i <= days; i++) {
printf("%-4d", i);
if ((week + i) % 7 == 0) {
printf("\n");
}
}

printf("\n");
}
```
四、测试结果分析
为了验证万年历推算的准确性,选取了多个年份和月份进行测试。
| 测试年份 | 测试月份 | 是否闰年 | 该月天数 | 测试结果 |
||:||:||
| 2024年 | 2月 | 闰年 | 29天 | 输出正确 |
| 2023年 | 2月 | 平年 | 28天 | 输出正确 |
| 2000年 | 2月 | 闰年 | 29天 | 输出正确 |
| 1900年 | 2月 | 平年 | 28天 | 输出正确 |
| 2025年 | 6月 | 平年 | 30天 | 输出正确 |
通过测试可以发现:
1. 程序能够正确区分平年和闰年;
2. 对2月份天数的处理正确;
3. 对每月1日星期的推算结果正确;
4. 日历输出格式基本整齐,符合常见日历显示习惯;
5. 程序逻辑清晰,功能模块划分合理。
特别是在测试1900年和2000年时,程序能正确处理“整百年”的特殊情况,说明闰年判断规则实现正确。
五、实训结果
通过本次万年历实训,掌握了日期推算的基本方法,理解了闰年判断、月份天数统计以及星期推算之间的关系。程序实现过程中,使用了循环、条件判断、数组和函数等基础知识,增强了对程序模块化设计的理解。
本次实训的重点是星期推算。只要确定一个可靠的基准日期,如1900年1月1日是星期一,再通过累计天数并对7取余,就可以推算出任意日期对应的星期。该方法思路清晰、实现简单,适合初学者理解和掌握。
总体来看,本次万年历程序能够完成预期功能,运行结果正确,具有一定的实用性。但程序仍有改进空间,例如可以增加输入、支持查询某一天是星期几、支持输出全年日历、增加农历或节假日显示等功能。
