zoukankan      html  css  js  c++  java
  • 每月一次、通过实现日截止日期代码

    每月一次、通过实现日截止日期代码

    【背景】:在我们计算截止日期、失效时期的时候,可能存在按年、按月、按天统计失效的情况。比方:当前日期是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 << "	 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 << "	iLeftDaysInCurMonth = " << iLeftDaysInCurMonth  //bug??
    		//<< "	iLeftDaysTotal = " << 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 << "	";
    	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 << "	";
    		}
    	}
    	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 << "	";
    		}
    
    		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 << "	";
    			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;
    }
    
    

                 【按天计算失效日期流程描写叙述】

                  第一步:确认当前月份到月末还剩余几天(记作A)。假设传入的失效天数<剩余天数,则返回原有年份、原有月份、新增天数就可以。

                                假设传入的失效天数>剩余天数。则记录下失效天数-剩余天数A的差值(记作B)。进入第二步;

                  第二步:循环判定下个月、下下个月....下Next N个月的总天数之和是否>第一步的差值,假设小于,则继续循环判定;

                                假设大于。则统计记录下当前月份、年份,并将月份减去1。并统计出循环的总天数C,进入第三步;

                  第三步:计算失效月的详细哪一天,依据B-C的值就是失效相应的那一天。

                           

                  【 注意事项】:

                  须要对月份、天数进行特殊判定。如1<=月份<=12;1<=天<=31。特定月份2月的平年、闰年处理;以及4,6,9.11 30天的处理。
            

             代码通过VS2010编译通过。測试案例都没有bug。有发现bug能够留言。一起改进完好,谢谢!

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

    作者:铭毅天下

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

    假设感觉本文对您有帮助,请点击支持一下。您的支持是我坚保持写作的最大动力。谢谢!

    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    web安全
    WCF通信架构
    WCF地址
    WCFContracts(契约)
    分布式中的王者WCF
    SOAP 介绍
    诊所管理软件
    MFC 画图CDC双缓冲
    Linux 启动、关闭、重启网络服务
    C# 除法的小数点问题
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4910458.html
Copyright © 2011-2022 走看看