每月一次、通过实现日截止日期代码
【背景】:在我们计算截止日期、失效时期的时候,可能存在按年、按月、按天统计失效的情况。比方:当前日期是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
假设感觉本文对您有帮助,请点击‘顶’支持一下。您的支持是我坚保持写作的最大动力。谢谢!
版权声明:本文博主原创文章。博客,未经同意不得转载。