¿Cómo encontrar el tercer viernes en un mes con C #?

Dada una fecha (del tipo DateTime ), ¿cómo encuentro el tercer viernes en el mes de esa fecha?

No lo he probado, pero como el tercer viernes no puede ocurrir antes del día 15 del mes, cree un nuevo DateTime, luego incremente hasta llegar a un viernes.

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

Voy a repetir mi respuesta desde aquí con una pequeña adición.

La versión agnóstica del idioma:

Para obtener el primer día del mes en particular, comience con el primer día del mes: aaaa-mm-01. Use cualquier función disponible para dar un número correspondiente al día de la semana; en C # esto sería DateTime.DayOfWeek . Reste ese número del día que está buscando; por ejemplo, si el primer día del mes es miércoles (3) y está buscando viernes (5), reste 3 de 5, dejando 2. Si la respuesta es negativa, agregue 7. Finalmente agregue eso al primero de el mes; para mi ejemplo, el primer viernes sería el tercero.

Para obtener el último viernes del mes, encuentre el primer viernes del mes siguiente y reste 7 días.

Para obtener el tercer viernes del mes, agregue 14 días al primer viernes.

Seguí al usuario: el algoritmo de Mark Ransom y escribí un buscador de día generalizado. Por ejemplo, para obtener el 3 ° viernes de diciembre de 2013,

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

Y aquí está la definición de la función. No tiene ningún bucle iterativo, por lo que es eficiente.

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

Versión un poco más optimizada:

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

Probablemente sea mejor resumir esto en un método para hacer cualquier combinación de fecha / día:

(Método de extensión)

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

Resultados:

 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 

Publicación anterior, pero encontré muy pocas respuestas decentes en línea para este problema bastante común! La respuesta de Mark Ransom debería ser la última palabra sobre este algoritmo, pero aquí hay una clase de ayuda C # (odio las extensiones) para cualquiera que quiera una respuesta rápida a los problemas comunes de “primer día de la semana en el mes”, “x día” de la semana en el mes “y” último día de la semana en el mes “.

Lo modifiqué para devolver DateTime.MinValue si el X día de la semana cae fuera del mes provisto en lugar de ajustarlo al mes siguiente, porque eso me parece más útil.

También incluí un progtwig de ejemplo LINQPad-ejecutable.

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

Huellas dactilares:

 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 

Esta es una versión que utiliza LINQ y el estilo de progtwigción funcional.

Funciona así.

Primero, tome todos los días del mes. Luego seleccione solo las del día correcto (viernes). Finalmente toma la enésima (tercera) entrada y regresa.

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

Paso este el DateTime para el comienzo del mes que estoy viendo.

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

No conozco ninguna manera limpia / construida de hacer esto. Pero no es muy difícil codificar:

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

Mi razonamiento es como esto

  • el 15 es el primer “tercer viernes” posible (1,8,15)
  • por lo tanto, estamos buscando el primer viernes a partir del día 15
  • DayOfWeek es una enumeración que comienza con 0 para el domingo
  • Por lo tanto, debe agregar un offet de 5-(int)baseDay.DayOfWeek al día 15
  • Excepto que el desplazamiento anterior puede ser negativo, lo cual corregimos agregando 7, y luego haciendo el módulo 7.

En codigo:

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

Como solo hay 7 resultados posibles, también puede hacer esto:

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

Lamento haber llegado tarde a esto … Podría ayudar a alguien más, aunque.

Comience a despotricar: Loops, yuck. Demasiado código, puaj. No genérico Suficiente, puaj.

Aquí hay una función simple con una sobrecarga gratuita.

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

Su uso:

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

Aquí está mi algoritmo:

  1. Encuentra la cantidad de días hasta el próximo viernes.
  2. Inicialice un contador y configúrelo en 1. Reste siete días de la fecha devuelta desde [1], luego compare el mes desde la fecha devuelta con la fecha devuelta desde (1).
    1. Si los meses no son iguales, devuelva el contador de [2].
    2. Si los meses son iguales, repita en [2] y agregue 1 al contador creado en [2].

El contador le dará el n ° viernes del mes para esa fecha (o el próximo viernes).

Los siguientes trabajos son excelentes, no se proporciona validación de ocurrencia. Puedes encontrar cualquier día n para la fecha dada mes ya sea desde el inicio o el último. Proporcione el valor de aparición menos si está buscando desde el último.

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

Aquí está mi granito de arena … Una solución optimizada sin lapsos innecesarios o pruebas:

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