简体   繁体   中英

Find closest end-of-month for a given date in C#

I want to find the "closest" end-of-month-date to a particular date. For instance, if the date is 4.3.2017 , 28.2.2017 is the closest date. For 20.3.2017 , 31.3.2017 is the closest date. For dates caught dead center it doesnt really matter if we pick the lower or the higher date.

From these two posts, How do I get the last day of a month? and Find the closest time from a list of times , I have been able to clobber together the following approach

public static DateTime findNearestDate(DateTime currDate)
{
    List<DateTime> dates = new List<DateTime> { ConvertToLastDayOfMonth(currDate.AddMonths(-1)), ConvertToLastDayOfMonth(currDate) };
    DateTime closestDate = dates[0];
    long min = long.MaxValue;

    foreach (DateTime date in dates)
        if (Math.Abs(date.Ticks - currDate.Ticks) < min)
        {
            min = Math.Abs(date.Ticks - currDate.Ticks);
            closestDate = date;
        }
    return closestDate;
}

public static DateTime ConvertToLastDayOfMonth(DateTime date)
{
    return new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
}

This works, but it seems like there is a lot of code for such a simple task. Does anybody know of a simpler, more compact, approach?

Given that there can only be two options, it seems odd to loop here.

Assuming you only have dates, rather than needing to worry about the time of day as well, it seems to me that the decision only rests on how many days are in the "current" month. So something like:

// Names adjusted to follow .NET naming conventions
public static DateTime FindNearestEndOfMonth(DateTime date)
{
    int year = date.Year;
    int month = date.Month;
    int daysInMonth = DateTime.DaysInMonth(year, month);
    return date.Day >= daysInMonth / 2
        // End of current month
        ? new DateTime(year, month, daysInMonth)
        // End of previous month
        : new DateTime(year, month, 1).AddDays(-1);
}

You can calculate the last date of current and previous month and choose the closest one:

public static DateTime GetNearestEOM(DateTime date)
{
    DateTime EOMPrev = new DateTime(date.Year, date.Month, 1).AddDays(-1);
    DateTime EOMNext = new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1);
    DateTime NearestEOM = (date - EOMPrev).TotalDays < (EOMNext - date).TotalDays ? EOMPrev : EOMNext;
    return NearestEOM;
}

GetNearestEOM(new DateTime(2017, 3, 4));  // 2017-02-28 00:00:00
GetNearestEOM(new DateTime(2017, 3, 20)); // 2017-03-31 00:00:00

There is no need for a loop. You can use the built-in timespan addition functions of the framework:

var closestendofmonth = new DateTime(date.Year, date.Month, 1).AddDays(-1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM