How to find the 3rd Friday in a month with C#?

2020-01-25 01:15发布

Given a date (of type DateTime), how do I find the 3rd Friday in the month of that date?

标签: c# .net datetime
17条回答
对你真心纯属浪费
2楼-- · 2020-01-25 01:37

I'm going to repeat my answer from here with one little addition.

The language-agnostic version:

To get the first particular day of the month, start with the first day of the month: yyyy-mm-01. Use whatever function is available to give a number corresponding to the day of the week; in C# this would be DateTime.DayOfWeek. Subtract that number from the day you are looking for; for example, if the first day of the month is Wednesday (3) and you're looking for Friday (5), subtract 3 from 5, leaving 2. If the answer is negative, add 7. Finally add that to the first of the month; for my example, the first Friday would be the 3rd.

To get the last Friday of the month, find the first Friday of the next month and subtract 7 days.

To get the 3rd Friday of the month, add 14 days to the first Friday.

查看更多
唯我独甜
3楼-- · 2020-01-25 01:39

This is a version that uses LINQ and functional programming style.

It works like this.

First, take all of the days of the month. Then select only the ones of the right day (Friday). Finally take the nth (3rd) entry and return.

// dt: The date to start from (usually DateTime.Now)
// n: The nth occurance (3rd)
// weekday: the day of the week to look for
    public DateTime GetNthWeekdayOfMonth(DateTime dt, int n, DayOfWeek weekday)
    {
        var days = Enumerable.Range(1, DateTime.DaysInMonth(dt.Year, dt.Month)).Select(day => new DateTime(dt.Year, dt.Month, day));

        var weekdays = from day in days
                            where day.DayOfWeek == weekday
                            orderby day.Day ascending
                            select day;

        int index = n - 1;

        if (index >= 0 && index < weekdays.Count())
            return weekdays.ElementAt(index);

        else
            throw new InvalidOperationException("The specified day does not exist in this month!");
   }
查看更多
不美不萌又怎样
4楼-- · 2020-01-25 01:39

Following works great, no validation for occurrence is provided. You can find any nth day for the given date month either from start or last. Provide minus occurrence value if you are looking for from the last.

 public static DateTime GetDayOfMonth(DateTime dateValue, DayOfWeek dayOfWeek, int occurance)
    {
        List<DateTime> dayOfWeekRanges = new List<DateTime>();

        //move to the first of th month
        DateTime startOfMonth = new DateTime(dateValue.Year, dateValue.Month, 1);

        //move startOfMonth to the dayOfWeek requested
        while (startOfMonth.DayOfWeek != dayOfWeek)
            startOfMonth = startOfMonth.AddDays(1);

        do
        {
            dayOfWeekRanges.Add(startOfMonth);
            startOfMonth = startOfMonth.AddDays(7);
        } while (startOfMonth.Month == dateValue.Month);

        bool fromLast = occurance < 0;
        if (fromLast)
            occurance = occurance * -1;

        if (fromLast)
            return dayOfWeekRanges[dayOfWeekRanges.Count - occurance];
        else
            return dayOfWeekRanges[occurance - 1];
    }
查看更多
家丑人穷心不美
5楼-- · 2020-01-25 01:40

I know of no clean/built in way of doing this. But it's not too hard to code up:

        DateTime now = DateTime.Now;

        for (int i = 0; i < 7; ++i)
        {
            DateTime d = new DateTime(now.Year, now.Month, i+1);
            if (d.DayOfWeek == DayOfWeek.Friday)
            {
                return d.AddDays(14);
            }
        }
查看更多
贪生不怕死
6楼-- · 2020-01-25 01:40

I wrote extended version of @justcoding121's code that can get from the last day of the month. I don't know this algorithm is right, but it works so far.

public static int? GetNthDayOfWeekInMonth(int year, int month, DayOfWeek dow, int weekNumOfMonth)
{
    if (weekNumOfMonth < -5 || weekNumOfMonth == 0 || weekNumOfMonth > 5)
        throw new ArgumentOutOfRangeException("weekNumOfMonth", $"must be between 1~5 or -1~-5. ({weekNumOfMonth})");

    int daysOfMonth = DateTime.DaysInMonth(year, month);

    if (weekNumOfMonth > 0)
    {
        var firstDay = new DateTime(year, month, 1);
        var firstDayOfTargetDOW = (int)dow - (int)firstDay.DayOfWeek;
        if (firstDayOfTargetDOW < 0)
            firstDayOfTargetDOW += 7;
        var resultedDay = (firstDayOfTargetDOW + 1) + (7 * (weekNumOfMonth - 1));

        if (resultedDay > daysOfMonth)
            return null;

        return resultedDay;
    }
    else
    {
        var lastDay = new DateTime(year, month, daysOfMonth);
        var firstDayOfTargetDOW = (int)lastDay.DayOfWeek - (int)dow;
        if (firstDayOfTargetDOW < 0)
            firstDayOfTargetDOW += 7;
        var resultedDay = firstDayOfTargetDOW + (7 * (Math.Abs(weekNumOfMonth) - 1));

        if (resultedDay > daysOfMonth)
            return null;

        return (daysOfMonth - resultedDay);
    }
}

usage

Assert.AreEqual(02, DateTimeHelper.GetNthDayOfWeekInMonth(2019, 11, DayOfWeek.Saturday, 1));
Assert.AreEqual(30, DateTimeHelper.GetNthDayOfWeekInMonth(2019, 11, DayOfWeek.Saturday, -1));
查看更多
乱世女痞
7楼-- · 2020-01-25 01:43

I followed User:Mark Ransom's algorithm and wrote a generalized day finder. For example to get the 3rd friday of december 2013,

int thirdFriday = DayFinder.FindDay(2013, 12, DayOfWeek.Friday, 3);

And here is the function definition. It doesn't have any iterative loops, so its efficient.

public class DayFinder
        {

            //For example to find the day for 2nd Friday, February, 2016
            //=>call FindDay(2016, 2, DayOfWeek.Friday, 2)
            public static int FindDay(int year, int month, dayOfWeek Day, int occurance)
            {

               if (occurance <= 0 || occurance > 5) 
                throw new Exception("Occurance is invalid");

               DateTime firstDayOfMonth = new DateTime(year, month, 1);
                //Substract first day of the month with the required day of the week 
               var daysneeded = (int)day - (int)firstDayOfMonth.DayOfWeek;
                //if it is less than zero we need to get the next week day (add 7 days)
               if (daysneeded < 0) daysneeded = daysneeded + 7;
                //DayOfWeek is zero index based; multiply by the Occurance to get the day
               var resultedDay =  (daysneeded + 1)+ (7*(occurance-1));

               if(resultedDay > (firstDayOfMonth.AddMonths(1) - firstDayOfMonth).Days) 
                throw new Exception(String.Format("No {0} occurance(s) of {1} in the required month", occurance, day.ToString()));

               return resultedDay; 
            }
        }
查看更多
登录 后发表回答