2010-06-17 107 views
12

Para los fines de esta pregunta, supongamos que el usuario será de EE. UU. Y utilizará el calendario gregoriano estándar. Entonces, una semana calendario comienza el domingo y termina el sábado.Obtenga el número de semanas calendario entre 2 fechas en C#

Lo que estoy tratando de hacer es determinar el número de semanas calendario que existen entre dos fechas. Un ejemplo perfecto de mi problema existe en octubre de 2010. Entre el 10/16 y el 10/31 hay 4 semanas calendario.


  1. 10 10 hasta 10 16
  2. 10 17 hasta 10 23
  3. 10 24 hasta 10 30
  4. octubre 31 a noviembre 6

preferiría permanecer lejos de cualquier lógica codificada como:

if (Day == DayOfWeek.Saturday && LastDayOfMonth == 31) { ... } 

¿Puede alguien pensar en una forma lógica de hacer esto?

ACTUALIZACIÓN:
Gracias por todas las grandes respuestas, después de cierta consideración aquí es la solución utilicé:

//get the start and end dates of the current pay period 
DateTime currentPeriodStart = SelectedPeriod.Model.PeriodStart; 
DateTime currentPeriodEnd = SelectedPeriod.Model.PeriodEnd; 

//get the first sunday & last saturday span that encapsulates the current pay period 
DateTime firstSunday = DayExtensions.SundayBeforePeriodStart(currentPeriodStart); 
DateTime lastSaturday = DayExtensions.SaturdayAfterPeriodEnd(currentPeriodEnd); 

//get the number of calendar weeks in the span 
int numberOfCalendarWeeks = DayExtensions.CalendarWeeks(firstSunday, lastSaturday); 

Y aquí están los métodos de la clase de ayuda:

/// <summary> 
    /// Get the first Sunday before the pay period start date 
    /// </summary> 
    /// <param name="periodStartDate">Date of the pay period start date</param> 
    /// <returns></returns> 
    public static DateTime SundayBeforePeriodStart(DateTime periodStartDate) 
    { 
     DateTime firstDayOfWeekBeforeStartDate; 

     int daysBetweenStartDateAndPreviousFirstDayOfWeek = (int)periodStartDate.DayOfWeek - (int)DayOfWeek.Sunday; 

     if (daysBetweenStartDateAndPreviousFirstDayOfWeek >= 0) 
     { 
      firstDayOfWeekBeforeStartDate = periodStartDate.AddDays(-daysBetweenStartDateAndPreviousFirstDayOfWeek); 
     } 
     else 
     { 
      firstDayOfWeekBeforeStartDate = periodStartDate.AddDays(-(daysBetweenStartDateAndPreviousFirstDayOfWeek + 7)); 
     } 

     return firstDayOfWeekBeforeStartDate; 
    } 

    /// <summary> 
    /// Get the first Saturday after the period end date 
    /// </summary> 
    /// <param name="periodEndDate">Date of the pay period end date</param> 
    /// <returns></returns> 
    public static DateTime SaturdayAfterPeriodEnd(DateTime periodEndDate) 
    { 
     DateTime lastDayOfWeekAfterEndDate; 

     int daysBetweenEndDateAndFollowingLastDayOfWeek = (int)DayOfWeek.Saturday - (int)periodEndDate.DayOfWeek; 

     if (daysBetweenEndDateAndFollowingLastDayOfWeek >= 0) 
     { 
      lastDayOfWeekAfterEndDate = periodEndDate.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek); 
     } 
     else 
     { 
      lastDayOfWeekAfterEndDate = periodEndDate.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek + 7); 
     } 

     return lastDayOfWeekAfterEndDate; 
    } 

    /// <summary> 
    /// Get the calendar weeks between 2 dates 
    /// </summary> 
    /// <param name="d1">First day of date span</param> 
    /// <param name="d2">Last day of date span</param> 
    /// <returns></returns> 
    public static int CalendarWeeks(DateTime d1, DateTime d2) 
    { 
     return 1 + (int)((d2 - d1).TotalDays/7); 
    } 

Y si tienes curiosidad, esto es lo que termino haciendo con las fechas:

//create an array of all the sundays in this span 
DateTime[] _sundays = new DateTime[numberOfCalendarWeeks]; 

//put the first sunday in the period 
_sundays[0] = firstSunday; 

//step through each week and get each sunday until you reach the last saturday 
for (int i = 1; i <= numberOfCalendarWeeks - 1; i++) 
{ 
    DateTime d = new DateTime(); 
    d = firstSunday.AddDays(i * 7); 
     _sundays[i] = d; 
} 

for (int i = 0; i <= _sundays.Length-1; i++) 
{ 
     //bind my view model with each sunday. 
} 
+0

Si he entendido bien, desea que el número de semanas completas (que creo que debería ser de * Lunes * a domingo) entre dos fechas dadas, por lo que a partir del jueves, 18 de junio al Miércoles, 24 de junio de usted no tendría una semana (como en 7 días), pero ninguna, ya que solo pasas el lunes una vez, y no alcanzas el domingo después, ¿es correcto? – Treb

+0

Esta aplicación en particular requiere Sun-Sat. Piense en 2 períodos de pago en un mes (período de 10/1 y el período de 10/16). Una semana de trabajo en este escenario es Sun-Sat. Por lo tanto, el período de pago 10/16 se ejecuta a través de 4 semanas calendario. ¿Tener sentido? –

+0

¿Está buscando un enfoque de fórmula simple, o está bien con un enfoque algorítmico? Además, ¿qué tan importante sería que la fórmula/algoritmo tenga en cuenta los años/días bisiestos, etc.? – jrista

Respuesta

6

Aquí hay una solución general que creo que debería funcionar para cualquier elección de días de inicio y fin de semana. Puede simplificarlo para su caso, pero este código le da la opción de cambiar el inicio y el fin de la semana (por ejemplo, de lunes a domingo) si es necesario. No es raro en las aplicaciones de nómina cambiar la definición de una semana calendario.

 DateTime periodStart = new DateTime(2010, 10, 17); 
     DateTime periodEnd = new DateTime(2010, 11, 14); 

     const DayOfWeek FIRST_DAY_OF_WEEK = DayOfWeek.Monday; 
     const DayOfWeek LAST_DAY_OF_WEEK = DayOfWeek.Sunday; 
     const int DAYS_IN_WEEK = 7; 

     DateTime firstDayOfWeekBeforeStartDate; 
     int daysBetweenStartDateAndPreviousFirstDayOfWeek = (int)periodStart.DayOfWeek - (int)FIRST_DAY_OF_WEEK; 
     if (daysBetweenStartDateAndPreviousFirstDayOfWeek >= 0) 
     { 
      firstDayOfWeekBeforeStartDate = periodStart.AddDays(-daysBetweenStartDateAndPreviousFirstDayOfWeek); 
     } 
     else 
     { 
      firstDayOfWeekBeforeStartDate = periodStart.AddDays(-(daysBetweenStartDateAndPreviousFirstDayOfWeek + DAYS_IN_WEEK)); 
     } 

     DateTime lastDayOfWeekAfterEndDate; 
     int daysBetweenEndDateAndFollowingLastDayOfWeek = (int)LAST_DAY_OF_WEEK - (int)periodEnd.DayOfWeek; 
     if (daysBetweenEndDateAndFollowingLastDayOfWeek >= 0) 
     { 
      lastDayOfWeekAfterEndDate = periodEnd.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek); 
     } 
     else 
     { 
      lastDayOfWeekAfterEndDate = periodEnd.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek + DAYS_IN_WEEK); 
     } 

     int calendarWeeks = 1 + (int)((lastDayOfWeekAfterEndDate - firstDayOfWeekBeforeStartDate).TotalDays/DAYS_IN_WEEK); 
0
private static int weekDifference(DateTime startDate, DateTime endDate) 
{ 
int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month; 
return Math.Abs(monthsApart*4); 
} 

canto considera una mejor manera la derecha del palo.

0
private static int weekDifference(DateTime startDate, DateTime endDate) 
{ 
    const int firstDayOfWeek = 0; // Sunday 
    int wasteDaysStart = (7+startDate.DatOfWeek-firstDayOfWeek)%7; 
    return (int)(((endDate-startDate).TotalDays() + wasteDaysStart + 6)/7); 
} 

Advertencia: código no probado. Por favor, prueba y elimina la nota.

+0

(31/10/2010) - (10/16/2010) devuelve 15. 15/7 = 2.14. ¿Cómo puedo truncar de manera diferente para obtener 4 de 2.14? –

+2

Creo que esto solo encuentra el número de intervalos de 7 días entre dos fechas ... no el número de semanas calendario abarcadas por el rango de fechas. Tenga en cuenta que la fecha puede coincidir con el último día de la semana o el primer día de la semana, lo que significa que abarca todas las semanas completas, así como la semana en la que cayó el primer día del último día de la semana y el semana donde el último día cayó en el primer día de la semana. Dado que ... no creo que este cálculo resuelva el problema en el PO. – jrista

+0

gracias, código fijo, ahora que entendí tu pregunta :) por favor, prueba cuidadosamente. –

4

Tenga en cuenta, que los cálculos de la semana se hacen de manera diferente en diferentes culturas y no hay ningún error si ve la semana número 53!

using System.Globalization; 

CultureInfo cultInfo = CultureInfo.CurrentCulture; 
int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now, 
        cultInfo.DateTimeFormat.CalendarWeekRule, 
         cultInfo.DateTimeFormat.FirstDayOfWeek); 
+0

¡Buen punto sobre la dependencia cultural! – Treb

5

La forma en que abordaría esto es llegar al comienzo de la semana para cualquier fecha. Al usar eso, restarías el resultado de la fecha de inicio del resultado de la fecha de finalización. La diferencia de su día siempre sería un múltiplo de 7, por lo tanto, divida y agregue 1 (0 días => 1 semana, 7 días => 2 semanas, etc.). Esto le indicaría cuántas semanas del calendario estuvieron cubiertas o representadas por dos fechas cualquiera.

static int GetWeeksCovered(DateTime startDate, DateTime endDate) 
{ 
    if (endDate < startDate) 
     throw new ArgumentException("endDate cannot be less than startDate"); 

    return (GetBeginningOfWeek(endDate).Subtract(GetBeginningOfWeek(startDate)).Days/7) + 1; 
} 

static DateTime GetBeginningOfWeek(DateTime date) 
{ 
    return date.AddDays(-1 * (int)date.DayOfWeek).Date; 
} 
  • 16-Oct-2010 y 16-Oct-2010 => 1 semana a cubierto (o representados).
  • 16-oct-2010 y 31-oct-2010 => 4 semanas cubiertas, según la especificación.
0

Lo siguiente parece funcionar para cualquier intervalo de fechas. Debe ser sonido culturalmente, y debe tener en cuenta los años bisiestos/día u otras rarezas naturales:

private static int getWeeksSpannedBy(DateTime first, DateTime last) 
    { 
     var calendar = CultureInfo.CurrentCulture.Calendar; 
     var weekRule = CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule; 
     var firstDayOfWeek = DayOfWeek.Sunday; 

     int lastWeek = calendar.GetWeekOfYear(last, weekRule, firstDayOfWeek); 
     int firstWeek = calendar.GetWeekOfYear(first, weekRule, firstDayOfWeek); 

     int weekDiff = lastWeek - firstWeek + 1; 

     return weekDiff; 
    } 

    static void Main(string[] args) 
    { 
     int weeks1 = getWeeksSpannedBy(new DateTime(2010, 1, 3), new DateTime(2010, 1, 9)); 
     int weeks2 = getWeeksSpannedBy(new DateTime(2010, 10, 16), new DateTime(2010, 10, 31)); 
     int weeks3 = getWeeksSpannedBy(new DateTime(2008, 2, 1), new DateTime(2008, 2, 29)); 
     int weeks4 = getWeeksSpannedBy(new DateTime(2012, 2, 1), new DateTime(2012, 2, 29)); 

     Console.WriteLine("Weeks Difference #1: " + weeks1); 
     Console.WriteLine("Weeks Difference #2: " + weeks2); 
     Console.WriteLine("Weeks Difference #3: " + weeks3); 
     Console.WriteLine("Weeks Difference #4: " + weeks4); 
     Console.ReadLine(); 
    } 

imprime el siguiente, que es correcto para todos los rangos de fechas, pasado, presente o futuro (año bisiesto 2008 y 2012 ambos tienen 5 semanas entre Feb 1 y 29 de febrero):

Semanas Diferencia # 1: 1
Semanas Diferencia # 2: 4
Semanas Diferencia # 3: 5
Semanas Diferencia # 4: 5

0

El sábado es el último día de la semana ¿eh?

public int CalendarWeeks(DateTime from, DateTime to) { 

    // number of multiples of 7 
    // (rounded up, since 15 days would span at least 3 weeks) 
    // and if we end on a day before we start, we know it's another week 

    return (int)Math.Ceiling(to.Subtract(from).Days/7.0) + 
      (to.DayOfWeek <= from.DayOfWeek) ? 1 : 0; 
} 
Cuestiones relacionadas