2010-09-15 130 views
8

Tengo problemas para hacer esto. Estoy creando un método que agrega días hábiles en una fecha específica. por ejemplo, quiero agregar 3 días hábiles para el 15 de septiembre de 2010 (miércoles), el método volvería el 20 de septiembre (lunes de la próxima semana). no tiene en cuenta los sábados y domingos porque su inhábil ..C#: Agregando días hábiles a partir de una fecha de recepción

Algo como esto en C#:

DateTime AddWorkingDays(DateTime specificDate, int workingDaysToAdd) 
{ 
    return specificDate + (workingDaysToAdd - (all saturdays and sundays)) 
} 

no considero fiestas especiales en los cálculos, acabo literalmente quiere añadir días, excepto los sábados y domingos .. Gracias de antemano! =)

Respuesta

16

Si no es necesario tener en cuenta las vacaciones, yo sugeriría que hacer algo como esto:

public static DateTime AddWorkingDays(DateTime specificDate, 
             int workingDaysToAdd) 
{ 
    int completeWeeks = workingDaysToAdd/5; 
    DateTime date = specificDate.AddDays(completeWeeks * 7); 
    workingDaysToAdd = workingDaysToAdd % 5; 
    for (int i = 0; i < workingDaysToAdd; i++) 
    { 
     date = date.AddDays(1); 
     while (!IsWeekDay(date)) 
     { 
      date = date.AddDays(1); 
     } 
    } 
    return date; 
} 

private static bool IsWeekDay(DateTime date) 
{ 
    DayOfWeek day = date.DayOfWeek; 
    return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday; 
} 

Es ineficiente, pero fácil de entender. Para una versión eficiente, calcularía el número de semanas completas para agregar como antes, pero luego tendrá un mapeo desde "día actual de la semana" y "días hábiles restantes para agregar" a "número de real días hasta añadir". Luego, podría calcular la cantidad total de días para agregar y hacerlo en una sola llamada.

EDITAR: En términos del nivel de ineficiencia ... realmente no es muy malo. Solo realizará verificaciones manuales de "es un fin de semana" durante un máximo de 4 días, lo cual no es tan malo. En particular, a pesar de las afirmaciones de igor (actual en el momento de la publicación), es bastante más rápido que su enfoque, a pesar de los puntos de referencia defectuosos;)

Tenga en cuenta que puede que aún no maneje las entradas negativas. No lo he comprobado.

Una de las razones detrás del enfoque que estoy usando es que no depende de que yo o el lector de códigos sepa cuáles son los valores en la enumeración DayOfWeek. No me importa si es 0-6, 1-7, de lunes a domingo, de sábado a viernes ... o incluso si hay valores completamente extraños. Solo comparo por igualdad, lo que hace que el código sea más "obviamente correcto".

+0

Jon, ¿sería más eficiente usar 'workingDaysToAdd = workingDaysToAdd% 5; date = date.AddDays (workingDaysToAdd); if (date.DayOfWeek == DayOfWeek.Saturday) date.AddDays (2); if (date.DayOfWeek == DayOfWeek.Sunday) date.AddDays (1); 'en lugar de la construcción del bucle? Sólo curioso. – Lazarus

+0

Lo probé y funciona según lo que necesito exactamente. ¿Lo hiciste sobre la marcha? en menos de 5 minutos desde que lo publiqué ... hombre, eso es bastante increíble ... pero me gustaría obtener respuestas más eficientes ... gracias por cierto ... – CSharpNoob

+1

No diría que es ineficiente, pero todas las cosas son relativas. La respuesta cuenta durante semanas por adelantado, por lo que lo máximo que tendrá que hacer es 6 veces (máximo 4 para workingDays% 5, max 2 para fines de semana). No fue un golpe tremendo. –

0

Esto es lo que necesita:

Actualizado:

public static DateTime AddWeekdays(DateTime start, int days) 
    { 
     int remainder = days % 5; 
     int weekendDays = (days/5) * 2; 

     DateTime end = start.AddDays(remainder); 

     if (start.DayOfWeek == DayOfWeek.Saturday && days > 0) 
     { 
      // fix for saturday. 
      end = end.AddDays(-1); 
     } 

     if (end.DayOfWeek == DayOfWeek.Saturday && days > 0) 
     { 
      // add two days for landing on saturday 
      end = end.AddDays(2); 
     } 
     else if (end.DayOfWeek < start.DayOfWeek) 
     { 
      // add two days for rounding the weekend 
      end = end.AddDays(2); 
     } 

     // add the remaining days 
     return end.AddDays(days + weekendDays - remainder); 
    } 
+0

pero el parámetro de fecha y hora (inicio) también puede ser domingo y sábado .. :(.. si los sábados y el domingo, debe regresar el miércoles de la semana siguiente, – CSharpNoob

+0

Acabo de editar el hacer lo que solicitó. –

+0

¿No es así? un poco demasiado complicado?Creo que se puede hacer de una manera mucho más simple – tocqueville

0
int foundWorkingDays = 0; 
while (foundWorkingDays < workingDaysToAdd) 
{ 
    specificDate= specificDate.AddDays(1); 
    if(specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday) 
    foundWorkingDays++; 

} 
return specificDate; 

añadido:

class Program 
    { 

     public static DateTime AddWorkingDays(DateTime specificDate, 
             int workingDaysToAdd) 
     { 
      int completeWeeks = workingDaysToAdd/5; 
      DateTime date = specificDate.AddDays(completeWeeks * 7); 
      workingDaysToAdd = workingDaysToAdd % 5; 
      for (int i = 0; i < workingDaysToAdd; i++) 
      { 
       date = date.AddDays(1); 
       while (!IsWeekDay(date)) 
       { 
        date = date.AddDays(1); 
       } 
      } 
      return date; 
     } 

     private static bool IsWeekDay(DateTime date) 
     { 
      DayOfWeek day = date.DayOfWeek; 
      return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday; 
     } 

     public static DateTime MyAddWorkingDays(DateTime specificDate, 
             int workingDaysToAdd) 
     { 
      int foundWorkingDays = 0; 
      while (foundWorkingDays < workingDaysToAdd) 
      { 
       specificDate = specificDate.AddDays(1); 
       if (specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday) 
        foundWorkingDays++; 

      } 
      return specificDate; 
     } 


     static void Main(string[] args) 
     { 

      DateTime specificDate = DateTime.Now; 

      Stopwatch globalTimer = Stopwatch.StartNew(); 
      Console.WriteLine(AddWorkingDays(specificDate, 300)); // 100000 :) 
      globalTimer.Stop(); 
      Console.WriteLine(globalTimer.ElapsedMilliseconds); 

      globalTimer = Stopwatch.StartNew(); 
      Console.WriteLine(MyAddWorkingDays(specificDate, 300)); // 100000 :) 
      globalTimer.Stop(); 
      Console.WriteLine(globalTimer.ElapsedMilliseconds); 



      Console.ReadLine(); 
     } 
    } 
+0

¿Es más eficiente que mr. La sugerencia de Jon Skeet? – CSharpNoob

+0

@CSharpNoob, no. Esta es esencialmente la misma lógica sin manejar semanas enteras por adelantado. Entonces, en lugar de un bucle que podría ser de 1 a 4 (más hasta dos días de fin de semana), tiene un bucle que va de 1 a * n * (más * todos * días de fin de semana) –

+0

cuál es la diferencia entre MyAddWorkingDays y AddWorkingDays en tu código? – CSharpNoob

1

Una manera fresca (creo) es puesto que en una método de extensión, como:

public static class DateTimeExtensions 
{ 
    public static DateTime AddWorkingDays(this DateTime self, int days) 
    { 
     self = self.AddDays(days); 
     while (self.DayOfWeek == DayOfWeek.Saturday || self.DayOfWeek == DayOfWeek.Sunday) 
     { 
      self = self.AddDays(1); 
     } 

     return self; 
    } 
} 

lo que el código final se verá así:

specificDate.AddWorkingDays(3); 
+0

solo agrega un día, incluso si paso 2 o más días. – CSharpNoob

+0

Como señaló CSharpNoob, este código no funciona del todo correctamente, pero realmente me gusta el enfoque de usar un método de extensión para esto. – Patrick

+0

sí, está mal, no lo hice bien antes de publicarlo. perdón chicos, mi culpa. –

-1

es un antiguo puesto, pero alguien podría estar interesado en una extensión que se encarga también días negativos.(He vuelto a trabajar respuesta @ Jon)

public static DateTime AddWeekDays(this DateTime start, int days) 
    { 
     int direction = Math.Sign(days); 

     int completeWeeks = days/5; 
     int remaining = days % 5; 

     DateTime end = start.AddDays(completeWeeks * 7); 

     for (int i = 0; i < remaining * direction; i++) 
     { 
      end = end.AddDays(direction * 1); 
      while (!IsWeekDay(end)) 
      { 
       end = end.AddDays(direction * 1); 
      } 
     } 
     return end; 
    } 

    private static bool IsWeekDay(DateTime date) 
    { 
     DayOfWeek day = date.DayOfWeek; 
     return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday; 
    } 
0

Ésta me parece la manera más limpia:

public static DateTime AddWorkingDays(DateTime date, int daysToAdd) 
{ 
    while (daysToAdd > 0) 
    { 
     date = date.AddDays(1); 

     if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday) daysToAdd -= 1; 
    } 

    return date; 
} 
Cuestiones relacionadas