2009-02-02 69 views
18

Necesito obtener una lista de semanas para un mes determinado, con el lunes como el día de inicio.C# - ¿Cuál es la mejor manera de obtener una lista de las semanas en un mes, dado un día de semana que comienza?

Así, por ejemplo, para el mes de febrero de 2009, este método podría volver:

2/2/2009 
2/9/2009 
2/16/2009 
2/23/2009 
+0

Dang, y tenía una forma muy buena de hacer esto en VB.NET. – ChrisA

+0

¡Estaba a punto de hacer esta pregunta yo mismo - +1 por haberla preguntado por mí! :) –

Respuesta

25
// Get the weeks in a month 

DateTime date = DateTime.Today; 
// first generate all dates in the month of 'date' 
var dates = Enumerable.Range(1, DateTime.DaysInMonth(date.Year, date.Month)).Select(n => new DateTime(date.Year, date.Month, n)); 
// then filter the only the start of weeks 
var weekends = from d in dates 
       where d.DayOfWeek == DayOfWeek.Monday 
       select d; 
+0

¡Muy listo! +1 para hacer que el código sea más claro con LINQ –

+0

¡esto me ha ahorrado unas dos horas! – roryok

+0

¡He adaptado tu solución y funciona muy bien! muy apreciado, gracias. –

0

Sólo cambia la línea de respuesta a lo que cada vez que hay que hacer con él

protected void PrintDay(int year, int month, DayOfWeek dayName) 
{ 
    CultureInfo ci = new CultureInfo("en-US"); 
    for (int i = 1 ; i <= ci.Calendar.GetDaysInMonth (year, month); i++) 
    { 
    if (new DateTime (year, month, i).DayOfWeek == dayName) 
     Response.Write (i.ToString() + "<br/>"); 
    } 
} 

solución rápida : no creo que haya una función incorporada ...

+0

Si utiliza este enfoque, es posible que desee izar primero la llamada GetDaysInMonth, en lugar de volver a calcularla para cada día (más 1). –

10
public static List<DateTime> GetWeeks(
    this DateTime month, DayOfWeek startOfWeek) 
{ 
    var firstOfMonth = new DateTime(month.Year, month.Month, 1); 
    var daysToAdd = ((Int32)startOfWeek - (Int32)month.DayOfWeek) % 7; 
    var firstStartOfWeek = firstOfMonth.AddDays(daysToAdd); 

    var current = firstStartOfWeek; 
    var weeks = new List<DateTime>(); 
    while (current.Month == month.Month) 
    { 
     weeks.Add(current); 
     current = current.AddDays(7); 
    } 

    return weeks; 
} 
+0

En lugar de ser inteligente con AddDays, simplemente actualice un nuevo DateTime reemplazando el día por 1. ¿No es eso más claro? – Larsenal

+0

Robert's es el patrón con el que fui, pero modifiqué su código en un método de extensión. ¡Gracias! –

+0

@Larsenal - es un poco más complicado que eso - reemplazar el día con uno nos daría el primero del mes, pero también necesitamos el primer día del mes que es el comienzo de una nueva semana, según el día en que se especifica como el comienzo de una semana. –

0

Algo como el pseudocódigo siguiente debería funcionar:

  • determinar la fecha de inicio del mes (utilización mes y año a partir de una fecha y establecer el día a 1
  • determinar la fecha final del mes (fecha de inicio + 1 mes)
  • determinar la primera fecha que es un lunes (este es su primer elemento de la lista)
  • Añadir 7 días para encontrar la próxima fecha y repetir hasta que haya leído o pasar el fin de mes
1
int year = 2009; 
int month = 2; 
DateTime startDate = new DateTime(year, month, 1); 
DateTime endDate = startDate.AddMonths(1); 
while (startDate.DayOfWeek != DayOfWeek.Monday) 
    startDate = startDate.AddDays(1); 
for (DateTime result = startDate; result < endDate; result = result.AddDays(7)) 
    DoWhatYouWant(result); 
1

¿Qué tal esto?

public IEnumerable<DateTime> GetWeeks(DateTime date, DayOfWeek startDay) 
    { 
    var list = new List<DateTime>(); 
    DateTime first = new DateTime(date.Year, date.Month, 1); 

    for (var i = first; i < first.AddMonths(1); i = i.AddDays(1)) 
    { 
     if (i.DayOfWeek == startDay) 
      list.Add(i); 
    } 

    return list; 
    } 
3

he aquí una solución (de hecho, una línea) usando C# 3.0/LINQ, en caso de que esté interesado:

var month = new DateTime(2009, 2, 1); 
var weeks = Enumerable.Range(0, 4).Select(n => month.AddDays(n * 7 - (int)month.DayOfWeek + 1)).TakeWhile(monday => monday.Month == month.Month); 
0

Veo que tienes tu respuesta, pero quería compartir con ustedes una clase de ayuda que creé para uno de mis proyectos. Está lejos de ser una clase comprehansive, pero podría ayudar ...

public static class WeekHelper { 

#region Public Methods 
public static DateTime GetWeekStart(DateTime date) { 
    DateTime weekStart; 
    int monday = 1; 
    int crtDay = (int)date.DayOfWeek; 
    if (date.DayOfWeek == DayOfWeek.Sunday) 
     crtDay = 7; 
    int difference = crtDay - monday; 
    weekStart = date.AddDays(-difference); 
    return weekStart; 
} 
public static DateTime GetWeekStop(DateTime date) { 
    DateTime weekStart; 
    int sunday = 7; 
    int crtDay = (int)date.DayOfWeek; 
    if (date.DayOfWeek == DayOfWeek.Sunday) 
     crtDay = 7; 
    int difference = sunday - crtDay; 
    weekStart = date.AddDays(difference); 
    return weekStart; 
} 
public static void GetWeekInterval(int year, int weekNo, 
    out DateTime weekStart, out DateTime weekStop) { 
    GetFirstWeekOfYear(year, out weekStart, out weekStop); 
    if (weekNo == 1) 
     return; 
    weekNo--; 
    int daysToAdd = weekNo * 7; 
    DateTime dt = weekStart.AddDays(daysToAdd); 
    GetWeekInterval(dt, out weekStart, out weekStop); 
} 
public static List<KeyValuePair<DateTime, DateTime>> GetWeekSeries(DateTime toDate) { 
    //gets week series from beginning of the year 
    DateTime dtStartYear = new DateTime(toDate.Year, 1, 1); 
    List<KeyValuePair<DateTime, DateTime>> list = GetWeekSeries(dtStartYear, toDate); 
    if (list.Count > 0) { 
     KeyValuePair<DateTime, DateTime> week = list[0]; 
     list[0] = new KeyValuePair<DateTime, DateTime>(dtStartYear, week.Value); 
    } 
    return list; 
} 
public static List<KeyValuePair<DateTime, DateTime>> GetWeekSeries(DateTime fromDate, DateTime toDate) { 
    if (fromDate > toDate) 
     return null; 
    List<KeyValuePair<DateTime, DateTime>> list = new List<KeyValuePair<DateTime, DateTime>>(100); 
    DateTime weekStart, weekStop; 
    toDate = GetWeekStop(toDate); 
    while (fromDate <= toDate) { 
     GetWeekInterval(fromDate, out weekStart, out weekStop); 
     list.Add(new KeyValuePair<DateTime, DateTime>(weekStart, weekStop)); 
     fromDate = fromDate.AddDays(7); 
    } 
    return list; 
} 
public static void GetFirstWeekOfYear(int year, out DateTime weekStart, out DateTime weekStop) { 
    DateTime date = new DateTime(year, 1, 1); 
    GetWeekInterval(date, out weekStart, out weekStop); 
} 
public static void GetWeekInterval(DateTime date, 
    out DateTime dtWeekStart, out DateTime dtWeekStop) { 
    dtWeekStart = GetWeekStart(date); 
    dtWeekStop = GetWeekStop(date); 
} 
#endregion Public Methods 

}

0

Esto funciona muy bien! Todo lo que tiene que hacer es obtener el primer día del mes para el que desea obtener las semanas y luego esto le dará el primer día de cada semana. Usted tiene que estar 5 semanas (no 4) por lo que el Enumerable.Range conteos de salida 5 en lugar de 4.

var date = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); 
var weeks = from n in Enumerable.Range(0, 5) 
    select date.AddDays(7 * n + (-1 * (int)date.DayOfWeek)); 
0

Esto es lo que hice, usando el código de Chaowlert como base de partida. Básicamente modifiqué que necesita verificar si agrega los días en los desbordamientos para el próximo mes, por lo que no agrego 4 días (de lunes a viernes), pero en realidad el mínimo entre 4 y el número de días restantes en el mes . Además, verifico si el día actual es un fin de semana, de lo contrario agregar días hasta que sea un día de la semana. Mi propósito es imprimir las semanas en un mes, de lunes a viernes

DateTime fechaInicio = new DateTime(año, mes, 1); 
DateTime fechaFin = fechaInicio.AddMonths(1); 
int diasHastaFinMes = 0; 
while (esFinDeSemana(fechaInicio)) 
    fechaInicio = fechaInicio.AddDays(1); 
for (DateTime fecha = fechaInicio; fecha < fechaFin; fecha = fecha.AddDays(7)) 
{ 
    diasHastaFinMes = DateTime.DaysInMonth(fecha.Year, fecha.Month) - fecha.Day; 
    printWeeks(fecha, fecha.AddDays(Math.Min(4, diasHastaFinMes))); 
} 
Cuestiones relacionadas