C语言万年历系统打印日历,运行时月份出错,求解答

问题:农历的月份和日期出错

img

img

请问怎么修改代码解决这个问题,下面是代码。感谢帮助


```c
#include<stdio.h>
#include<stdlib.h>
#include <conio.h>
#include"string.h"
#include"math.h"
/**********************************************************************************
*                            函数声明
***********************************************************************************/
int Leap_year(int year);
int Month_Day(int year,int month);
int Year_Day(int year,int month,int day);
int Week_Day1(int year,int month,int day);
char *Week_Day2(int number);
void Menu1(int year,int month,int day);
void Menu2(int year,int month);
int Menu3(int year,int month,int day);
void Month_Display(int year,int month);
void Lunar_Calendar(int year ,int month,int day);
void Day_Display(int year,int month,int day);
/*******************************************************************************
*   函数名:闰年判断
*   入口参数:year
*   返回参数:闰年返回1 否则返回0
********************************************************************************/
int Leap_year(int year) {
    if(year%4==0&&year%100!=0||year%400==0)
        return 1;
    else
        return 0;
}
/**********************************************************************************
*  函数名:月份天数确定
*  入口参数:year,month
*  返回参数:今年该月的天数
*  调用函数:int Leap_year(int year)
**********************************************************************************/
int Month_Day(int year,int month) {
    int a[12]= {31,28,31,30,31,30,31,31,30,31,30,31}; /*定义数组确定12个月每个月的天数*/
    if(Leap_year(year))
        a[1]=29;
    return a[month-1];
}
/*************************************************************************************
*  函数名:天数查询->查询该天是今年的第几天
*  入口参数:year,month,day
*  返回参数:该天是今年的第几天
*  调用函数:day1(int year,int month)
**************************************************************************************/
int Year_Day(int year,int month,int day) {
    int i,sum=0;
    for(i=1; i<month; i++) {
        sum+=Month_Day(year,i);
    }
    sum+=day;
    return sum;
}
/****************************************************************************************
*   函数名:天数查询->查询该天是本周的第几天
*   入口参数:year,month,day
*   返回参数:返回该天是本周的第几天
*   调用函数:day2(int year,int month,int day)
****************************************************************************************/
int Week_Day1 ( int year, int month, int day ) {
    if(month ==1 || month ==2){
        year -=1 ;
        month +=12;
    }
    int number = ( day + 2 * month + 3 * ( month + 1 ) / 5 + year + year / 4 - year / 100 + year / 400 +1) % 7; //基姆拉尔森计算公式
//    printf("%d年%d月%d日,number+1=%d\n",year,month,day,number+1);
    return number; //+ 1;
}

/***********************************************************************************
*  函数名:星期查询
*  入口参数:number
*  返回参数:星期
**********************************************************************************/
char *Week_Day2(int number) {
    switch(number) {
        case 0:
            return "星期日";
        case 1:
            return "星期一";
        case 2:
            return "星期二";
        case 3:
            return "星期三";
        case 4:
            return "星期四";
        case 5:
            return "星期五";
        case 6:
            return "星期六";
        default:
            return "错误!请您重新输入。";
    }
}
/*****************************************************************************
*   函数名:菜单1年历查询->输出年,月,日,星期,农历
*   入口参数:year month day
*   调用函数:int week1(int year,int month,int day)
*             int runnian(int year)
*****************************************************************************/
void Menu1(int year,int month,int day) {
    int number=Week_Day1(year,month,day);
    if(Leap_year(year))printf("闰年");
    else printf("平年");
    printf(" %d 年  %d 月 %d 日%10s %s",year,month,day,Week_Day2(number));
    Lunar_Calendar( year , month,day);//输出当前日期的农历
}
/*******************************************************************************************
*   函数名:菜单2月历查询->生成日历格式
*   入口参数:year,month
*   调用函数:int day1(int year,int month)
*             int week1(int year,int month,int day)
*******************************************************************************************/
void Menu2(int year,int month) {
    int max,number,i,j=1;
    max=Month_Day(year,month);//计算该月总天数
    number=Week_Day1(year,month,1);
    printf("%2s%2s%2s%2s%2s%2s%2s\n","  星期日 ","  星期一 ","  星期二","  星期三 "," 星期四 ","  星期五 "," 星期六 ");
    for(i=0; i<number; i++) {
        if(number<7){
            printf("        ");
        }
    }
    while(j<=max) { //该月的天数
        printf("%8d",j);
        if(i%7==6) {
            printf("\n");
        }
        i++;
        j++;
    }
    printf("\n\n");
}
/*****************************************************************************
*  函数名:菜单3日历查询->输入参数检查
*  入口参数:year,month,day
*  返回参数 当输入无效时返回0 否则返回1
*****************************************************************************/
int Menu3(int year,int month,int day) {
    if(year<0||month<1||month>12||day<1||day>Month_Day(year,month))
        return 0;
    else
        return 1;
}
/*********************************************************************************
*  函数名:年历查询
*  入口参数:year
*  调用函数:int Leap_year(int year)
*********************************************************************************/
void Year(int year) {
    int i;
    printf("\n");
    for(i=1; i<=12; i++) {
        Month_Display(year,i);
    }
}
/*************************************************************************************
*  函数名:月历查询
*  入口参数:year,month
*  调用函数:int Leap_year(int year)
*           void x2(int year,int month)
*  输出:年月并输出日历格式
*************************************************************************************/
void Month_Display(int year,int month) {
    if(Leap_year(year))
        printf("闰年");
    else printf("平年");
    printf(" %d 年 %d 月\n\n",year,month);
    Menu2(year,month);
}
/*************************************************************************************
*   函数名:农历查询
*   入口参数:year,month,day
*   调用函数:
*************************************************************************************/
void Lunar_Calendar(int year ,int month,int day) {
    /*天干名称*/
    const char *cTianGan[] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
    /*地支名称*/
    const char *cDiZhi[] = {"子","丑","寅","卯","辰","巳","午",
                            "未","申","酉","戌","亥"
                           };
    /*属相名称*/
    const char *cShuXiang[] = {"鼠","牛","虎","兔","龙","蛇",
                               "马","羊","猴","鸡","狗","猪"
                              };
    /*农历日期名*/
    const char *cDayName[] = {"*","初一","初二","初三","初四","初五",
                              "初六","初七","初八","初九","初十",
                              "十一","十二","十三","十四","十五",
                              "十六","十七","十八","十九","二十",
                              "廿一","廿二","廿三","廿四","廿五",
                              "廿六","廿七","廿八","廿九","三十"
                             };
    /*农历月份名*/
    const char *cMonName[] = {"*","正","二","三","四","五","六",
                              "七","八","九","十","十一","腊"
                             };
    /*公历每月前面的天数*/
    const int wMonthAd[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
    /***************************************************************
    *农历数据计算方式:用十进制保存
    *例如:1、农历每个月的大小;2、今年是否有闰月,闰几月以及闰月的大小。
    用一个整数来保存这些信息就足够了。具体的方法是:用一位来表示一个月的大
    小,大月记为1,小月记为0,这样就用掉12位(无闰月)或13位(有闰月),再
    用高4位来表示闰月的月份,没有闰月记为0。比如说,2000年的信息数据是是0xC96
    化为十进制就是3222,化成二进制就是110010010110B,表示的含义是指1、2、5、8、10、11月大,其余月小
    ****************************************************************/
    /*农历数据*/
    const int wNongliData[100] = {
        2635,333387,1701,1748,267701,694,2391,133423,1175,396438
        ,3402,3749,331177,1453,694,201326,2350,465197,3221,3402
        ,400202,2901,1386,267611,605,2349,137515,2709,464533,1738
        ,2901,330421,1242,2651,199255,1323,529706,3733,1706,398762
        ,2741,1206,267438,2647,1318,204070,3477,461653,1386,2413
        ,330077,1197,2637,268877,3365,531109,2900,2922,398042,2395
        ,1179,267415,2635,661067,1701,1748,398772,2742,2391,330031
        ,1175,1611,200010,3749,527717,1452,2742,332397,2350,3222
        ,268949,3402,3493,133973,1386,464219,605,2349,334123,2709
        ,2890,267946,2773,592565,1210,2651,395863,1323,2707,265877
    };
 
    static int wCurYear,wCurMonth,wCurDay;
    static int nTheDate,nIsEnd,m,k,n,i,nBit;
    char szNongli[30], szNongliDay[10],szShuXiang[10];
    /*—取当前公历年、月、日—*/
    wCurYear = year;
    wCurMonth = month;
    wCurDay = day;
    /*—计算到初始时间1921年2月8日的天数:1921-2-8(正月初一)—*/
    /*1921年 鸡年 辛酉年*/
    nTheDate = (wCurYear-1921) * 365 + (wCurYear-1921) / 4 + wCurDay + wMonthAd[wCurMonth-1]-38;
    if((!(wCurYear % 4)) && (wCurMonth > 2)) //如今年阳历是闰年(2月有29天),而且当前月份大于2月,经历的总天数加1
        nTheDate = nTheDate + 1;
    /*–计算农历天干、地支、月、日—*/
    nIsEnd = 0;
    m = 0;
    while(nIsEnd != 1) {
        if(wNongliData[m] < 4095) //4095:111111111111 判断是否有闰月  小于则没有闰月 扣掉一个月
            k = 11;
        else
            k = 12;
        n = k;
        while(n>=0) {
            //获取wNongliData(m)的第n个二进制位的值
            nBit = wNongliData[m];
            for(i=1; i<n+1; i++) //大小月确定
                nBit = nBit/2;
            nBit = nBit % 2; //取出农历数据前12位的二进制数据
            if (nTheDate <= (29 + nBit)) { //若为1则是大月 天数有30天
                nIsEnd = 1; //大月
                break;
            }
            nTheDate = nTheDate-29-nBit;//天数
            n = n-1;
        }
        if(nIsEnd)
            break;
        m = m + 1;
    }
    wCurYear =1921 + m;
    wCurMonth =k-n + 1; //农历月份
    wCurDay = nTheDate; //农历天数
    if (k == 12) { //存在闰月
        if (wCurMonth == wNongliData[m] / 65536 + 1)//保存闰月是几月
            wCurMonth =1-wCurMonth;
        else if (wCurMonth > wNongliData[m] / 65536 + 1)
            wCurMonth = wCurMonth-1;
    }
    /*–生成农历天干、地支、属相 ==> wNongli–*/
    /************************************************************************
    * 计算公式: 天干:(农历年份-3)Mod 10
    * 地支:(农历年份-3)Mod 12
    * 生肖:(Year-3) Mod 12
    ************************************************************************/
    printf(" %s年 ",cShuXiang[(wCurYear - 4) % 12]);//属相
    printf("%s",cTianGan[(wCurYear - 4)  % 10]);//天干
    printf("%s年 ",cDiZhi[(wCurYear - 4) % 12]);//地支
    /*–生成农历月、日 ==> wNongliDay–*/
    if (wCurMonth < 1) { //闰月
        printf("闰");
        printf("%s",cMonName[-1 * wCurMonth]);//农历月份确定
        printf("月");
        printf("%s",cDayName[wCurDay]);//农历日期确定
        printf(" %s\n",Week_Day2(Week_Day1(year,month,day)));//星期的确定
    } else {
        printf("%s",cMonName[wCurMonth]);
        printf("月 ");
        printf("%s",cDayName[wCurDay]);
        printf(" %s\n",Week_Day2(Week_Day1(year,month,day)));
    }
}
/**********************************************************************
*   函数名:日历显示
*   入口参数:year,month,day
*   调用函数:void Menu1(int year,int month,int day)
**********************************************************************/
void Day_Display(int year,int month,int day) {
    printf("\n");
    Menu1(year,month,day);
}
int main( ) {
    int year,month,day,a,b,i;
    int Event,Event1,Event2;
    char name[20];
    FILE *fp;
 
    printf("            ---------------------------------------------------------------\n");
    printf("                                                                           \n");
    printf("                               欢迎进入万年历查询系统                      \n");
    printf("                                                                           \n");
    printf("            ---------------------------------------------------------------\n\n");
    while(1) {
        printf("\n\n请按任意键进入查询系统...");
        getch();
        printf("\n\n");
        printf("          1 年历 2 月历 3 日历 4 农历查询 5 退出 \n");
        printf("               请输入您的选择<1~5>,按回车键确定: ");
        scanf("%d",&b);
        /****************************************************************************************************************
        *                                        菜单选项
        ****************************************************************************************************************/
        switch(b) {
            case 1:
                printf("\n请输入您要查的年份: ");
                scanf("%d",&year);
                a=Menu3(year,1,1);//输入参数检查
                if(a==0) {
                    printf("错误!请您重新输入。\n");/*输入值异常时报错*/
                    break;
                }
                Year( year);
                /*for(i=1;i<=12;i++)
                {
                         Month_Display(year,i);
                }*/
                break;
            case 2:
                printf("\n请输入您要查的年和月,年月之间用空格隔开: ");
                scanf("%d%d",&year,&month);
                a=Menu3(year,month,1);
                if(a==0) {
                    printf("错误!请您重新输入。\n");
                    break;
                }
                Month_Display(year,month);
                break;
            case 3:
                printf("\n请输入您要查的年月日,年月日之间用空格隔开: ");
                scanf("%d%d%d",&year,&month,&day);
                a=Menu3(year,month,day);
                if(a==0) {
                    printf("错误!请您重新输入!\n");
                    break;
                }
                Day_Display(year,month,day);
                break;
            case 4:
                printf("请输入您需要查询的日期,年月日中间用空格隔开");
                scanf("%d%d%d",&year,&month,&day);
                if(month>12||day>31) {
                    printf("错误!请您重新输入\n");
                    break;
                }
                Lunar_Calendar(year,month,day);
                break;
            case 5:
                exit(0);
                break;
            default:
                printf("错误!请您重新输入!\n\n");
        }
    }
}
 

```

利用基姆拉尔森计算公式计算星期,1,2月要特殊处理,只适用3~12月
https://zhuanlan.zhihu.com/p/452911148
所以只要改函数Week_Day1 如下

int Week_Day1 ( int year, int month, int day ) {
    if(month ==1 || month ==2){
        year -=1 ;
        month +=12;
    }
    int number = ( day + 2 * month + 3 * ( month + 1 ) / 5 + year + year / 4 - year / 100 + year / 400 +1) % 7; //基姆拉尔森计算公式
//    printf("%d年%d月%d日,number+1=%d\n",year,month,day,number+1);
    return number; //+ 1;
}

楼上chuifengde 正解

如果2月以前不对,很可能和闰年的判断有关,你检查调试下。

可以借鉴下

#include<stdio.h>
int Leap_year[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31 };
int Com_year[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; 
char Week[7][5] = { "一","二","三","四","五","六","日" };
int year, month, day;
//用户输入日期
int User_Scanf()
{
    printf("请输入年-月-日:");
    while (scanf("%d-%d-%d", &year, &month, &day) != EOF)
    {
        //是否在有效范围内检查
        if (year <= 0 || year >= 10000 || month < 0 || month >= 13 || day < 0 || day >= 31)
        {
            printf("Error!\n");
            continue;
        }
        return 0;
    }
}
//打印星期
void Print_Week()
{
    printf("********************************************************\n");
    printf("\t\t\t万年历\t\t\t\n");
    for (int i = 0; i < 7; i++)
    {
        printf("%s\t", Week[i]);
    }
    printf("\n");
}
//判断闰/平年
int is_Leap_Com(int year)
{
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
    {
        return 1;//闰年
    }
    else
        return 0;//平年
}
//计算天数
int Count_Day(int year,int month,int day,int Leap_year[],int Com_year[])
{
    int sum = 0;
    //计算年天数
    if (is_Leap_Com(year) == 1)
    {
        sum += 366;//闰年
    }
    else
        sum += 365;//平年
    
    //计算月天数
    if (is_Leap_Com(year) == 1)
    {
        for (int i = 1; i <=month; i++)
        {
            sum += Leap_year[i];//闰月
        }
    }
    else
    {
        for (int i = 1; i <=month; i++)
        {
            sum += Com_year[i];//平月
        }
    }
    return sum;
}
//打印日历
void Print_Day(int num, int year, int month)
{
    int result = 0, temp = 0;
    result = num % 7;//打印空格
    for (int i = 0; i < result; i++)
    {
        printf("\t");
    }
    temp = 7 - result;//打印除空格外的日历
    if (is_Leap_Com(year) == 1)
    {
        for (int i = 1; i <=Leap_year[month]; i++)
        {
            printf("%d\t", i);
            if (i == temp || (i - temp) % 7 == 0)//判断是否换行
                printf("\n");
        }
    }
    else
    {
        for (int i = 1; i <=Com_year[month]; i++)
        {
            printf("%d\t", i);
            if (i == temp || (i - temp) % 7 == 0)
                printf("\n");
        }
    }
    printf("\n");
    printf("********************************************************\n");
}
int main()
{
    User_Scanf();//用户输入日期
    Print_Week();//打印星期
    int num=Count_Day(year,month,day, Leap_year, Com_year);计算天数
    Print_Day(num,year, month);//打印日历
    return 0;
}

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/7567265
  • 这篇博客也不错, 你可以看下C语言实现钟表,年月日时分秒实时更新。(后附函数使用方法)
  • 除此之外, 这篇博客: C语言-5月7日 从键盘输入两个整型,输出两个整型的最大值。中的 方法三:利用函数来解决: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:
    #include<stdio.h>
    int max(int a , int b)
    {
        int max = 0;
        if(a>=b){
            max = a;
        }
        else{
            max = b;
        }
        return max;
    }
    int main()
    {
        int a , b;
        scanf("%d%d",&a,&b);
        printf("max = %d\n",max(a,b));
        return 0;
    }

    如图,我输入两个数字123和234:

    输出完成

    扩展:那么如何输出三个整型值的最大值呢?

    #include<stdio.h>
    int main()
    {
        int num1;
        int num2;
        int num3;//定义三个整型值
        int max;//定义max中间变量
        printf("请输入三个整数:\n");
        scanf("%d%d%d",&num1,&num2,&num3);//从键盘上输入三个整型值
        if(num1 >= num2){
            max = num1;
        }
        else{
            max = num2;
        }
        if(max >= num3){
            printf("这三个整数中最大值为max=%d\n",max);
        }
        else{
            printf("这三个整数中最大值为num3=%d\n",num3);
        }
        return 0;

    如图,我输入123,234,456三个整型值,最终输出最大值为456.。

    输出完成

  • 您还可以看一下 刘浩老师的微信小程序从入门到实战保姆级教程课程中的 日历的小程序代码实现(一)小节, 巩固相关知识点
  • 以下回答来自chatgpt:

    很抱歉,根据您提供的代码并没有涉及到农历计算,因此无法直接判断出问题所在。请提供更加详细的代码或者提供更加具体的报错信息,以便我们能够更好地帮助您解决问题。另外,关于农历计算的参考资料可以参考一些历法算法书籍或者搜索一些开源的农历计算工具,例如liblunar等。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^