Contar el número de lunes en un rango de fechas determinado

Dado un rango de fechas, necesito saber cuántos lunes (o martes, miércoles, etc.) están en ese rango.

Actualmente estoy trabajando en C #.

Prueba esto:

static int CountDays(DayOfWeek day, DateTime start, DateTime end) { TimeSpan ts = end - start; // Total duration int count = (int)Math.Floor(ts.TotalDays / 7); // Number of whole weeks int remainder = (int)(ts.TotalDays % 7); // Number of remaining days int sinceLastDay = (int)(end.DayOfWeek - day); // Number of days since last [day] if (sinceLastDay < 0) sinceLastDay += 7; // Adjust for negative days since last [day] // If the days in excess of an even week are greater than or equal to the number days since the last [day], then count this one, too. if (remainder >= sinceLastDay) count++; return count; } 

Como usa C #, si usa C # 3.0, puede usar LINQ.

Suponiendo que tiene un Array / List / IQueryable etc. que contiene sus fechas como tipos DateTime:

 DateTime[] dates = { new DateTime(2008,10,6), new DateTime(2008,10,7)}; //etc.... var mondays = dates.Where(d => d.DayOfWeek == DayOfWeek.Monday); // = {10/6/2008} 

Adicional:

No estoy seguro de si se refería a agruparlos y contarlos, pero aquí también se explica cómo hacerlo en LINQ:

 var datesgrouped = from d in dates group d by d.DayOfWeek into grouped select new { WeekDay = grouped.Key, Days = grouped }; foreach (var g in datesgrouped) { Console.Write (String.Format("{0} : {1}", g.WeekDay,g.Days.Count()); } 

Es divertido ver diferentes algoritmos para calcular el día de la semana, y @Gabe Hollombe apunta a WP sobre el tema fue una gran idea (y recuerdo implementar la Congruencia de Zeller en COBOL hace unos veinte años), pero fue más bien a lo largo de la línea de entregó a alguien un plano de un reloj cuando todos le preguntaron qué hora era.

Cª#:

  private int CountMondays(DateTime startDate, DateTime endDate) { int mondayCount = 0; for (DateTime dt = startDate; dt < endDate; dt = dt.AddDays(1.0)) { if (dt.DayOfWeek == DayOfWeek.Monday) { mondayCount++; } } return mondayCount; } 

Por supuesto, esto no evalúa la fecha de finalización de "Mondayness", por lo tanto, si esto se desea, haga que el bucle For evalúe

 dt < endDate.AddDays(1.0) 

Aquí hay un pseudocódigo:

 DifferenceInDays(Start, End) / 7 // Integer division discarding remainder + 1 if DayOfWeek(Start) <= DayImLookingFor + 1 if DayOfWeek(End) >= DayImLookingFor - 1 

Donde DifferenceInDays devuelve End - Start en días, y DayOfWeek devuelve el día de la semana como un entero. En realidad, no importa qué asignación use DayOfWeek , siempre que aumente y coincida con DayImLookingFor .

Tenga en cuenta que este algoritmo supone que el rango de fechas es inclusivo. Si End no debe formar parte del rango, tendrás que ajustar el algoritmo ligeramente.

La traducción a C # se deja como un ejercicio para el lector.

¿Algún idioma en particular y por lo tanto formato de fecha?

Si las fechas se representan como un recuento de días, la mayor parte de la respuesta es la diferencia entre dos valores más uno (día) y división entre 7. Si ambas fechas de finalización son el día en cuestión, agregue una.

Editado: corregido ‘modulo 7’ a ‘dividir por 7’ – gracias. Y esa es la división entera.

Me he encontrado con una forma un poco más fácil de resolver este problema usando linq.

 public static int NumberOfFridays(DateTime start, DateTime end) { return start.GetDaysInBetween(end, inclusive: true).Count(d => d.DayOfWeek == DayOfWeek.Friday); } 

Espero que ayude.

Agregue el número más pequeño posible para que el primer día sea un lunes. Reste el número más pequeño posible para hacer que el último día sea un lunes. Calcule la diferencia en días y divida por 7.

Convierta las fechas en Julian Day Number, luego haga un poco de matemática. Como los lunes son cero mod 7, puede hacer el cálculo de esta manera:

 JD1=JulianDayOf(the_first_date) JD2=JulianDayOf(the_second_date) Round JD1 up to nearest multiple of 7 Round JD2 up to nearest multiple of 7 d = JD2-JD1 nMondays = (JD2-JD1+7)/7 # integer divide 

He tenido la misma necesidad hoy. Empecé con la función cjm porque no entiendo la función JonB y porque la función Cyberherbalist no es lineal.

Tuve que corregir

 DifferenceInDays(Start, End) / 7 // Integer division discarding remainder + 1 if DayOfWeek(Start) <= DayImLookingFor + 1 if DayOfWeek(End) >= DayImLookingFor - 1 

a

 DifferenceInDays(Start, End) / 7 // Integer division discarding remainder + 1 if DayImLookingFor is between Start.Day and End.Day 

Con la función entre que devuelve verdadero si, comenzando desde el día de inicio, nos encontramos primero el día ImLookingFor antes del día final.

He hecho la función entre al calcular el número de días desde el día de inicio hasta los otros dos días:

 private int CountDays(DateTime start, DateTime end, DayOfWeek selectedDay) { if (start.Date > end.Date) { return 0; } int totalDays = (int)end.Date.Subtract(start.Date).TotalDays; DayOfWeek startDay = start.DayOfWeek; DayOfWeek endDay = end.DayOfWeek; ///look if endDay appears before or after the selectedDay when we start from startDay. int startToEnd = (int)endDay - (int)startDay; if (startToEnd < 0) { startToEnd += 7; } int startToSelected = (int)selectedDay - (int)startDay; if (startToSelected < 0) { startToSelected += 7; } bool isSelectedBetweenStartAndEnd = startToEnd >= startToSelected; if (isSelectedBetweenStartAndEnd) { return totalDays / 7 + 1; } else { return totalDays / 7; } } 

Puede intentar esto, si desea obtener días de semana específicos entre dos fechas

 public List GetSelectedDaysInPeriod(DateTime startDate, DateTime endDate, List daysToCheck) { var selectedDates = new List(); if (startDate >= endDate) return selectedDates; //No days to return if (daysToCheck == null || daysToCheck.Count == 0) return selectedDates; //No days to select try { //Get the total number of days between the two dates var totalDays = (int)endDate.Subtract(startDate).TotalDays; //So.. we're creating a list of all dates between the two dates: var allDatesQry = from d in Enumerable.Range(1, totalDays) select new DateTime( startDate.AddDays(d).Year, startDate.AddDays(d).Month, startDate.AddDays(d).Day); //And extracting those weekdays we explicitly wanted to return var selectedDatesQry = from d in allDatesQry where daysToCheck.Contains(d.DayOfWeek) select d; //Copying the IEnumerable to a List selectedDates = selectedDatesQry.ToList(); } catch (Exception ex) { //Log error //... //And re-throw throw; } return selectedDates; } 

Esto devolverá una colección de enteros que muestra cuántas veces ocurre cada día de la semana dentro de un rango de fechas

  int[] CountDays(DateTime firstDate, DateTime lastDate) { var totalDays = lastDate.Date.Subtract(firstDate.Date).TotalDays + 1; var weeks = (int)Math.Floor(totalDays / 7); var result = Enumerable.Repeat(weeks, 7).ToArray(); if (totalDays % 7 != 0) { int firstDayOfWeek = (int)firstDate.DayOfWeek; int lastDayOfWeek = (int)lastDate.DayOfWeek; if (lastDayOfWeek < firstDayOfWeek) lastDayOfWeek += 7; for (int dayOfWeek = firstDayOfWeek; dayOfWeek <= lastDayOfWeek; dayOfWeek++) result[dayOfWeek % 7]++; } return result; } 

O una pequeña variación que le permite hacer FirstDate.TotalDaysOfWeeks (SecondDate) y devuelve un Dictionary

  public static Dictionary TotalDaysOfWeeks(this DateTime firstDate, DateTime lastDate) { var totalDays = lastDate.Date.Subtract(firstDate.Date).TotalDays + 1; var weeks = (int)Math.Floor(totalDays / 7); var resultArray = Enumerable.Repeat(weeks, 7).ToArray(); if (totalDays % 7 != 0) { int firstDayOfWeek = (int)firstDate.DayOfWeek; int lastDayOfWeek = (int)lastDate.DayOfWeek; if (lastDayOfWeek < firstDayOfWeek) lastDayOfWeek += 7; for (int dayOfWeek = firstDayOfWeek; dayOfWeek <= lastDayOfWeek; dayOfWeek++) resultArray[dayOfWeek % 7]++; } var result = new Dictionary(); for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) result[(DayOfWeek)dayOfWeek] = resultArray[dayOfWeek]; return result; } 

Tuve un problema similar para un informe. Necesitaba el número de días hábiles entre dos fechas. Podría haber recorrido las fechas y contado, pero mi discreta capacitación en matemáticas no me lo permitió. Aquí hay una función que escribí en VBA para obtener el número de días de trabajo entre dos fechas. Estoy seguro de que .net tiene una función WeekDay similar.

  1 2 ' WorkDays 3 ' returns the number of working days between two dates 4 Public Function WorkDays(ByVal dtBegin As Date, ByVal dtEnd As Date) As Long 5 6 Dim dtFirstSunday As Date 7 Dim dtLastSaturday As Date 8 Dim lngWorkDays As Long 9 10 ' get first sunday in range 11 dtFirstSunday = dtBegin + ((8 - Weekday(dtBegin)) Mod 7) 12 13 ' get last saturday in range 14 dtLastSaturday = dtEnd - (Weekday(dtEnd) Mod 7) 15 16 ' get work days between first sunday and last saturday 17 lngWorkDays = (((dtLastSaturday - dtFirstSunday) + 1) / 7) * 5 18 19 ' if first sunday is not begin date 20 If dtFirstSunday <> dtBegin Then 21 22 ' assume first sunday is after begin date 23 ' add workdays from begin date to first sunday 24 lngWorkDays = lngWorkDays + (7 - Weekday(dtBegin)) 25 26 End If 27 28 ' if last saturday is not end date 29 If dtLastSaturday <> dtEnd Then 30 31 ' assume last saturday is before end date 32 ' add workdays from last saturday to end date 33 lngWorkDays = lngWorkDays + (Weekday(dtEnd) - 1) 34 35 End If 36 37 ' return working days 38 WorkDays = lngWorkDays 39 40 End Function 
 private System.Int32 CountDaysOfWeek(System.DayOfWeek dayOfWeek, System.DateTime date1, System.DateTime date2) { System.DateTime EndDate; System.DateTime StartDate; if (date1 > date2) { StartDate = date2; EndDate = date1; } else { StartDate = date1; EndDate = date2; } while (StartDate.DayOfWeek != dayOfWeek) StartDate = StartDate.AddDays(1); return EndDate.Subtract(StartDate).Days / 7 + 1; } 

Cuatro años después, pensé que haría una prueba:

 [TestMethod] public void ShouldFindFridaysInTimeSpan() { //reference: http://stackoverflow.com/questions/248273/count-number-of-mondays-in-a-given-date-range var spanOfSixtyDays = new TimeSpan(60, 0, 0, 0); var setOfDates = new List(spanOfSixtyDays.Days); var now = DateTime.Now; for(int i = 0; i < spanOfSixtyDays.Days; i++) { setOfDates.Add(now.AddDays(i)); } Assert.IsTrue(setOfDates.Count == 60, "The expected number of days is not here."); var fridays = setOfDates.Where(i => i.DayOfWeek == DayOfWeek.Friday); Assert.IsTrue(fridays.Count() > 0, "The expected Friday days are not here."); Assert.IsTrue(fridays.First() == setOfDates.First(i => i.DayOfWeek == DayOfWeek.Friday), "The expected first Friday day is not here."); Assert.IsTrue(fridays.Last() == setOfDates.Last(i => i.DayOfWeek == DayOfWeek.Friday), "The expected last Friday day is not here."); } 

Mi uso de TimeSpan es un poco exagerado — en realidad quería consultar TimeSpan directamente.