如何用C#查找一个月的第3个星期五?

时间:2011-03-24 15:58:14

标签: c# .net datetime

给定日期(类型DateTime),如何找到该日期的第3个星期五?

20 个答案:

答案 0 :(得分:77)

我将从here重复我的回答,只需添加一点。

与语言无关的版本:

要获得该月的第一天,请从该月的第一天开始:yyyy-mm-01。使用任何可用的函数给出对应于星期几的数字;在C#中,这将是DateTime.DayOfWeek。从你想要的那天减去那个数字;例如,如果该月的第一天是星期三(3)并且您正在寻找星期五(5),则从5减去3,留下2.如果答案是否定的,则添加7.最后将其添加到第一天这个月;就我而言,第一个星期五将是第三个。

要获得本月的最后一个星期五,请找到下个月的第一个星期五,并减去7天。

要获得本月的第3个星期五,请在第一个星期五添加14天。

答案 1 :(得分:24)

我没有对此进行过测试,但由于第三个星期五不可能在本月15日之前发生,所以创建一个新的DateTime,然后直到你到达星期五为止。

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

while (thirdFriday.DayOfWeek != DayOfWeek.Friday)
{
   thirdFriday = thirdFriday.AddDays(1);
}

答案 2 :(得分:17)

我跟随用户:Mark Ransom的算法并写了一个广义的日取景器。例如,要获得2013年12月的第3个星期五,

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

这是功能定义。它没有任何迭代循环,因此效率很高。

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

答案 3 :(得分:6)

可能最好将此抽象为一种方法来进行任何日期/日期组合:

(扩展方法)

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

结果:

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

答案 4 :(得分:5)

略微更优化的版本:

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

答案 5 :(得分:5)

旧帖子,但我发现这个肯定很常见的问题在网上找到了不错的答案! Mark Ransom的答案应该是这个算法的最后一个词,但是这里有一个C#助手类(在这种情况下我认为比扩展更清晰)对于那些想要快速回答#34的常见问题的人来说;月中的第一天&#34;,&#34;月中的第x天和#34;和&#34;一周中的最后一天&#34;。

如果一周中的第X天超出了提供的月份而不是包装到下个月,我将其修改为返回DateTime.MinValue,因为这对我来说似乎更有用。

我也在LINQPad可运行的示例程序中抛出。

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

打印:

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

答案 6 :(得分:3)

这是一个使用LINQ和函数式编程风格的版本。

就像这样。

首先,采取一个月的所有日子。然后只选择正确的一天(星期五)。最后取第n个(第3个)条目并返回。

// 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!");
   }

答案 7 :(得分:2)

我将DateTime传递给我正在查看的月份的开始。

    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];
    }

答案 8 :(得分:1)

我知道没有干净/内置的方式这样做。但编码起来并不难:

        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);
            }
        }

答案 9 :(得分:1)

我的理由是这样的

  • 15日是第一个可能的“第三个星期五”(1,8,15)
  • 因此我们正在寻找15日或之后的第一个星期五
  • DayOfWeek是一个以0为星期日
  • 开头的枚举
  • 因此,您必须在第15个
  • 中添加5-(int)baseDay.DayOfWeek的offet
  • 除了上面的偏移可以是负数,我们通过加7来修复,然后做模7。

在代码中:

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);
}

由于只有7种可能的结果,您也可以这样做:

  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];
  }

答案 10 :(得分: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;
    }

答案 11 :(得分:0)

游戏晚了,但这是我添加 DateTime 扩展功能的解决方案,该功能在减去出现值时考虑了 1 月至 12 月的问题,并考虑了出现次数是否为 5 - 在我的情况下应该返回最后一次出现数字 4 或 5,具体取决于月份中的日期:

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

你可以用这样的方式调用你的方法:

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

这将返回当月的第三个星期五并将其作为字符串值记录到控制台。它很好地从 DateTime 扩展而来,不需要使用任何静态帮助器类或任何额外的移动部件。

答案 12 :(得分: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;
    }

答案 13 :(得分:0)

我知道这则帖子很旧。我有此解决方案,试图找到更干净的代码。 #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]

答案 14 :(得分:0)

我写了@ justcoding121的代码的扩展版本,该版本可以从一个月的最后一天开始获取。我不知道这个算法是正确的,但是到目前为止它仍然有效。

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);
    }
}

用法

Assert.AreEqual(02, DateTimeHelper.GetNthDayOfWeekInMonth(2019, 11, DayOfWeek.Saturday, 1));
Assert.AreEqual(30, DateTimeHelper.GetNthDayOfWeekInMonth(2019, 11, DayOfWeek.Saturday, -1));

答案 15 :(得分:0)

这是我的两分钱...... 没有不必要的循环或测试的优化解决方案:

public static DateTime ThirdFridayOfMonth(DateTime dateTime)
{
    int day = dateTime.Day;
    return dateTime.AddDays(21 - day - ((int)dateTime.DayOfWeek + 37 - day) % 7);
}

答案 16 :(得分:0)

以下工作很好,没有提供发生的验证。您可以从开始或最后一个查找给定日期月份的任何第n天。如果您要从最后一个查找,请提供减去发生值。

 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];
    }

答案 17 :(得分:0)

这是我的算法:

  1. 查找即将到来的星期五之前的天数。
  2. 初始化计数器并将其设置为1.从[1]返回的日期减去七天,然后将返回日期的月份与(1)返回的日期进行比较。
    1. 如果月份不相等,请从[2]返回计数器。
    2. 如果月份相等,则递归到[2]并将[1]中创建的计数器加1。
  3. 该计数器将在该日期(或即将到来的星期五)为您提供该月的星期五 n

答案 18 :(得分:0)

对不起,我迟到了......可能会帮助其他人。

开始咆哮:循环,哎呀。太多的代码,哎呀。不太通用了,哎呀。

这是一个带有自由过载的简单功能。

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);
}

您的用法:

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

答案 19 :(得分: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);
        }

    }