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

来源:互联网 发布:淘宝标题带特价 编辑:程序博客网 时间:2024/06/14 07:08

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

【背景】:在我们计算截止日期、失效时期的时候,可能存在按年、按月、按天统计失效的情况。比如:当前日期是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 iMonthcout << 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

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

 

1 0
原创粉丝点击