I have an agreement with a customer. When the agreement ends, the customer needs to pay. The amount which the customer needs to pay increases for each month that has passed since the agreement was initiated. The maximum duration is 3 years, so I have a final expiration date. From this final expiration date, I must be able to find the periodic expiration date (the date when the payment increases). In other words, I need a function which does this:
DateTime GetNextExpirationDate(finalExpirationDate)
One of the issues which I am struggling with is that the algorithm needs to consider whether the expiration date in the current month has already passed (there will be a date each month). It also needs to consider that the day of the month for the final expiration date, might not exist for the periodic expiration dates (e.g. if the final expiration date is the 31st of something).
I have some code which is working, but it appears somewhat redundant and with many steps. I was wondering, if perhaps it could be simplified (either a little or a lot).
public DateTime GetNextExpirationDate(DateTime finalExpirationDate)
{
int expirationDay = finalExpirationDate.Day;
int currentMonth = DateTime.Now.Month;
int currentYear = DateTime.Now.Year;
int daysInCurrentMonth = DateTime.DaysInMonth(currentYear, currentMonth);
// If the month has less days that the day of the final expiration date,
// then we need to use the maximum date of the month.
int expirationDayThisMonth = Math.Min(expirationDay, daysInCurrentMonth);
DateTime expirationDateThisMonth = new DateTime(currentYear, currentMonth, expirationDayThisMonth);
// If the periodic expiration date in the current month is already surpassed,
// then we need to the date in the next month.
if (expirationDateThisMonth < DateTime.Now)
{
DateTime dateInOneMonth = DateTime.Now.AddMonths(1);
int nextMonthMonth = dateInOneMonth.Month;
int nextMonthYear = dateInOneMonth.Year;
int daysInNextMonth = DateTime.DaysInMonth(nextMonthYear, nextMonthMonth);
int expirationDayNextMonth = Math.Min(expirationDay, daysInNextMonth);
DateTime expirationDateNextMonth = new DateTime(nextMonthYear, nextMonthMonth, expirationDayNextMonth);
return expirationDateNextMonth;
}
else
{
return expirationDateThisMonth;
}
}
Any ways to improve this?
Input/output examples:
Final expiration date: 15.12.2019
DateTime.Now: 12.03.2019
Output: 15.03.2019
Final expiration date 11.10.2019
DateTime.Now: 16.04.2019
Output: 11.05.2019
(I know that I cannot change DateTime.Now
but it does work as an pseudo-input, which is why I included it).