天天看點

按月、按天計算失效日期的代碼實作

// 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;

 case 2:

  if (IsLeapYear(iYear))

  {

   iDaysInMonth = 29;

  }

  else

   iDaysInMonth = 28;

 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;

 dateAfterAdd.date_day = dateInit.date_day;

return dateAfterAdd;

**@brief:初始月份加*天後的日期.

**@param: dateInit初始日期,iMonthCnts過多少天;

Date DateOp::DateAddDays(Date dateInit, unsigned int day_cnts)

assert(day_cnts >= 1);

cout << "+ " << day_cnts << endl;

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;

  unsigned int iMonthNew = (iCurMonth)%(MAX_MONTH_CNTS_IN_YEAR);

  if (0 == iMonthNew) //月份為0特殊處理

   dateAfterAdd.date_year = dateInit.date_year + iYearCnts -1;

   iMonthNew = 12;

   dateAfterAdd.date_year = dateInit.date_year + iYearCnts;

  dateAfterAdd.date_month = iMonthNew;

  iDaysInMonth = daysInMonth(dateAfterAdd.date_year, iMonthNew);

 }//end else

 //對于超出的做特殊處理.

 if (iLeftDaysTotal > (iDayTotal - iLeftDaysInCurMonth))

  iLeftDaysTotal -= iDaysInMonth;

//cout << "iDayTotal  =" << iDayTotal << "\tiLeftDaysInCurMonth = " << iLeftDaysInCurMonth  //bug??

 //<< "\tiLeftDaysTotal = " << iLeftDaysTotal << endl;

if (iDayTotal - iLeftDaysInCurMonth - iLeftDaysTotal < 0)

 dateAfterAdd.date_day = iDayTotal - iLeftDaysInCurMonth;

 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;

  dateAfterAdd.date_month -= 1;

assert((dateAfterAdd.date_month >= 1) && (dateAfterAdd.date_month <= 12));

assert((dateAfterAdd.date_day >= 1) && (dateAfterAdd.date_day <= 31));

**@brief:列印日期格式.

**@param: theDate提供列印的日期

**@return:空.

void DisplayDate(Date& theDate)

cout << theDate.date_year << "/" << theDate.date_month

  << "/" << theDate.date_day << "\t";

cout << endl << endl;

**@brief:測試用例:測試某年是否為閏年.

**@param: 空.

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:單元測試用例,某年某月有多少天.

void testDaysInMonth()

unsigned int iBeginYear = 1980;

unsigned int iEndYear = 2020;

unsigned int iBeginMonth = 1;

unsigned int iEndMonth = 12;

unsigned int iDaysOfYear = 0;

    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:單元測試用例,測試幾個月後日期.

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;

 beginDate.date_year = iYear;

 (void)DisplayDate(beginDate);

 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:單元測試用例,測試給定天後的日期.

void testDataAddDays()

beginDate.date_year = 1988;

beginDate.date_month = 7;

beginDate.date_day = 19;

cout << "Init Date is :" << endl;

(void)DisplayDate(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

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

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

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

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

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

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

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

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

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

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

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可以留言,一起改進完善,謝謝!

繼續閱讀