日期的计算虽不是一个难题,却也算是比较繁琐的,经常会在一些公司的笔试题中出现。日期计算的关键是要把特殊情况考虑周全,如闰年。下面就对一些常见的计算日期的相关函数进行讨论。先从简单的函数谈起,然后再考虑复杂点的函数,后面的函数会调用前面的函数。
1、判断输入的年份是否是闰年。
一年是闰年时,该年的2月会是29天,否则是28天。
闰年有两种情况:
(1) 该年可以被400整除,如2000年、2400年等。
(2)该年可以被4整除,但不能被100整除,如2004年、2008年。
从以上两种情况可以得知,2100年、2200年和2300年并不是闰年。
计算闰年的代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/******************************************************************************/
/* 函数名称:IsLeapYear */
/* 功能说明:判断输入的年份是否是闰年 */
/* 闰年有2种情况:(1)可以被400整除的正整数 */
/* (2)不能被100整除,但可以被4整除的正整数 */
/* 只对公元后的年份进行处理,否则抛出异常 */
/* 参 数: */
/* iYear -- 输入的年份 */
/* 返 回 值: */
/* ture -- 输入是闰年时 */
/* false -- 输入不是闰年时 */
/******************************************************************************/
bool IsLeapYear(int iYear)
{
/*检查输入的年份是否合法*/
if (iYear < 1)
{
throw -1;
}
/*判断输入的年份是否是闰年*/
if ((0 == (iYear%400))
|| ((0 != (iYear%100)) && (0 == (iYear%4))))
{
return true;
}
else
{
return false;
}
}
/* 函数名称:IsLeapYear */
/* 功能说明:判断输入的年份是否是闰年 */
/* 闰年有2种情况:(1)可以被400整除的正整数 */
/* (2)不能被100整除,但可以被4整除的正整数 */
/* 只对公元后的年份进行处理,否则抛出异常 */
/* 参 数: */
/* iYear -- 输入的年份 */
/* 返 回 值: */
/* ture -- 输入是闰年时 */
/* false -- 输入不是闰年时 */
/******************************************************************************/
bool IsLeapYear(int iYear)
{
/*检查输入的年份是否合法*/
if (iYear < 1)
{
throw -1;
}
/*判断输入的年份是否是闰年*/
if ((0 == (iYear%400))
|| ((0 != (iYear%100)) && (0 == (iYear%4))))
{
return true;
}
else
{
return false;
}
}
2、得到一年中的天数。
通过判断该年是不是闰年,就能得到该年的天数,闰年一年为366天,其他为365天。
计算一年的天数的代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/******************************************************************************/
/* 函数名称:GetDayCntOfYear */
/* 功能说明:得到输入年份的一年中的天数 */
/* 只对公元后的年份进行处理,否则抛出异常 */
/* 参 数: */
/* iYear -- 输入的年份 */
/* 返 回 值: */
/* 366 -- 输入是闰年时 */
/* 365 -- 输入不是闰年时 */
/******************************************************************************/
int GetDayCntOfYear(int iYear)
{
/*检查输入的年份是否合法*/
if (iYear < 1)
{
throw -1;
}
int iDayCnt = 0;
if (IsLeapYear(iYear))
{
iDayCnt = 366;
}
else
{
iDayCnt = 365;
}
return iDayCnt;
}
/* 函数名称:GetDayCntOfYear */
/* 功能说明:得到输入年份的一年中的天数 */
/* 只对公元后的年份进行处理,否则抛出异常 */
/* 参 数: */
/* iYear -- 输入的年份 */
/* 返 回 值: */
/* 366 -- 输入是闰年时 */
/* 365 -- 输入不是闰年时 */
/******************************************************************************/
int GetDayCntOfYear(int iYear)
{
/*检查输入的年份是否合法*/
if (iYear < 1)
{
throw -1;
}
int iDayCnt = 0;
if (IsLeapYear(iYear))
{
iDayCnt = 366;
}
else
{
iDayCnt = 365;
}
return iDayCnt;
}
3、得到指定日期是该年中的第几天
要得到指定日期中是概念中的第几天,先要得到该年中的每个月的天数。然后根据输入的月份和日子累加得到输入日期对应的天数。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/******************************************************************************/
/* 函数名称:GetDayIdxOfYear */
/* 功能说明:得到指定日期是该年的第几天,起始值为1 */
/* 只对公元后的正常日期进行处理,否则抛出异常 */
/* 参 数: */
/* iYear -- 输入的年份 */
/* iMonth -- 输入的月份 */
/* iDay -- 输入的日子 */
/* 返 回 值: */
/* 输入日期在改天中的第几天 */
/******************************************************************************/
int GetDayIdxOfYear(int iYear, int iMonth, int iDay)
{
/*检查输入的年份是否合法*/
if (iYear < 1)
{
throw -1;
}
/*检查输入的月份是否合法*/
if ((iMonth < 1) || (iMonth > 12))
{
throw -1;
}
int iDaysOfYear = 0;
/*得到该年的每个月的天数*/
int iarrDayCntOfMonth[13] = {0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
if (IsLeapYear(iYear))
{
iarrDayCntOfMonth[2] = 29;
}
/*判断输入的日子是否合法*/
if ((iDay < 1) || (iDay > iarrDayCntOfMonth[iMonth]))
{
throw -1;
}
/*累加得到输入日期是在该年的第几天*/
for (int iMonthIdx = 1; iMonthIdx < iMonth; iMonthIdx++)
{
iDaysOfYear += iarrDayCntOfMonth[iMonthIdx];
}
iDaysOfYear += iDay;
return iDaysOfYear;
}
/* 函数名称:GetDayIdxOfYear */
/* 功能说明:得到指定日期是该年的第几天,起始值为1 */
/* 只对公元后的正常日期进行处理,否则抛出异常 */
/* 参 数: */
/* iYear -- 输入的年份 */
/* iMonth -- 输入的月份 */
/* iDay -- 输入的日子 */
/* 返 回 值: */
/* 输入日期在改天中的第几天 */
/******************************************************************************/
int GetDayIdxOfYear(int iYear, int iMonth, int iDay)
{
/*检查输入的年份是否合法*/
if (iYear < 1)
{
throw -1;
}
/*检查输入的月份是否合法*/
if ((iMonth < 1) || (iMonth > 12))
{
throw -1;
}
int iDaysOfYear = 0;
/*得到该年的每个月的天数*/
int iarrDayCntOfMonth[13] = {0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
if (IsLeapYear(iYear))
{
iarrDayCntOfMonth[2] = 29;
}
/*判断输入的日子是否合法*/
if ((iDay < 1) || (iDay > iarrDayCntOfMonth[iMonth]))
{
throw -1;
}
/*累加得到输入日期是在该年的第几天*/
for (int iMonthIdx = 1; iMonthIdx < iMonth; iMonthIdx++)
{
iDaysOfYear += iarrDayCntOfMonth[iMonthIdx];
}
iDaysOfYear += iDay;
return iDaysOfYear;
}
4、计算两输入年之间的天数
从起始年的1月1日开始算起,到终止年的12月31日为止。
先计算两年之年的年数,然后以365天计算天数;
再计算两年之间的闰年数,然后补出闰年多出的天数。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/******************************************************************************/
/* 函数名称:GetDayDif */
/* 功能说明:得到两个指定年之间的天数 */
/* 从EarlyYear年1月1日算起,到iLaterYear年12月31日止 */
/* 终止年必须大于起始年 */
/* 参 数: */
/* iEarlyYear -- 起始年 */
/* iLateYear -- 终止年 */
/* 返 回 值: */
/* 两个输入年之间的天数 */
/******************************************************************************/
int GetDayDif(int iEarlyYear, int iLaterYear)
{
if (iEarlyYear > iLaterYear)
{
throw -1;
}
/*以365年计算,两个输入年之间的天数*/
int iDayDif = (iLaterYear-iEarlyYear+1) * 365;
/*计算两个输入年之间的的闰年次数*/
int iEarlyLeapCnt = (iEarlyYear/4) - (iEarlyYear/100) + (iEarlyYear/400);
int iLaterLeapCnt = (iLaterYear/4) - (iLaterYear/100) + (iLaterYear/400);
int iLeapDif = iLaterLeapCnt - iEarlyLeapCnt;
/*补足闰年的天数*/
iDayDif += iLeapDif;
return iDayDif;
}
/* 函数名称:GetDayDif */
/* 功能说明:得到两个指定年之间的天数 */
/* 从EarlyYear年1月1日算起,到iLaterYear年12月31日止 */
/* 终止年必须大于起始年 */
/* 参 数: */
/* iEarlyYear -- 起始年 */
/* iLateYear -- 终止年 */
/* 返 回 值: */
/* 两个输入年之间的天数 */
/******************************************************************************/
int GetDayDif(int iEarlyYear, int iLaterYear)
{
if (iEarlyYear > iLaterYear)
{
throw -1;
}
/*以365年计算,两个输入年之间的天数*/
int iDayDif = (iLaterYear-iEarlyYear+1) * 365;
/*计算两个输入年之间的的闰年次数*/
int iEarlyLeapCnt = (iEarlyYear/4) - (iEarlyYear/100) + (iEarlyYear/400);
int iLaterLeapCnt = (iLaterYear/4) - (iLaterYear/100) + (iLaterYear/400);
int iLeapDif = iLaterLeapCnt - iEarlyLeapCnt;
/*补足闰年的天数*/
iDayDif += iLeapDif;
return iDayDif;
}
5、已知某个日期对应的星期,输入另一个日期,计算其对应的星期。
首先先计算出两个日期之间相隔的天数。
计算两个日期计算之间相隔的天数的方法是,先计算两年之间的天数,然后减去多加的天数,包括起始日期在起始年中的天数,以及终止日期在终止年中还剩的天数。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class CDate
{
public:
int iYear;
int iMonth;
int iDay;
};
/******************************************************************************/
/* 函数名称:GetDayOfWeek */
/* 功能说明:已知某天的日期,以及该天是星期几,计算出另一个输入日期是星期几 */
/* 其中,0表示星期日,1-6分别表示星期一到星期六 */
/* 参 数: */
/* dateKnown -- 已知的日期和星期 */
/* dateUnknown -- 已知日期,但星期未知 */
/* 返 回 值: */
/* dateUnKnown的日期对应的星期 */
/******************************************************************************/
int GetDayOfWeek(const CDate& dateKnown, int iKnownDayOfWeek,
const CDate& dateUnknown)
{
/*判断输入的年份是否合法*/
if (dateKnown.iYear < 1)
{
throw -1;
}
/*判断输入的月份是否合法*/
if ((dateKnown.iMonth < 1) || (dateKnown.iMonth > 12)
|| (dateUnknown.iMonth < 1) || (dateUnknown.iMonth > 12))
{
throw -1;
}
int iarrDayCntOfMonth[13] = {0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
/*判断已知星期的日期是否合法*/
if (IsLeapYear(dateKnown.iYear))
{
iarrDayCntOfMonth[2] = 29;
}
else
{
iarrDayCntOfMonth[2] = 28;
}
if ((dateKnown.iDay < 1)
|| (dateKnown.iDay > iarrDayCntOfMonth[dateKnown.iMonth]))
{
throw -1;
}
/*判断未知星期的日期是否合法*/
if (IsLeapYear(dateUnknown.iYear))
{
iarrDayCntOfMonth[2] = 29;
}
else
{
iarrDayCntOfMonth[2] = 28;
}
if ((dateUnknown.iDay < 1)
|| (dateUnknown.iDay > iarrDayCntOfMonth[dateUnknown.iMonth]))
{
throw -1;
}
/*判断已知的星期是否合法*/
if ((iKnownDayOfWeek < 0) || (iKnownDayOfWeek > 6))
{
throw -1;
}
/*用于保存两个日期之间相差的天数*/
int iDayDif = 0;
/*根据年份的前后,设定年份小的为起始年,年份大的为终止年*/
/*先得到起始年和终止年之间的天数*/
/*然后减去起始日期在该年中的天数*/
/*再减去终止日期在该年中剩余的天数*/
if (dateUnknown.iYear > dateKnown.iYear)
{
iDayDif = GetDayDif(dateKnown.iYear, dateUnknown.iYear);
iDayDif -= GetDayIdxOfYear(dateKnown.iYear, dateKnown.iMonth, dateKnown.iDay);
iDayDif -= GetDayCntOfYear(dateUnknown.iYear)
- GetDayIdxOfYear(dateUnknown.iYear, dateUnknown.iMonth, dateUnknown.iDay);
}
else
{
iDayDif = GetDayDif(dateUnknown.iYear, dateKnown.iYear);
iDayDif -= GetDayIdxOfYear(dateUnknown.iYear, dateUnknown.iMonth, dateUnknown.iDay);
iDayDif -= GetDayCntOfYear(dateKnown.iYear)
- GetDayIdxOfYear(dateKnown.iYear, dateKnown.iMonth, dateKnown.iDay);
iDayDif *= -1;
}
/*得到输入的日期的星期*/
int iUnknownDayOfWeek = (iKnownDayOfWeek + iDayDif) % 7;
if (iUnknownDayOfWeek < 0)
{
iUnknownDayOfWeek += 7;
}
return iUnknownDayOfWeek;
}
{
public:
int iYear;
int iMonth;
int iDay;
};
/******************************************************************************/
/* 函数名称:GetDayOfWeek */
/* 功能说明:已知某天的日期,以及该天是星期几,计算出另一个输入日期是星期几 */
/* 其中,0表示星期日,1-6分别表示星期一到星期六 */
/* 参 数: */
/* dateKnown -- 已知的日期和星期 */
/* dateUnknown -- 已知日期,但星期未知 */
/* 返 回 值: */
/* dateUnKnown的日期对应的星期 */
/******************************************************************************/
int GetDayOfWeek(const CDate& dateKnown, int iKnownDayOfWeek,
const CDate& dateUnknown)
{
/*判断输入的年份是否合法*/
if (dateKnown.iYear < 1)
{
throw -1;
}
/*判断输入的月份是否合法*/
if ((dateKnown.iMonth < 1) || (dateKnown.iMonth > 12)
|| (dateUnknown.iMonth < 1) || (dateUnknown.iMonth > 12))
{
throw -1;
}
int iarrDayCntOfMonth[13] = {0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
/*判断已知星期的日期是否合法*/
if (IsLeapYear(dateKnown.iYear))
{
iarrDayCntOfMonth[2] = 29;
}
else
{
iarrDayCntOfMonth[2] = 28;
}
if ((dateKnown.iDay < 1)
|| (dateKnown.iDay > iarrDayCntOfMonth[dateKnown.iMonth]))
{
throw -1;
}
/*判断未知星期的日期是否合法*/
if (IsLeapYear(dateUnknown.iYear))
{
iarrDayCntOfMonth[2] = 29;
}
else
{
iarrDayCntOfMonth[2] = 28;
}
if ((dateUnknown.iDay < 1)
|| (dateUnknown.iDay > iarrDayCntOfMonth[dateUnknown.iMonth]))
{
throw -1;
}
/*判断已知的星期是否合法*/
if ((iKnownDayOfWeek < 0) || (iKnownDayOfWeek > 6))
{
throw -1;
}
/*用于保存两个日期之间相差的天数*/
int iDayDif = 0;
/*根据年份的前后,设定年份小的为起始年,年份大的为终止年*/
/*先得到起始年和终止年之间的天数*/
/*然后减去起始日期在该年中的天数*/
/*再减去终止日期在该年中剩余的天数*/
if (dateUnknown.iYear > dateKnown.iYear)
{
iDayDif = GetDayDif(dateKnown.iYear, dateUnknown.iYear);
iDayDif -= GetDayIdxOfYear(dateKnown.iYear, dateKnown.iMonth, dateKnown.iDay);
iDayDif -= GetDayCntOfYear(dateUnknown.iYear)
- GetDayIdxOfYear(dateUnknown.iYear, dateUnknown.iMonth, dateUnknown.iDay);
}
else
{
iDayDif = GetDayDif(dateUnknown.iYear, dateKnown.iYear);
iDayDif -= GetDayIdxOfYear(dateUnknown.iYear, dateUnknown.iMonth, dateUnknown.iDay);
iDayDif -= GetDayCntOfYear(dateKnown.iYear)
- GetDayIdxOfYear(dateKnown.iYear, dateKnown.iMonth, dateKnown.iDay);
iDayDif *= -1;
}
/*得到输入的日期的星期*/
int iUnknownDayOfWeek = (iKnownDayOfWeek + iDayDif) % 7;
if (iUnknownDayOfWeek < 0)
{
iUnknownDayOfWeek += 7;
}
return iUnknownDayOfWeek;
}
6、测试的Main函数如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void main()
{
/*已知2011年7月14日,星期二*/
CDate dateKnown;
dateKnown.iYear = 2011;
dateKnown.iMonth = 7;
dateKnown.iDay = 12;
int iKnownDayOfWeek = 2;
CDate dateUnknown;
/*2016年8月15日,星期一*/
dateUnknown.iYear = 2016;
dateUnknown.iMonth = 8;
dateUnknown.iDay = 15;
cout<<GetDayOfWeek(dateKnown, iKnownDayOfWeek, dateUnknown)<<endl;
/*1999年1月1日,星期五*/
dateUnknown.iYear = 1999;
dateUnknown.iMonth = 1;
dateUnknown.iDay = 1;
cout<<GetDayOfWeek(dateKnown, iKnownDayOfWeek, dateUnknown)<<endl;
}
{
/*已知2011年7月14日,星期二*/
CDate dateKnown;
dateKnown.iYear = 2011;
dateKnown.iMonth = 7;
dateKnown.iDay = 12;
int iKnownDayOfWeek = 2;
CDate dateUnknown;
/*2016年8月15日,星期一*/
dateUnknown.iYear = 2016;
dateUnknown.iMonth = 8;
dateUnknown.iDay = 15;
cout<<GetDayOfWeek(dateKnown, iKnownDayOfWeek, dateUnknown)<<endl;
/*1999年1月1日,星期五*/
dateUnknown.iYear = 1999;
dateUnknown.iMonth = 1;
dateUnknown.iDay = 1;
cout<<GetDayOfWeek(dateKnown, iKnownDayOfWeek, dateUnknown)<<endl;
}