2009-07-07 39 views
9

Estoy creando un sistema de gestión de bibliotecas.¿Cómo calculo el número de días, menos los domingos, entre dos fechas en C#?

He utilizado la marca de tiempo para calcular la diferencia de fecha y con la ayuda de la diferencia de fecha también estoy calculando la multa.

Ahora esta diferencia de fecha incluye todos los días de la semana. Sin embargo, para una aplicación de la biblioteca, la multa se debe cobrar solo durante 6 días (de lunes a sábado) en la semana.

No puedo hacer esto.

¿Alguien puede ayudarme en la realización de esta tarea?

Gracias de antemano!

Respuesta

17

Esencialmente, puede calcular el número bruto de días; necesita encontrar el número de domingos a restar de ese número. Usted sabe que cada 7 días es un domingo, por lo que puede dividir su número bruto de días entre 7 y restar ese número del número bruto de días. Ahora necesita eliminar el número de domingos en el resto de la semana que existe; un mod del número bruto de días le indicará los días restantes. Para saber si ese lapso incluye un domingo, debe saber el día de la semana del primer día; si define Monday para ser 0, Tuesday para ser 1, Wednesday para ser 3, etc., luego si agrega el valor del día de la semana del inicio del lapso al mod (7) del número bruto de días, si el número es 6 o mayor, ha abarcado un domingo adicional, y debe eliminar 1 día de su número fino.

En pseudocódigo:

int fine; 
int numdays = endDay - startDay; 

fine = numdays - (numdays/7); 

int dayOfWeek = startDate.DayOfWeek; 
if (dayOfWeek + (numdays % 7) > 6) 
{ 
    fine = fine - 1; 
} 
+0

Gracias por su respuesta. Excelente explicación ¿Puede representar la explicación programáticamente por medio de la codificación? – sheetal

+0

Seudocódigo agregado. –

8

Esto lo hará:

private int DaysLate(DateTime dueDate, DateTime returnDate) 
{ 
    var ts = returnDate - dueDate; 
    int dayCount = 0; 

    for (int i = 1; i <= ts.Days; i++) 
    { 
     if (dueDate.AddDays(i).DayOfWeek != DayOfWeek.Sunday) 
      dayCount++; 
    } 

    return dayCount; 
} 
+0

Aprovechar las clases TimeSpan/Date definitivamente es el camino a seguir para IMO. –

+2

La mejor respuesta hasta ahora. Pero: en general, es un "olor" utilizar "DateTime.Now". Por ejemplo, ¿cómo probar esto? Es posible que el resultado de la prueba unitaria sea diferente los lunes de martes. Mejor, entonces, agregar un parámetro, p. "DateTime returnedDate" y reste dueDate de esto. En segundo lugar, tenga mucho cuidado con DateTime.Now. Calcula la fecha y hora actual, teniendo en cuenta las zonas horarias. Cosas extrañas pueden suceder dos veces al año alrededor del horario en que cambia el horario de verano. –

+0

@Jeremy: buenos puntos. Modifiqué la función según tu sugerencia. – raven

1

probado esto de forma rápida y parece que funciona para sus propósitos: (edit: añaden algunos comentarios para claridad y corregir errores de código)

private static int CalculateDaysToFine(DateTime dateDue, DateTime dateIn) 
     { 
      TimeSpan ts = dateIn - dateDue; 
      int daysToFine = ts.Days - (ts.Days/7); //subtract full weeks (1 Sunday each) 
      if (((int)dateDue.DayOfWeek + (ts.Days%7)) >6) //check to see if the remaining days contain a Sunday 
       daysToFine--; 
      return daysToFine; 
     } 
+1

Si mi respuesta va a ser rechazada, ¿alguien puede dar una razón al menos? Me gustaría saber por qué esto no funcionará. – Chuck

-2

Mi enfoque Linqy (tiene la virtud de ser más fácil de leer, pero tiene una menor perf ormance golpe de crear una lista de tipos de estructuras):

private int DaysLate(DateTime dateDue, DateTime dateReturned) 
{ 
    return getDayList(dateDue, dateReturned).Where(d => d.DayOfWeek != DayOfWeek.Sunday).Count(); 
} 

private List<DateTime> getDayList(DateTime begin, DateTime end) 
{ 
    List<DateTime> dates = new List<DateTime>(); 
    DateTime counter = begin; 
    while (counter <= end) 
    { 
     dates.Add(counter); 
     counter = counter.AddDays(1); 
    } 
    return dates; 
} 
+2

Este es el ejemplo menos eficaz de todas las respuestas. Es O (N2) donde una simple operación matemática sería suficiente. –

+0

Sí, me gusta más la respuesta de zvolkov. Aunque no estoy terriblemente impresionado por el voto negativo. Niños punk. –

2

Sobre la base de Jacob Proffitt respuesta, pero sin la sobrecarga de lista en memoria. Desde el DaysBetween produce sus fechas de forma dinámica, el recuento se calcula como se genera la lista:

int c = DaysBetween(begin, end).Count(d => d.DayOfWeek != DayOfWeek.Sunday); 

private IEnumerable<DateTime> DaysBetween(DateTime begin, DateTime end) 
{ 
    for(var d = begin; d <= end; d.AddDays(1)) yield return d; 
} 

Por supuesto, si no quería showoff LINQ se podía simplificar e ir con una función:

private int DaysBetween(DateTime begin, DateTime end) 
{ 
    int count = 0; 
    for(var d = begin; d <= end; d.AddDays(1)) 
     if(d.DayOfWeek != DayOfWeek.Sunday) count++ 
    return count; 
} 

En mi humilde opinión, ambos son más limpios y fáciles de entender, depurar, solucionar y modificar que los favoritos de todos (respuesta de cuervo).

Por supuesto, esta es una solución O (n), lo que significa que cuanto más separados están los días, más tiempo se tarda en calcular. Si bien esto puede ser aceptable para la mayoría de aplicaciones del mundo real, en algunos casos puede ser preferible un enfoque basado en una fórmula, algo a lo largo de estas líneas:

int q = end.Subtract(begin).Days - (end.Subtract(begin).Days/7); 
0

Aquí es mi aplicación. Mi objetivo era O (1) tiempo de ejecución usando un enfoque similar a McWafflestix.Traté de mantenerlo legible, maximizando el código OO y minimizando la "magia matemática" tanto como sea posible (no es que tenga nada en contra de las matemáticas ... o la magia para el caso).

La idea es determinar el número de semanas completas de 7 días entre la fecha de vencimiento y la fecha de regreso, y un número "delta" de días para ajustarlo para corregir el número. Siempre que pueda garantizar que ni la fecha de vencimiento ni la fecha de devolución caen en domingo (lo cual supongo que a partir de su descripción no será un problema), esto funcionará como se esperaba.

 
     static int CalculateFineDays(DateTime due, DateTime returned) 
     { 
      TimeSpan ts = returned - due; 
      if (ts < TimeSpan.Zero) 
       return 0;
int delta = returned.DayOfWeek - due.DayOfWeek; return delta + ts.Subtract(TimeSpan.FromDays(delta)).Days * 6/7; }

Edit: se había planteado una solución anterior y se encontró un error en ella, y ya que estaba trabajando en él que reduce el código reduce a esto.

Cuestiones relacionadas