两个日期之间相差的天数——C语言实现

前言

今天我们来看一道我个人认为很有意思的题,乍一看好像很简单,却有很多细微之处容易忽略。下面把我当时解题的思路展现出来,其实算法并不难,只是当初第一次做的时候花了我很多时间去对每一种情况进行讨论,现在看来依然望而生畏。大佬们有任何好的解法欢迎留言到评论区![doge][doge][doge]

原题复现

两个日期之间相差天数

简要分析

首先,要求小明的出生日期和现在的日期之间相差的天数,我们很容易就想到闰年和平年的问题。其次,我们还要分析输入的两个年份是同一年还是不同年,这两种情况也是不一样的。而题目的难点就在判断使是否是闰年后天数的计算上。我们易得到以下几个问题:
1、出生年是否是闰年;
2、今年是否是闰年;
3、出生年与今年之间是否相差闰年,相差几个闰年。
其次,如果是两者是同一年,我们还要考虑是否是同一月的情况。

实现过程

假设输入的起始年、月、日分别为y1、m1、d1,输入的终止年、月、日分别为y2、m2、d2。即以y1-m1-d1 y2-m2-d2的形式输入,并设总天数为D。(即要求的天数为D)

1.判断闰年函数

由于程序中有多处涉及到闰年的判断,我们先单独封装一个用来判断是否是闰年的函数。是闰年返回1,不是闰年返回0。

int prime(int n)
{
	if ((n % 4 == 0) && (n % 100 != 0) || (n % 400 == 0))
	{
		return 1;//是闰年
	}
	else
	{
		return 0;//不是闰年
	}
}

1.设置两个数组存放闰年和平年的每月天数

这里我们设置两个大小为13的数组,是为了方便我们后面直接将月份作为数组下标来获得数组元素,每个月份正好与数组下标相对应,这种方法非常常见。

int days1[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31 };//平年每月天数
int days2[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31 };//闰年每月天数

3.求y1与y2之间相差的天数

我们先不管y1、y2这两个年份的天数,先求出y1、y2之间相差的年数并判断闰年,如果是闰年,直接D+366;如果是平年,直接D+365。

for (i = y1 + 1; i < y2; i++)//先不管y1、y2这两个年份,只看两者中间的年份
{
	if (prime(i) == 1)//是闰年
	{
		D += 366;
	}
	else//是平年
	{
		D += 365;
	}
}

4.起始年与终止年是同一年

如果起始年与终止年是同一年

①是同一月

先判断是同一年同一月的情况,则直接用终止日期减去起始日期得到相差天数。

if (y1 == y2)//输入的是同一年
{
	if (m1 == m2)
	{
		D += (d2 - d1);
	}

②是不同月

a.如果两者都是闰年

if (prime(y1) == 1)//两者都是闰年
{
	D += days2[m1] - d1;//先算出起始月当月剩余天数
	for(i = m1 + 1; i < m2; i++)
	{
		D += days2[i];//再计算起始月与终止月之间相差的天数
	}
	D += d2;//最后加上终止月当月天数
}

b.如果两者都是平年

else//两者都是平年
{
	D += days1[m1] - d1;//先算出起始月当月剩余天数
	for (i = m1 + 1; i < m2; i++)
	{
		D += days1[i];//再计算起始月与终止月之间相差的天数
	}
	D += d2;//最后加上终止月当月天数
}

5.起始年与终止年是不同年

如果起始年与终止年是不同年,其实计算思路都是一样的,只是由于平年和闰年的区别需要代入不同的数组进行运算。

①y1是闰年

if (prime(y1) == 1)//y1是闰年
{
	D += days2[m1] - d1;//先算出起始月当月剩余天数
	for (i = m1 + 1; i < 13; i++)//起始月的下一月~12月
	{
		D += days2[i];//再计算起始年当年剩余天数
	}
}

②y1是平年

else//y1是平年
{
	D += days1[m1] - d1;//先算出起始月当月剩余天数
	for (i = m1 + 1; i < 13; i++)//起始月的下一月~12月
	{
		D += days1[i];//再计算起始年当年剩余天数
	}
}

③y2是闰年

if (prime(y2) == 1)//y2是闰年
{
	D += d2;//先算出终止月当月已过的天数
	for (i = 1; i < m2; i++)//终止年的1月~终止月的上一月
	{
		D += days2[i];//再计算终止年当年已过的天数
	}
}

④y2是平年

else//y2是平年
{
	D += d2;//先算出终止月当月已过的天数
	for (i = 1; i < m2; i++)//终止年的1月~终止月的上一月
	{
		D += days1[i];//再计算终止年当年已过的天数
	}
}

完整源码

#include <stdio.h>

int prime(int n)
{
	if ((n % 4 == 0) && (n % 100 != 0) || (n % 400 == 0))
	{
		return 1;//是闰年
	}
	else
	{
		return 0;//不是闰年
	}
}

int main()
{
	int y1 = 0, m1 = 0, d1 = 0, y2 = 0, m2 = 0, d2 = 0;
	scanf("%d-%d-%d %d-%d-%d", &y1, &m1, &d1, &y2, &m2, &d2);
	int days1[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31 };//平年每月天数
	int days2[13] = {0,31,29,31,30,31,30,31,31,30,31,30,31 };//闰年每月天数
	int i = 0, D = 0;
	for (i = y1 + 1; i < y2; i++)
	{
		if (prime(i) == 1)//是闰年
		{
			D += 366;
		}
		else//是平年
		{
			D += 365;
		}
	}
	if (y1 == y2)//输入的是同一年
	{
		if (m1 == m2)
		{
			D += (d2 - d1);
		}
		else
		{
			if (prime(y1) == 1)//两者都是闰年
			{
				D += days2[m1] - d1;
				for(i = m1 + 1; i < m2; i++)
				{
					D += days2[i];
				}
				D += d2;
			}
			else//两者都是平年
			{
				D += days1[m1] - d1;
				for (i = m1 + 1; i < m2; i++)
				{
					D += days1[i];
				}
				D += d2;
			}
		}
	}
	else//不同年
	{
		if (prime(y1) == 1)//y1是闰年
		{
			D += days2[m1] - d1;
			for (i = m1 + 1; i < 13; i++)
			{
				D += days2[i];
			}
		}
		else//y1是平年
		{
			D += days1[m1] - d1;
			for (i = m1 + 1; i < 13; i++)
			{
				D += days1[i];
			}
		}
		if (prime(y2) == 1)//y2是闰年
		{
			D += d2;
			for (i = 1; i < m2; i++)
			{
				D += days2[i];
			}
		}
		else//y2是平年
		{
			D += d2;
			for (i = 1; i < m2; i++)
			{
				D += days1[i];
			}
		}
	}
	printf("%d\n", D);

	return 0;
}

总结

写完这篇博客后,我发现这道题不是难,是麻烦!其实计算思路非常简单,就是要有耐心去对每一种情况进行分析并计算,也有很多细节需要注意。
这也告诉我们,想做程序员一定要耐得住寂寞,一定要有耐心!
Patience!Patience!And patience!

  • 67
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值