C语言编写万年历,解决1582年历史问题

#include <stdio.h>

int main()
{
	int Year,Month;
	/*判断输入年份是否是闰年*/
	_Bool isLeapYear(int);
	/*判断每月天数*/
	int monthDays(int,int);
	/*判断某个日期是星期几*/
	int getWeekDay(int,int,int);
	/*判断输入年份一月一日星期几*/
	int yearstartday(int); 
	/*输出某年某月的日历*/
	void outMonthDays(int,int);
	/*输出1582年某月日历*/
	void outMonthDays1582(int,int);

	printf("请输入年份(公元前用负数表示):");
	scanf("%d",&Year);
	if(Year == 0)
	{
		printf("输入错误,没有公元零年"); 
	}else
	{
		if(Year > 0)
		{
			printf("       公元%d年日历为:\n",Year);
		}
		else{
			printf("      公元前%d年日历为:\n",-Year);
		}
		printf("=====================================\n");
		if(Year != 1582)      //为计算及表达简略,不在输出中加入修正,单独编写1582年输出函数 
		{
			for(Month=1;Month<=12;Month++)
			{
				outMonthDays(Year,Month);
			}
		}
		else
		{
			for(Month=1;Month<=12;Month++)
			{
				outMonthDays1582(Year,Month);
			}
		}
	}
	return 0;
}
	
/*判断输入年分一月一日星期几*/
int yearstartday(int Year)			
{
	int detayear,corday,weekstartday,detaday;
	detayear = Year - 2000;    //以2000年为参考计算每年一月一日星期几   2000.01.01周六 
	if(detayear>0)
	{
	   	corday = 2;           
	   	detayear -= 1;
	   	//这个corday和detayear一起解释,这是修正了一个计算错误,计算的时候2000年是闰年,应该
		//让detaday为2,又因为计算2000年以后的年份时,比如计算2020年,只需要计算到2019在内
		//要间隔多少天,一月一日不需要计算2020年内的天数对星期的影响,所以就让detayear减1
		//让corday赋值为2 
	}else{
		corday = 0;    //大于1582年小于2000年的时候不需要修正 
		if (detayear <= -418)   
		{
			corday = -3;    //大于等于0001年小于等于1582年,做一次修正 
							//1582年由于历史原因,10月少了10天,当年只有355天 
			if(detayear <= -2000)
			{
				corday = -1;   //公元零年不存在,按照计算公式,如果这一年存在的话,它应该是闰年 
			}                  //闰年每年相隔两天,剔除这两天的误差
		}
	}
	detaday = (detayear / 400) * 2 - detayear / 100 + detayear / 4 + detayear + corday;//相隔天数 
	//下面解释一下detaday计算公式的计算方式
	//平年有365天,365除以7余1;闰年有366天,366除以7余2.这样我们就可以,先取一个参考年份, 
	//然后用这个年份一月一日星期几来推算别的年份,为了计算方便,我选择2000年 
	//相隔年份里面,如果是平年,应该记为一天;如果是闰年,则应该是两天
	//(detayear / 400) * 2 - detayear / 100 + detayear / 4 这些计算出了相隔年份里有多少闰年
	// 后面detayear把不管是闰年还是平年都计算上了,那么再加上闰年有几个就可以,也就是前面的那些
	//corday做计算公式的修正,不同年份区域有不同值 
	weekstartday = (6 + detaday % 7) % 7;
	//6是2000年一月一日为周六,detaday % 7先将计算出的“相隔天数 ”进行周期处理,也可以不用,
	//即使用后面的式子:weekstartday = (6 + detaday) % 7; 
	//最后也取余7了,同样进行了周期处理 
	return weekstartday;
	//weekstartday即为一月一日周几,0代表周日 
}

/*判断闰年函数的具体实现*/
_Bool isLeapYear(int Year)     //布尔函数 
{
	if(Year%4==0 && Year%100!=0 || Year%400==0)
	{
	   return 1;
	}else
	return 0;
}

/*判断每月天数的具体实现*/
int monthDays(int Year,int Month){
	 if(Month == 1 || Month == 3 || Month == 5 || Month == 7 || Month == 8 || Month == 10 || Month == 12)
	 {
	 	return 31;
	 }else if(Month == 4 || Month == 6 || Month == 9 || Month == 11)
	 {
	    return 30;
	 }else{
	    if(isLeapYear(Year))
	    {
	       return 29;
		}else
	    return 28;
	 }
}

/*判断某年某月某号是周几的具体实现*/
int getWeekDay(int Year,int Month,int Day){
	int i,temp,weekday,Days=0;
	for(i=1;i<=Month-1;i++)
	{
		Days += monthDays(Year,i);  //也可以定义全局数组解决 
	}
	Days = Days + Day-1;           //weekstartday里面包含了开始那天,这里剔除一天 
	temp = yearstartday(Year)+Days;
	weekday = temp % 7;           //weekday即为周几,0代表周日 
	if(Year==1582&&Month>10)     //1582年10月后面少了10天,10 % 7 = 3 
	{
		weekday -= 3;
	}
	return weekday;
}

/*输出某年某月日历的具体实现*/
void outMonthDays(int Year,int Month){
	int i,j,weekday;
	printf("           %d月日历\n",Month);
	printf("  日  一  二  三  四  五  六\n");
	weekday = getWeekDay(Year,Month,1);
	for(i=0;i<weekday;i++)
	{
		printf("    ");
	}
	for(j=1;j<=monthDays(Year,Month);j++)
	{
		printf("%4d",j);
		if((j+weekday)%7==0)
		{
			printf("\n");
		}
	}
	printf("\n");
	printf("-------------------------------------\n");
}

/*输出1582年某月日历的具体实现*/
void outMonthDays1582(int Year,int Month){
	int i,j,weekday;
	printf("           %d月日历\n",Month);
	printf("  日  一  二  三  四  五  六\n");
	weekday = getWeekDay(Year,Month,1);
	for(i=0;i<weekday;i++)
	{
		printf("    ");
	}
	for(j=1;j<=monthDays(Year,Month);j++)
	{
		if(Month == 10)
		{
			if(j>4&&j<15)
			{
				//这里为空,是为了提示从4号以后删除了10天	
			}else
			{
				printf("%4d",j);
				if(j==16||j==23||j==30)   //没有再写函数约束,通过查到的日历直接定义换行 
				{
					printf("\n");
				}	
			}	
		}
		else
		{
			printf("%4d",j);
			if((j+weekday)%7==0)
			{
				printf("\n");
			}
		}
	}
	printf("\n");
	printf("-------------------------------------\n");
}

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值