33

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

Paul Fryer
  • 9,268
  • 14
  • 61
  • 93

20 Answers20

98

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.

Community
  • 1
  • 1
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 33
    +1 for explaining and **not giving code**, because that's an algorithm problem here, not a technical one. – Clement Herreman Mar 24 '11 at 16:08
  • 1
    This should be the answer, because it's clear, generally applicable, and actually works. I've created a C# class based on it and added it as an answer for anyone who just wants a quickie. – Whelkaholism Oct 08 '14 at 11:02
35

I haven't tested this, but since the third Friday can't possibly occur before the 15th of the month, create a new DateTime, then just increment until you get to a Friday.

DateTime thirdFriday= new DateTime(yourDate.Year, yourDate.Month, 15);

while (thirdFriday.DayOfWeek != DayOfWeek.Friday)
{
   thirdFriday = thirdFriday.AddDays(1);
}
Brandon
  • 68,708
  • 30
  • 194
  • 223
26

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;
    }
}
Ram Singh
  • 6,664
  • 35
  • 100
  • 166
Jehonathan Thomas
  • 2,110
  • 1
  • 28
  • 34
7

Probably best to abstract this to a method to do any date/day combination:

(Extension Method)

public static bool TryGetDayOfMonth(this DateTime instance, 
                                 DayOfWeek dayOfWeek, 
                                 int occurance, 
                                 out DateTime dateOfMonth)
{
    if (instance == null)
    {
        throw new ArgumentNullException("instance");
    }

    if (occurance <= 0 || occurance > 5)
    {
        throw new ArgumentOutOfRangeException("occurance", "Occurance must be greater than zero and less than 6.");
    }

    bool result;
    dateOfMonth = new DateTime();

    // Change to first day of the month
    DateTime dayOfMonth = instance.AddDays(1 - instance.Day);

    // Find first dayOfWeek of this month;
    if (dayOfMonth.DayOfWeek > dayOfWeek)
    {
        dayOfMonth = dayOfMonth.AddDays(7 - (int)dayOfMonth.DayOfWeek + (int)dayOfWeek);
    }
    else
    {
        dayOfMonth = dayOfMonth.AddDays((int)dayOfWeek - (int)dayOfMonth.DayOfWeek);
    }

    // add 7 days per occurance
    dayOfMonth = dayOfMonth.AddDays(7 * (occurance - 1));

    // make sure this occurance is within the original month
    result = dayOfMonth.Month == instance.Month;


    if (result)
    {
        dateOfMonth = dayOfMonth;
    }

    return result;
}

Results:

DateTime myDate = new DateTime(2013, 1, 1)
DateTime dateOfMonth;

myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 1, out dateOfMonth) 
// returns: true; dateOfMonth = Sunday, 1/6/2013

myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 4, out dateOfMonth) 
// returns: true; dateOfMonth = Sunday, 1/27/2013

myDate.TryGetDayOfMonth(DayOfWeek.Sunday, 5, out dateOfMonth) 
// returns: false; 

myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 1, out dateOfMonth) 
// returns: true; dateOfMonth = Wednesday, 1/2/2013

myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 4, out dateOfMonth) 
// returns: true; dateOfMonth = Wednesday, 1/23/2013

myDate.TryGetDayOfMonth(DayOfWeek.Wednesday, 5, out dateOfMonth) 
// returns: true; dateOfMonth = Wednesday, 1/30/2013 

// etc
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • 1
    You've got a bug. It should be as below. Otherwise I think it's the cleanest solution. // Change to first day of the month DateTime dayOfMonth = instance.AddDays(1 - instance.Day); – Bartosz Wójtowicz Oct 16 '13 at 10:03
  • This test: if (occurance < 0 || occurance > 5) will allow a value of #0 for occurrence, which I believe is an error. – BillW Jul 28 '14 at 06:13
  • This works but should a TryGet method throw exceptions?I am thinking you modeled this after methods like Int32.TryParse – Tundey Jun 11 '15 at 15:06
  • Most if not all Microsoft .Net framework methods that start with Try do not throw an exception on normal errors. Instead they return if the attempt is successful as a boolean and return the valid result in an out parameter (like [int.tryparse()](https://msdn.microsoft.com/en-us/library/f02979c7(v=vs.110).aspx) which throws no exceptions). Now considering I've added additional paramters, it's still best practice to validate parameters and throw exceptions when those parameters are invalid (I probably shouldn't be checking instance, since DateTime cannot be null). – Erik Philips Jun 11 '15 at 15:42
  • For example, [DateTime.TryParse](https://msdn.microsoft.com/en-us/library/9h21f14e(v=vs.110).aspx) can throw both an `ArgumentException` and a `NotSupportedException`. – Erik Philips Jun 11 '15 at 15:48
7

Old post, but I found remarkably few decent answers online for this surely quite common problem! Mark Ransom's answer should be the last word on this algorithm-wise, but here is a C# helper class (in this case I think clearer than extensions) for anyone who wants a quick answer to the common problems of "first day of week in month", "xth day of week in month" and "last day of week in month".

I modified it to return DateTime.MinValue if the Xth day of the week falls outside the provided month rather than wrapping to the next month, because that to me seems more useful.

I've thrown in a LINQPad-runnable example program too.

void Main()
{
    DayOfWeek dow = DayOfWeek.Friday;
    int y = 2014;
    int m = 2;

    String.Format("First {0}: {1}", new object[] { dow, DateHelper.FirstDayOfWeekInMonth(y, m, dow) }).Dump();

    "".Dump();

    String.Format("Last {0}: {1}", new object[] { dow, DateHelper.LastDayOfWeekInMonth(y, m, dow) }).Dump();

    "".Dump();

    for(int i = 1; i <= 6; i++)
        String.Format("{0} #{1}: {2}", new object[] { dow, i, DateHelper.XthDayOfWeekInMonth(y, m, dow, i) }).Dump();
}


public class DateHelper
{
    public static DateTime FirstDayOfWeekInMonth(int year, int month, DayOfWeek day)
    {
        DateTime res = new DateTime(year, month, 1);
        int offset = -(res.DayOfWeek - day);

        if (offset < 0)
            offset += 7;

        res = res.AddDays(offset);

        return res;
    }

    public static DateTime LastDayOfWeekInMonth(int year, int month, DayOfWeek day)
    {
        DateTime dt = new DateTime(year, month, 1).AddMonths(1);        
        DateTime res = FirstDayOfWeekInMonth(dt.Year, dt.Month, day);

        res = res.AddDays(-7);

        return res;
    }


    public static DateTime XthDayOfWeekInMonth(int year, int month, DayOfWeek day, int x)
    {
        DateTime res = DateTime.MinValue;

        if (x > 0)
        {
            res = FirstDayOfWeekInMonth(year, month, day);

            if (x > 1)
                res = res.AddDays((x - 1) * 7);

            res = res.Year == year && res.Month == month ? res : DateTime.MinValue;
        }

        return res;
    }
}

Prints:

First Friday: 07/02/2014 00:00:00

Last Friday: 28/02/2014 00:00:00

Friday #1: 07/02/2014 00:00:00
Friday #2: 14/02/2014 00:00:00
Friday #3: 21/02/2014 00:00:00
Friday #4: 28/02/2014 00:00:00
Friday #5: 01/01/0001 00:00:00
Friday #6: 01/01/0001 00:00:00
Whelkaholism
  • 1,551
  • 3
  • 18
  • 28
  • On reflection, it'd be quite nice to change XthDayOfWeekInMonth to accept negative "x"s to indicate "last", "second to last" etc. but I have no personal use case for this, so I haven't done it :o) – Whelkaholism Oct 23 '14 at 11:58
  • LastDayOfWeekInMonth fails for December because DateTime cannot take Month 13 and figure out that you need January of the next year. – Rex Bloom Feb 21 '19 at 21:36
  • Well damn, how have I never noticed that? I will edit with a fix – Whelkaholism Feb 22 '19 at 09:36
6

Slightly more optimized version:

    DateTime Now = DateTime.Now;

    DateTime TempDate = new DateTime(Now.Year, Now.Month, 1);

    // find first friday
    while (TempDate.DayOfWeek != DayOfWeek.Friday)
        TempDate = TempDate.AddDays(1);

    // add two weeks
    TempDate = TempDate.AddDays(14);
Steve Wellens
  • 20,506
  • 2
  • 28
  • 69
5

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!");
   }
Nayeem Mansoori
  • 821
  • 1
  • 15
  • 41
Josh G
  • 14,068
  • 7
  • 62
  • 74
2

I pass this the DateTime for the start of the month I am looking at.

    private DateTime thirdSunday(DateTime timeFrom)
    {
        List<DateTime> days = new List<DateTime>();
        DateTime testDate = timeFrom;

        while (testDate < timeFrom.AddMonths(1))
        {
            if (testDate.DayOfWeek == DayOfWeek.Friday)
            {
                days.Add(testDate);
            }
            testDate = testDate.AddDays(1);
        }

        return days[2];
    }
2

My reasoning goes like this

  • the 15th is the first possible "third Friday" (1,8,15)
  • therefore we're looking for the first Friday on or after the 15th
  • DayOfWeek is an enumeration starting with 0 for Sunday
  • Therefore you have to add an offet of 5-(int)baseDay.DayOfWeek to the 15th
  • Except that the above offset can be negative, which we fix by adding 7, then doing modulo 7.

In code:

public static DateTime GetThirdFriday(int year, int month)
{
   DateTime baseDay = new DateTime(year, month, 15);
   int thirdfriday = 15 + ((12 - (int)baseDay.DayOfWeek) % 7);
   return new DateTime(year, month, thirdfriday);
}

Since there are only 7 possible results, you could also do this:

  private readonly static int[] thirdfridays =
      new int[] { 20, 19, 18, 17, 16, 15, 21 };

  public static int GetThirdFriday(int year, int month)
  {
     DateTime baseDay = new DateTime(year, month, 15);
     return thirdfridays[(int)baseDay.DayOfWeek];
  }
Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
1

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);
            }
        }
Matt Greer
  • 60,826
  • 17
  • 123
  • 123
1

Late to the game but here's my solution to add DateTime extension functionality which accounts for the January to December issue when subtracting occurrence values and accounts for if the occurrence is 5 - which in my case should return the last occurrence which would either be number 4 or 5 depending on where the day lands in the month:

public static DateTime NthOf(this DateTime CurDate, int Occurrence, DayOfWeek Day)
    {
        //Last day of month if 5 - return last day.
        if (Occurrence == 5)
        {
            return LastDayOfMonth(CurDate, Day);
        }
        var fday = new DateTime(CurDate.Year, CurDate.Month, 1, CurDate.Hour, CurDate.Minute, CurDate.Second);

        var firstoccurrence = fday.DayOfWeek == Day ? fday : fday.AddDays(Day - fday.DayOfWeek);
        // CurDate = 2011.10.1 Occurance = 1, Day = Friday >> 2011.09.30 FIX. 
        if (firstoccurrence.Month < CurDate.Month)
        {
            Occurrence = Occurrence + 1;
        } else if (firstoccurrence.Month == 12 && CurDate.Month == 1)
        {
            Occurrence = Occurrence + 1;
        }
        return firstoccurrence.AddDays(7 * (Occurrence - 1));
    }

public static DateTime LastDayOfMonth(this DateTime CurDate, DayOfWeek Day)
    {
        DateTime EndOfMonth = new DateTime(CurDate.Year, CurDate.Month, 1).AddMonths(1).AddDays(-1);
        while (EndOfMonth.DayOfWeek != Day)
        {
            EndOfMonth = EndOfMonth.AddDays(-1);
        }
        return EndOfMonth;
    }

The you can call your method with something like this:

Console.WriteLine(DateTime.Now.NthOf(3, DayOfWeek.Friday).ToString());

This would return the third Friday of the current month and log it to the console as a string value. It extends from DateTime nicely and does not require any usage of a static helper class or any additional moving parts.

Eric Conklin
  • 539
  • 4
  • 17
1
    public DateTime GetThirdThursday(DateTime now)
    {
        DateTime ThirdThursday;
        now = DateTime.Now;
        string wkday;
        DateTime firstday = new DateTime(now.Year, now.Month, 1);
        ThirdThursday = firstday.AddDays(15);

        // ThirdThursday = now.AddDays((now.Day - 1) * -1).AddDays(14);
        wkday = ThirdThursday.DayOfWeek.ToString();

        while (wkday.CompareTo("Thursday") < 0)

        {
            ThirdThursday.AddDays(1);
        }
        return ThirdThursday;
    }
Edwin de Koning
  • 14,209
  • 7
  • 56
  • 74
Yude
  • 11
  • 1
0

Sorry to jump in late on this... Might help someone else tho.

Begin rant: Loops, yuck. Too much code, yuck. Not Generic Enough, yuck.

Here's a simple function with a free overload.

public DateTime DateOfWeekOfMonth(int year, int month, DayOfWeek dayOfWeek, byte weekNumber)
{
    DateTime tempDate = new DateTime(year, month, 1);
    tempDate = tempDate.AddDays(-(tempDate.DayOfWeek - dayOfWeek));

    return
        tempDate.Day > (byte)DayOfWeek.Saturday
            ? tempDate.AddDays(7 * weekNumber)
            : tempDate.AddDays(7 * (weekNumber - 1));
}

public DateTime DateOfWeekOfMonth(DateTime sender, DayOfWeek dayOfWeek, byte weekNumber)
{
    return DateOfWeekOfMonth(sender.Year, sender.Month, dayOfWeek, weekNumber);
}

Your usage:

DateTime thirdFridayOfMonth = DateOfWeekOfMonth(DateTime.Now, DayOfWeek.Friday, 3);
0

Here's my algorithm:

  1. Find the number of days until the upcoming Friday.
  2. Initialize a counter and set it to 1. Subtract seven days from the date returned from [1], then compare the month from the date returned against the date returned from (1).
    1. If the months are not equal, return the counter from [2].
    2. If the months are equal, recurse into [2] and add 1 to the counter created in [2].

The counter will give you the nth Friday of the month for that date (or its upcoming Friday).

Carlos Nunez
  • 2,047
  • 1
  • 18
  • 20
0

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];
    }
Paresh Varde
  • 1,084
  • 3
  • 16
  • 39
0

Here is my two cents... An optimized solution without unnecessary loops or tests :

public static DateTime ThirdFridayOfMonth(DateTime dateTime)
{
    int day = dateTime.Day;
    return dateTime.AddDays(21 - day - ((int)dateTime.DayOfWeek + 37 - day) % 7);
}
Wizou
  • 1,336
  • 13
  • 24
0
    int numday = 0;
    int dayofweek = 5; //friday
    DateTime thirdfriday;
    for (int i = 0; i < (date.AddMonths(1) - date).Days && numday <3; i++)
    {
        if ((int)date.AddDays(i).DayOfWeek == dayofweek)
        {
            numday++;
        }
        if (numday == 3)
        {
            thirdfriday = date.AddDays(i);
        }

    }
arnehehe
  • 1,386
  • 1
  • 17
  • 33
0

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));
tsu1980
  • 2,472
  • 1
  • 25
  • 13
0

I know this post is old. I have this solution, trying to find a more clean code. #unclebob

    public static DateTime FindTheNthDay(
        int year, int month, DayOfWeek day, int occurrence)
    {
        var startDate = new DateTime(year, month, 1);

        while(startDate.DayOfWeek != day)
        {
            startDate = startDate.AddDays(1);
        }

        var nDays = 7 * (occurrence - 1);
        var result = startDate.AddDays(nDays);

        return result;
    }
> FindTheNthDay(2006, 11, DayOfWeek.Friday, 4)
[11/24/2006 12:00:00 AM]
> FindTheNthDay(2005, 11, DayOfWeek.Friday, 4)
[11/25/2005 12:00:00 AM]
> FindTheNthDay(2004, 11, DayOfWeek.Friday, 4)
[11/26/2004 12:00:00 AM]
> FindTheNthDay(2003, 11, DayOfWeek.Friday, 4)
[11/28/2003 12:00:00 AM]
> FindTheNthDay(1983, 11, DayOfWeek.Friday, 4)
[11/25/1983 12:00:00 AM]
> FindTheNthDay(1978, 11, DayOfWeek.Friday, 4)
[11/24/1978 12:00:00 AM]
> FindTheNthDay(1972, 11, DayOfWeek.Friday, 4)
[11/24/1972 12:00:00 AM]
  • Will this handle 5th Fridays? I am looking at predicting the next ocuurance (date) of a 5th Friday event. It might not fall on month I am inside (Now). – JustJohn Feb 19 '23 at 02:19
0
    public static bool IsThirdWednesday(DateTime inputDate)
    {
        DateTime firstDayOfMonth = new DateTime(inputDate.Year, inputDate.Month, 1);
        DateTime firstDayOfNextMonth = firstDayOfMonth.AddMonths(1);

        int wednesdayCount = 0;
        while(firstDayOfMonth < firstDayOfNextMonth)
        {
            if (firstDayOfMonth.DayOfWeek == DayOfWeek.Wednesday)
                wednesdayCount++;

            if (wednesdayCount == 3)
            {
                if (inputDate == firstDayOfMonth)
                    return true;
                else
                    return false;
              
            }

            firstDayOfMonth = firstDayOfMonth.AddDays(1);
        }

        return false;
    }
  • 1
    Welcome to SO. While answering it may help to explain the logic/rationale behind the code you are demonstrating. – seshadri_c Oct 14 '20 at 16:27