按月、按天计算失效日期的代码实现

按月、按天计算失效日期的代码实现

【背景】:在我们计算截止日期、失效时期的时候,可能存在按年、按月、按天统计失效的情况。比如:当前日期是2014-12-22,900天后失效,失效日期是多少?17个月后失效,失效日期是多少。通过本文源码,你都可以得到答案。

为验证程序的正确性,本文对每个接口函数都做了大量的测试用例。

// sn_ctrl.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <assert.h>
#include <iostream>
using namespace std;

const int MAX_MONTH_CNTS_IN_YEAR = 12;

/*
**@brief:判定年份是否为闰年.
**@param: iYear当前年份.
**@return:true,闰年; false,平年.
*/
bool IsLeapYear(unsigned int iYear)
{
	if ( (iYear%4 == 0 && iYear%100 != 0) || (iYear%400 == 0) )
	{
		return true;
	}
	else
	{
		return false;
	}
}

/*
**@brief:判定某年某月的天数.
**@param: iYear当前年份,iMonth当前月份;
**@return:当前年、月的天数.
*/
unsigned int daysInMonth(unsigned int iYear, unsigned int iMonth)
{
	assert(iMonth >=1 && iMonth <= MAX_MONTH_CNTS_IN_YEAR);
	int iDaysInMonth = 0;
	switch(iMonth)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			iDaysInMonth = 31;
		break;
		case 4:
		case 6:
		case 9:
		case 11:
			iDaysInMonth = 30;
		break;
		case 2:
			if (IsLeapYear(iYear))
			{
				iDaysInMonth = 29;
			}
			else
			{
				iDaysInMonth = 28;
			}
		break;
		default:
			cout << "Error Month!!" << endl;
			break;
	}
	return iDaysInMonth;
}

struct Date
{
	unsigned int date_year;
	unsigned int date_month;
	unsigned int date_day;
};

class DateOp
{
public:
	DateOp(){}
	DateOp(Date thisDate):theDate(thisDate){}
	virtual ~DateOp(){}
	Date DataAddmonths(Date date_init, unsigned int month_cnts);
	Date DateAddDays(Date date_init, unsigned int day_cnts);

private:
	Date theDate;
};

/*
**@brief:初始月份加几个月后的日期.
**@param: dateInit初始日期,iMonthCnts过几个月;
**@return:计算后的新的日期.
*/
Date DateOp::DataAddmonths(Date dateInit, unsigned int iMonthCnts)
{
	assert (iMonthCnts >= 1);
	Date dateAfterAdd = dateInit;

	unsigned int iMonthNewPos = dateInit.date_month + iMonthCnts;
	if (iMonthNewPos > MAX_MONTH_CNTS_IN_YEAR)  //求和后超过12
	{
		unsigned int iYearCnts = (iMonthNewPos)/(MAX_MONTH_CNTS_IN_YEAR);
		unsigned int iMonthNew = (iMonthNewPos)%(MAX_MONTH_CNTS_IN_YEAR);
		if (0 == iMonthNew) //月份为0特殊处理
		{
			dateAfterAdd.date_year = dateInit.date_year + iYearCnts -1;
			iMonthNew = 12;
		}
		else
		{
			dateAfterAdd.date_year = dateInit.date_year + iYearCnts;
		}
		dateAfterAdd.date_month = iMonthNew;

	}
	else  //求和后不超过12
	{
		dateAfterAdd.date_year = dateInit.date_year;
		dateAfterAdd.date_month = dateInit.date_month + iMonthCnts;
	}

	//2月份特殊处理
	if ( (30 == dateInit.date_day || 31 == dateInit.date_day) && (2 == dateAfterAdd.date_month))
	{
		dateAfterAdd.date_day = daysInMonth(dateAfterAdd.date_year, dateAfterAdd.date_month);
	}
	//30天的月份特殊处理
	else if ((31 == dateInit.date_day) && ((4 == dateAfterAdd.date_month) || (6 == dateAfterAdd.date_month) ||
		     (9 == dateAfterAdd.date_month) || (11 == dateAfterAdd.date_month)))
	{
		dateAfterAdd.date_day = 30;
	}
	else
	{
		dateAfterAdd.date_day = dateInit.date_day;
	}
	return dateAfterAdd;
}

/*
**@brief:初始月份加*天后的日期.
**@param: dateInit初始日期,iMonthCnts过多少天;
**@return:计算后的新的日期.
*/
Date DateOp::DateAddDays(Date dateInit, unsigned int day_cnts)
{
	assert(day_cnts >= 1);
	cout << "+ " << day_cnts << endl;
	Date dateAfterAdd = dateInit;

	unsigned int iCurDaysInMonth = daysInMonth(dateInit.date_year, dateInit.date_month); //当前月的总天数.
	//cout << "iCurDaysInMonth = " << iCurDaysInMonth << endl;
	int iDayTotal = day_cnts;
	if (dateInit.date_day + day_cnts <= iCurDaysInMonth)
	{
		dateAfterAdd.date_day = dateInit.date_day + day_cnts;
		return dateAfterAdd;
	}

	int iLeftDaysInCurMonth = iCurDaysInMonth - dateInit.date_day; //当前月剩余天数.
	//cout << endl << "iDayTotal = " << iDayTotal << "\t iLeftDayInCurmonth = " << iLeftDaysInCurMonth << endl << endl;
	//cout << "iAvgMonthCnts = " << iAvgMonthCnts << endl << endl;

	unsigned int iDaysInMonth = 0;
	int iLeftDaysTotal = 0;  //统计大约几个月的实际总天数.
	unsigned int iMonthCnts = 0;
	while (iLeftDaysTotal <= iDayTotal - iLeftDaysInCurMonth)
	{
		++iMonthCnts;
		unsigned int iCurMonth = dateInit.date_month + iMonthCnts;
	// cout << "iCurMonth = " << iCurMonth << endl;
		unsigned int iYearCnts = 0;
		if (iCurMonth > 12)
		{
			iYearCnts = (iCurMonth)/(MAX_MONTH_CNTS_IN_YEAR);
		}

		//cout << "iYearCnts = " << iYearCnts << endl;

		if (0 == iYearCnts)
		{
			dateAfterAdd.date_year = dateInit.date_year;
			dateAfterAdd.date_month = iCurMonth;
			iDaysInMonth = daysInMonth(dateInit.date_year, iCurMonth);
			iLeftDaysTotal += iDaysInMonth;
		}
		else
		{
			unsigned int iMonthNew = (iCurMonth)%(MAX_MONTH_CNTS_IN_YEAR);
			if (0 == iMonthNew) //月份为0特殊处理
			{
				dateAfterAdd.date_year = dateInit.date_year + iYearCnts -1;
				iMonthNew = 12;
			}
			else
			{
				dateAfterAdd.date_year = dateInit.date_year + iYearCnts;
			}
			dateAfterAdd.date_month = iMonthNew;
			iDaysInMonth = daysInMonth(dateAfterAdd.date_year, iMonthNew);
			iLeftDaysTotal += iDaysInMonth;

		}//end else
		//对于超出的做特殊处理.
		if (iLeftDaysTotal > (iDayTotal - iLeftDaysInCurMonth))
		{
			iLeftDaysTotal -= iDaysInMonth;
			break;
		}
	}

	//cout << "iDayTotal  =" << iDayTotal << "\tiLeftDaysInCurMonth = " << iLeftDaysInCurMonth  //bug??
		//<< "\tiLeftDaysTotal = " << iLeftDaysTotal << endl;
	if (iDayTotal - iLeftDaysInCurMonth - iLeftDaysTotal < 0)
	{
		dateAfterAdd.date_day = iDayTotal - iLeftDaysInCurMonth;
	}
	else
	{
		dateAfterAdd.date_day = iDayTotal - iLeftDaysInCurMonth - iLeftDaysTotal;
	}

	if (dateAfterAdd.date_month > 12)
	{
		dateAfterAdd.date_year += 1;
		dateAfterAdd.date_month = 1;
	}
	if (dateAfterAdd.date_day == 0)
	{
		if (1 == dateAfterAdd.date_month)
		{
			dateAfterAdd.date_month = 12;
			dateAfterAdd.date_year -= 1;
		}
		else
		{
			dateAfterAdd.date_month -= 1;
		}

		dateAfterAdd.date_day = daysInMonth(dateAfterAdd.date_year, dateAfterAdd.date_month);
	}
	assert((dateAfterAdd.date_month >= 1) && (dateAfterAdd.date_month <= 12));
	assert((dateAfterAdd.date_day >= 1) && (dateAfterAdd.date_day <= 31));
	return dateAfterAdd;
}

/*
**@brief:打印日期格式.
**@param: theDate提供打印的日期
**@return:空.
*/
void DisplayDate(Date& theDate)
{
	cout << theDate.date_year << "/" << theDate.date_month
		 << "/" << theDate.date_day << "\t";
	cout << endl << endl;
}

/*
**@brief:测试用例:测试某年是否为闰年.
**@param: 空.
**@return:空.
*/
void testLeapYearOrNot()
{
	unsigned int iBeginYear=1900;
	unsigned int iEndYear=3000;

	cout << "From " << iBeginYear << " To " << iEndYear << endl;

	for (unsigned int iYear = iBeginYear; iYear <= iEndYear; ++iYear)
	{
		if (IsLeapYear(iYear))
		{
			cout << iYear << "\t";
		}
	}
	cout << endl;
}

/*
**@brief:单元测试用例,某年某月有多少天.
**@param: 空.
**@return:空.
*/
void testDaysInMonth()
{
	unsigned int iBeginYear = 1980;
	unsigned int iEndYear = 2020;
	unsigned int iBeginMonth = 1;
	unsigned int iEndMonth = 12;
	unsigned int iDaysOfYear = 0;

	for (unsigned int iYear = iBeginYear; iYear <= iEndYear; ++iYear)
	{
	    iDaysOfYear = 0;
		cout << "Year:" << iYear << endl;
		for (unsigned int iMonth = iBeginMonth; iMonth <= iEndMonth; ++iMonth)
		{

			unsigned int iDaysInmonth = daysInMonth(iYear,iMonth);
			iDaysOfYear += iDaysInmonth;
			cout << iDaysInmonth << "\t";
		}

		cout << endl;
		cout << iYear << " has " << iDaysOfYear << " days!" << endl << endl;
	}
}

/*
**@brief:单元测试用例,测试几个月后日期.
**@param: 空.
**@return:空.
*/
void testDataAddmonths()
{
	unsigned int iBeginYear = 2014;
	unsigned int iEndYear = 2015;

	unsigned int iBeginMonths = 1;
	unsigned int iEndMonths = 30;

	Date beginDate;
	beginDate.date_year = 1980;
	beginDate.date_month = 1;
	beginDate.date_day = 31;
	Date endDate = beginDate;
	DateOp dateOp;

	for (unsigned int iYear = iBeginYear; iYear <= iEndYear; ++iYear)
	{
		beginDate.date_year = iYear;
		(void)DisplayDate(beginDate);
		cout << endl;
		for (unsigned int iMonth = 1; iMonth <= MAX_MONTH_CNTS_IN_YEAR; ++iMonth)
		{
			beginDate.date_month = iMonth;
			cout << iMonth << "\t";
			for (unsigned int iMonthCnts = iBeginMonths; iMonthCnts <= iEndMonths; ++iMonthCnts)
			{
				endDate = dateOp.DataAddmonths(beginDate, iMonthCnts);
				cout << " +" << iMonthCnts << " ";
				(void)DisplayDate(endDate);
			}//end for iMonthCnts;
			cout << endl << endl;
		}//end for iMonth
		cout << endl << endl << endl;
	}//end for iYear
}

/*
**@brief:单元测试用例,测试给定天后的日期.
**@param: 空.
**@return:空.
*/
void testDataAddDays()
{
	Date beginDate;
	beginDate.date_year = 1988;
	beginDate.date_month = 7;
	beginDate.date_day = 19;

	DateOp dateOp;
	cout << "Init Date is :" << endl;
	(void)DisplayDate(beginDate);

	Date endDate = beginDate;

	endDate = dateOp.DateAddDays(beginDate, 1); //1988-7-20
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 12); //1988-7-31
	(void)DisplayDate(endDate); 

	endDate = dateOp.DateAddDays(beginDate, 13); //1988-8-1
	(void)DisplayDate(endDate); 

	endDate = dateOp.DateAddDays(beginDate, 100); //1988-10-27
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 200); //1989-2-4
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 500); //1989-12-1
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 954); //1991-2-28
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 955); //1991-3-1
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 1000); //1991年4月15日星期一
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 2000); //1994年1月9日星期日
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 5000); //2002年3月28日星期四
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 10000); //2015年12月5日星期六
	(void)DisplayDate(endDate);

	endDate = dateOp.DateAddDays(beginDate, 20000); //2043年4月22日星期三
	(void)DisplayDate(endDate);

}

int _tmain(int argc, _TCHAR* argv[])
{
	Date thisDate;
	thisDate.date_year = 2014;
	thisDate.date_month = 2;
	thisDate.date_day = 21;

	Date endDate = thisDate;

	DateOp thisDateOp(thisDate);
	(void)DisplayDate(thisDate);

	//不同类型用例测试.
	(void)testLeapYearOrNot();
	(void)testDaysInMonth();
	(void)testDataAddmonths();
	(void)testDataAddDays();
	return 0;
}

代码通过VS2010编译通过,测试案例都没有bug。有发现bug可以留言,一起改进完善,谢谢!

2014-12-23  am0:01思于家中床前

作者:铭毅天下

转载请标明出处,原文地址:http://blog.csdn.net/laoyang360/article/details/41604621

如果感觉本文对您有帮助,请点击‘顶’支持一下,您的支持是我坚持写作最大的动力,谢谢!

时间: 2024-10-10 13:21:30

按月、按天计算失效日期的代码实现的相关文章

计算指定日期的前N个月日期

/**     * 计算指定日期的前N个月日期     * @param type $time      * @param int $month_length     * @return date     */    public function calLMP($time,$month_length ){        $r = date('Y-m-d',strtotime('-'.$month_length.'month',strtotime($time)));        list($e

【Java】使用switch 计算一个日期是当年的第几天

计算一个日期是当年的第几天 这是去年做的一个Java题目,老师当时说这段代码里的switch用的很好. 现在工作一年了,明显感觉当时还很稚嫩,那个时候考虑问题很简单, 现在遇到问题会想更多的方面,说到这里,真的要谢谢带我的经理, 这段时间真的学到很多东西,每天都是在解决问题,每天都能学到新东西, 短短几个月时间进步了好多. 1 import java.util.Scanner; 2 3 /** 4 * 计算一个日期是当年的第几天 5 */ 6 public class CountDays { 7

用Java计算某个日期100天后的日期

用Java计算日期时间,首先考虑到时间类,Java中提供的和时间日期相关的类里,有一个Calendar类,可以获取某个时间日期. 计算某个日期100天后的日期,思路如下: 1.先设定时间,例如2017年1月1日: 2.在给定日期的天数上增加100: 具体代码如下: 1 /* 2 * 1.先给定一个时间,例如2017年1月1日 3 */ 4 Calendar cld = Calendar.getInstance(); 5 cld.set(Calendar.YEAR, 2017); 6 cld.se

JS实现——计算两日期之差

在网上找了个js实现的,根据相差天数计算日期和根据两个日期计算相差多少天的示例和代码: 根据相差天数计算日期: 距离: 年 月 日 (缺省为今天) 相差: 天 (输入负数则往前计算) 日期是:   根据日期计算相差天数: 开始日期: 年 月 日 结束日期: 年 月 日 相差天数:   实现代码如下: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content=&qu

iOS之计算上次日期距离现在多久, 如 xx 小时前、xx 分钟前等

/**  *  计算上次日期距离现在多久  *  *  @param lastTime    上次日期(需要和格式对应)  *  @param format1     上次日期格式  *  @param currentTime 最近日期(需要和格式对应)  *  @param format2     最近日期格式  *  *  @return xx分钟前.xx小时前.xx天前  */ + (NSString *)timeIntervalFromLastTime:(NSString *)lastT

输入年份,月份,日期计算该日期是一年中的第几天//雪碧和可乐temp

输入一个整数day代表星期几,根据day的值输出对应的星期几,比如day==1,就输出"星期一"(用两种方式实现) int day; printf("请输入1~7的数字"); scanf("%d",&day); if(day>0&&day<8) { //多重if...else if条件分支实现 if(day==1){ printf("星期一"); }else if(day==2){ prin

MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数

MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数 计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数,这里主要分享的是通过MySql内置的函数 TimeStampDiff() 实现. 函数 TimeStampDiff() 是MySQL本身提供的可以计算两个时间间隔的函数,语法为: TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) 返回日期或日期时间表达式datetime_expr1 和datetime_expr2the 之

关于计算两日期之间经过多少天的超巧妙算法

首先声明:本文引自一博主原创博客 原创地址:https://blog.csdn.net/chinaeran/article/details/43601699 昨天呢,刚刚阅读了这个代码,大部分都还可以看懂,有一两个地方属实难懂,但细细思来,方知博主此代码超神奇.简直巧妙至极. 所以来细细解析一下此代码. 话不多说.我们先来看一下原文. #include <stdio.h>#include <stdlib.h> int day_diff(int year_start, int mon

java计算两日期间隔小时或分钟

public static void main(String[] args) {        try {            long min = dateDiff("2014-05-27 13:30:00","2014-05-27 13:00:00","yyyy-MM-dd HH:mm:ss");            System.out.println("---------相隔分钟数: "+min);