寻找计算指定月份首日的正确算法以修复C语言日历程序错误
日历程序修复方案
现有代码核心问题
- 闰年判定错误:
get_first_weekDay函数中遍历年份判断闰年时,误将输入的year作为判断对象,而非循环变量i,导致所有年份的闰年统计完全错误。 - 前序月份天数统计错误:计算目标月份首日之前的总天数时,错误累加了当前月份的天数,且传参时仅传入了从目标月份开始的数组切片,读取前序月份天数时越界。
- 基准值与计算逻辑不匹配:原设定1800年1月1日对应基准值
beginning=3(对应表头中周三的偏移量),但错误的累加逻辑导致最终偏移值计算错误。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> // 修复后的计算首日星期几函数 int get_first_weekDay(int year, int target_month, int monthDays[]) { int total_days = 0; // 基准值:1800年1月1日是周三,对应表头Sun(0)的偏移为3 int beginning = 3; // 累加目标月份之前所有月份的天数 for(int i = 0; i < target_month; i++) { total_days += monthDays[i]; } // 累加1800到输入年份前一年的总天数 for (int i = 1800; i < year; i++) { if ((i % 4 == 0 && i % 100 != 0) || i % 400 == 0) { beginning += 366; } else { beginning += 365; } } return (beginning + total_days) % 7; } int main(int argc, char* argv[]) { if(argc != 3) { printf("Usage: ./calendar year month \n"); return 1; } int year = atoi(argv[1]); int target_month = atoi(argv[2]) - 1; int day = 0, dayInMonth, weekDay = 0, startingDay, month; char *months[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; int monthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31}; // 处理闰年二月 if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { monthDays[1] = 29; } // 传入完整的月份天数数组 startingDay = get_first_weekDay(year, target_month, monthDays); for(month = 0; month < 12; month++) { if(target_month == month) { dayInMonth = monthDays[month]; printf(" %s %d \n ---------------------------", months[month], year); printf("\n Sun Mon Tue Wed Thu Fri Sat\n"); for(weekDay = 0; weekDay < startingDay; weekDay++) { printf(" "); } for(day = 1; day <= dayInMonth; day++) { printf("%4d", day); if(++weekDay > 6) { printf("\n"); weekDay = 0; } } } } printf("\n"); return 0; }
更高效的实现:蔡勒公式
如果不需要限制从1800年开始累加,可以使用专门计算星期几的蔡勒公式,代码更简洁且效率更高,不需要循环累加年份和月份:
// 蔡勒公式实现,返回值0=周日,1=周一...6=周六 int zeller(int year, int month) { if (month < 3) { month += 12; year--; } int c = year / 100; int y = year % 100; int m = month; int d = 1; int week = (y + y/4 + c/4 - 2*c + 26*(m+1)/10 + d - 1) % 7; // 处理负数结果 return week < 0 ? week +7 : week; }
直接替换get_first_weekDay函数调用即可使用。
内容的提问来源于stack exchange,提问作者Hyakkimaru
相关产品推荐
相关产品推荐

