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

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

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

 DateTime thirdFriday= new DateTime(yourDate.Year, yourDate.Month, 15); while (thirdFriday.DayOfWeek != DayOfWeek.Friday) { thirdFriday = thirdFriday.AddDays(1); } 

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

与语言无关的版本:

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

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

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

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

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

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

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

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

(扩展方法)

 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 

稍微优化的版本:

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

老post,但我发现这个肯定很常见的问题在网上找到了不错的答案! Mark Ransom的答案应该是这个算法的最后一个词,但对于那些想要快速回答“一周中的第一天”,“第x天”的常见问题的人来说,这是一个C#帮助类(我讨厌扩展)一个星期的月和“一个月的最后一天”。

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

我也抛出了一个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 res = FirstDayOfWeekInMonth(year, month + 1, 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 

这是一个使用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!"); } 

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

  private DateTime thirdSunday(DateTime timeFrom) { List days = new List(); DateTime testDate = timeFrom; while (testDate < timeFrom.AddMonths(1)) { if (testDate.DayOfWeek == DayOfWeek.Friday) { days.Add(testDate); } testDate = testDate.AddDays(1); } return days[2]; } 

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

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

我的理由是这样的

  • 15日是第一个可能的“第三个星期五”(1,8,15)
  • 因此,我们正在寻找15日或之后的第一个星期五
  • DayOfWeek是一个枚举,从星期日开始为0
  • 因此,您必须在15日添加5-(int)baseDay.DayOfWeek
  • 除了上面的偏移可以是负数,我们通过加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]; } 
  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; } 
  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); } } 

对不起,我迟到了……可能会帮助别人。

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

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

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

这是我的算法:

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

该计数器将在该日期的第n个星期五(或即将到来的星期五)给您。

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

  public static DateTime GetDayOfMonth(DateTime dateValue, DayOfWeek dayOfWeek, int occurance) { List dayOfWeekRanges = new List(); //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]; } 

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

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