2010-09-14 14 views
8

necesito ayuda. Necesito contar los días hábiles regulares para un período dado, por ejemplo, en nuestro país, tenemos 5 días hábiles regulares de lunes a viernes, luego, en el código, debo excluir los sábados y domingos cuando lo uso en mis cálculos.Contando días laborables regulares en un período de tiempo dado

Necesito un algoritmo algo como esto en C#:.

int GetRegularWorkingDays(DateTime startDate, DateTime endDate) 
    { 

     int nonWorkingDays = ((endDate - startDate) % 7) * 2; 

     return (endDate - startDate) - nonWorkingDays; 
    } 

Sé que mi proyecto es manera lejos :(Gracias de antemano =)

PS:. Chicos por favor, arriba-voto la mejor/más rápida/más eficiente respuesta a continuación. Gracias =)

+3

¿Cómo desea para tratar las vacaciones? – kbrimington

+0

Eso también es una pregunta, pero mi solución está anulando algo en mi cálculo. Las vacaciones regulares aquí en nuestro país varían constantemente. Y no quiero decir, crear una tabla de Calendario solo para mantenerla. – CSharpNoob

Respuesta

18

Salida this example on Code Project que utiliza una forma muy eficiente que no implica ningún bucle;)

Utiliza este alogrithm:

  1. Calcular la cantidad de tiempo en términos de semanas. Llámelo, W.
  2. Deducir la primera semana del número de semanas. W = W-1
  3. Multiplique el número de semanas con el número de días hábiles por semana. Llámelo, D.
  4. Averigüe las vacaciones durante el período de tiempo especificado. Llámelo, H.
  5. Calcule los días de la primera semana. Llámalo, SD.
  6. Calcule los días de la última semana. Llámalo, ED.
  7. Resumir todos los días. BD = D + SD + ED H.
+5

Esto es realmente clave. Si tiene un lapso de 6 o 7 (o 66 o 77) semanas, no necesita iterar semana tras semana omitiendo Sat y Sun. La primera semana y la última semana son casos especiales, no se sabe si el lapso incluye los días de la semana o los fines de semana, pero el gran centro es solo 5 días laborables menos festivos. Esto te ahorrará una gran cantidad de cálculos. –

+0

+1: No estoy seguro de por qué se vuelven a votar todos los bucles, cuando esta solución es esencialmente O (1) ... Sin embargo, el paso 4 no es obligatorio de acuerdo con la pregunta del OP. – Dirk

+0

actualmente leyéndolo. esto es interesante, sin bucles .. – CSharpNoob

2

Puede probar un método simple para contar los días. Si esto generalmente se hace por periodos de tiempo como meses y no años y no se llama repetidamente, entonces esto no será un golpe de rendimiento para simplemente caminar.

int GetWorkingDays(DateTime startDate, DateTime endDate) 
{ 
    int count = 0; 
    for (DateTime currentDate = startDate; currentDate < endDate; currentDate = currentDate.AddDays(1)) 
    { 
     if (currentDate.DayOfWeek == DayOfWeek.Sunday || currentDate.DayOfWeek == DayOfWeek.Saturday) 
     { 
      continue; 
     } 
     count++; 
    } 
    return count; 
} 
+0

También necesito hacer un seguimiento de los días no laborables, si reemplazo el contador continue with the noworkingdays ?? – CSharpNoob

+1

Primero debes tener la tabla almacenando todos los días festivos (predefinidos) y verificar si current_day coincide con day_holiday_table ... no debes contar eso y el resto son días laborables. –

+0

Tengo una solución diferente para tratar las vacaciones. y crear una tabla de base de datos solo para esto realmente no es mi opción. Acabo de querer contar los lunes y los viernes ... Gracias por cierto =) – CSharpNoob

2

No es muy rápido, pero esto va a hacer el truco:

int GetRegularWorkingDays(DateTime start, DateTime end) 
{ 
    return (
     from day in Range(start, end) 
     where day.DayOfWeek != DayOfWeek.Saturday 
     where day.DayOfWeek != DayOfWeek.Sunday 
     select day).Count(); 
} 

IEnumerable<DateTime> Range(DateTime start, DateTime end) 
{ 
    while (start <= end) 
    { 
     yield return start; 
     start = start.AddDays(1); 
    } 
} 
+0

Gracias señor, pero también necesito la más eficiente porque la usaré dentro de un bucle for con un promedio de 5000 filas ... gracias .. – CSharpNoob

4

de una sola línea!

int workingDays = Enumerable.Range(0, Convert.ToInt32(endDate.Subtract(startDate).TotalDays)).Select(i=>new [] { DayOfWeek.Saturday, DayOfWeek.Sunday }.Contains(startDate.AddDays(i).DayOfWeek) ? 0 : 1).Sum(); 

o más eficiente:

DayOfWeek currDay = startDate.DayOfWeek; 
int nonWorkingDays = 0; 

foreach(var i in Enumerable.Range(0, Convert.ToInt32(endDate.Subtract(startDate).TotalDays))) 
{ 
    if(currDay == DayOfWeek.Sunday || currDay == DayOfWeek.Saturday) 
      nonWorkingDays++; 
    if((int)++currDay > 6) currDay = (DayOfWeek)0; 
} 
+3

Yo don No lo llamo un trazador de líneas. Llamo a eso una línea muy larga :-) – Steven

+0

hombre esto impresionante, pero ¿qué hay de su eficacia? gracias, me refiero al rendimiento alcanzado – CSharpNoob

+0

Mwah, si no hace software de banco en realidad no le importa, pero está construyendo una matriz y un objeto datetime. Verifica mi edición para una forma eficiente de supa dupa. –

0

método simple para obtener días de trabajo:

int GetRegularWorkingDays(DateTime startDate, DateTime endDate) 
{ 
    int total = 0; 

    if (startDate < endDate) 
    { 
     var days = endDate - startDate; 

     for(; startDate < endDate; startDate = startDate.AddDays(1)) 
     { 
      switch(startDate.DayOfWeek) 
      { 
       case DayOfWeek.Saturday : 
       case DayOfWeek.Sunday :      
        break; 
       default: 
        total++; 
        break; 
      } 
     } 
    } 
    return total; 
} 
1

Usted podría hacerlo con una clase línea de ayudante de tiempo - esta clase también permite otras intervalos:

public class TimeLine 
{ 
    public static IEnumerable<DateTime> CreateTimeLine(DateTime start, TimeSpan interval) { 
     return TimeLine.CreateTimeLine(start, interval, DateTime.MaxValue); 
    } 

    public static IEnumerable<DateTime> CreateTimeLine(DateTime start, TimeSpan interval, DateTime end) { 
     var currentVal = start; 
     var endVal = end.Subtract(interval); 

     do { 
      currentVal = currentVal.Add(interval); 
      yield return currentVal; 
     } while (currentVal <= endVal); 
    } 
} 

Para resolver su problema, puede haga lo siguiente:

var workingDays = TimeLine.CreateTimeLine(DateTime.Now.Date, TimeSpan.FromDays(1), DateTime.Now.Date.AddDays(30)) 
          .Where(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday); 
var noOfWorkingDays = workingDays.Count(); 

Esta clase de línea de tiempo se puede utilizar para cualquier línea de tiempo continuo de cualquier intervalo.

4

Escribí un extensor de tipo para permitirme agregar (o restar) los días de la semana a una fecha determinada. Quizás esto te ayude. Funciona muy bien, así que por favor vote por mi publicación si esto lo ayudó.

/// <summary> 
    /// Adds weekdays to date 
    /// </summary> 
    /// <param name="value">DateTime to add to</param> 
    /// <param name="weekdays">Number of weekdays to add</param> 
    /// <returns>DateTime</returns> 
    public static DateTime AddWeekdays(this DateTime value, int weekdays) 
    { 
     int direction = Math.Sign(weekdays); 
     int initialDayOfWeek = Convert.ToInt32(value.DayOfWeek); 

     //--------------------------------------------------------------------------- 
     // if the day is a weekend, shift to the next weekday before calculating 
     if ((value.DayOfWeek == DayOfWeek.Sunday && direction < 0) 
      || (value.DayOfWeek == DayOfWeek.Saturday && direction > 0)) 
     { 
      value = value.AddDays(direction * 2); 
      weekdays += (direction * -1); // adjust days to add by one 
     } 
     else if ((value.DayOfWeek == DayOfWeek.Sunday && direction > 0) 
      || (value.DayOfWeek == DayOfWeek.Saturday && direction < 0)) 
     { 
      value = value.AddDays(direction); 
      weekdays += (direction * -1); // adjust days to add by one 
     } 
     //--------------------------------------------------------------------------- 

     int weeksBase = Math.Abs(weekdays/5); 
     int addDays = Math.Abs(weekdays % 5); 

     int totalDays = (weeksBase * 7) + addDays; 
     DateTime result = value.AddDays(totalDays * direction); 

     //--------------------------------------------------------------------------- 
     // if the result is a weekend, shift to the next weekday 
     if ((result.DayOfWeek == DayOfWeek.Sunday && direction > 0) 
      || (result.DayOfWeek == DayOfWeek.Saturday && direction < 0)) 
     { 
      result = result.AddDays(direction); 
     } 
     else if ((result.DayOfWeek == DayOfWeek.Sunday && direction < 0) 
      || (result.DayOfWeek == DayOfWeek.Saturday && direction > 0)) 
     { 
      result = result.AddDays(direction * 2); 
     } 
     //--------------------------------------------------------------------------- 

     return result; 
    } 
+0

También necesito esto ... muchas gracias =) – CSharpNoob

+0

tengo muchos de estos extensores de tipo que pongo en el espacio de nombres del sistema para que estén siempre disponibles. Me alegro de que esto pueda ayudarlo. ¡Tardó MUCHO tiempo en hacerlo bien! :) – Brad

+0

esto solo en .. Me encantan los métodos de extensión! – jlafay

0
int count = 0; 
switch (dateTimePicker2.Value.DayOfWeek.ToString()) 
{ 
    case "Saturday": count--; break; 
    case "Sunday": count--; break; 
    default:break; 
} 
switch (dateTimePicker3.Value.DayOfWeek.ToString()) 
{ 
    case "Saturday": count--; break; 
    case "Sunday": count--; break; 
    default:break; 
} 
if (count == -2) 
    count = -1; 
int weeks = t.Days/7; 
int daycount =count+ t.Days - (2 * weeks)+1; 
label7.Text = "No of Days : " + daycount.ToString(); 
Cuestiones relacionadas