2011-01-05 10 views
37

Tengo un escenario en el que da una fecha (DateTime), que datan de más/menos x días (que se logra con DateTime.AddDays) deben sumar o restar x días de trabajo, es decir, omitir fines de semana y días festivos. ¿Cómo puedo lograr que haga esto? ¿Debería implementar mi propia versión y adjuntarla a un calendario o algo así?C# DateTime para agregar/Jornadas Restar

+3

¿Cómo saber cuáles son los días festivos? –

+0

supongamos que tengo esos datos – Aks

+0

Puede extender el método señalado por @Taz para incluir días festivos. –

Respuesta

49

Yo sugeriría que usted tiene que ponerlo en práctica por su cuenta, y lo haría dentro de un método de extensión de esta manera:

 

public static class DateTimeExtensions 
{ 
    public static DateTime AddWorkdays(this DateTime originalDate, int workDays) 
    { 
     DateTime tmpDate = originalDate; 
     while (workDays > 0) 
     { 
      tmpDate = tmpDate.AddDays(1); 
      if (tmpDate.DayOfWeek < DayOfWeek.Saturday && 
       tmpDate.DayOfWeek > DayOfWeek.Sunday && 
       !tmpDate.IsHoliday()) 
       workDays--; 
     } 
     return tmpDate; 
    } 

    public static bool IsHoliday(this DateTime originalDate) 
    { 
     // INSERT YOUR HOlIDAY-CODE HERE! 
     return false; 
    } 
} 
 
+5

Este código arroja una excepción 'ArgumentOutOfRangeException'. Tampoco maneja días negativos. – Kev

+4

Sí, lo sé. Este código solo muestra el concepto grosero y tiene que implementarse de manera más sofisticada. Creo que hay librerías listas para usar en Codeplex. – sprinter252

0

Debe comprobar si el día está trabajando por su cuenta, ya que la clase DateTime no puede saber qué días serán días de fiesta este año :)

0

Usted probablemente debería tener una base de datos de las vacaciones para comprobar en contra, y si el valor de día más/menos x es igual a un valor en la base de datos agregar/restar otro, ya que no todos tienen las mismas vacaciones.

40

Basado en Taz'slink:

public static class DateTimeExtensions 
{ 
    public static DateTime AddWorkDays(this DateTime date, int workingDays) 
    { 
    int direction = workingDays < 0 ? -1 : 1; 
    DateTime newDate = date; 
    while (workingDays != 0) 
    { 
     newDate = newDate.AddDays(direction); 
     if (newDate.DayOfWeek != DayOfWeek.Saturday && 
      newDate.DayOfWeek != DayOfWeek.Sunday && 
      !newDate.IsHoliday()) 
     { 
     workingDays -= direction; 
     } 
    } 
    return newDate; 
    } 

    public static bool IsHoliday(this DateTime date) 
    { 
    // You'd load/cache from a DB or file somewhere rather than hardcode 
    DateTime[] holidays = 
    new DateTime[] { 
     new DateTime(2010,12,27), 
     new DateTime(2010,12,28), 
     new DateTime(2011,01,03), 
     new DateTime(2011,01,12), 
     new DateTime(2011,01,13) 
    }; 

    return holidays.Contains(date.Date); 
    } 
} 
7

lo hice recientemente:

private DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection<DateTime> holidays) 
{ 
    var futureDate = fromDate; 
    var daterange = Enumerable.Range(1, numberofWorkDays * 2); 
    var dateSet = daterange.Select (d => futureDate.AddDays(d)); 
    var dateSetElim = dateSet.Except(holidays).Except(dateSet.Where(s =>s.DayOfWeek == DayOfWeek.Sunday).Except(dateSet.Where (s=>s.DayOfWeek==DayOfWeek.Saturday))); 

    //zero-based array 
    futureDate = dateSetElim.ElementAt(numberofWorkDays-1); 
    return futureDate; 
} 

Tendrás que comprobar el comportamiento por -ve días, ¡solo los agrego!

2

Me tomó algo de tiempo para resolverlo ... He creado una tabla de BD que coloco en una matriz con mis días de vacaciones. All Credit to Kev (on this post) .. Tuve que modificar el suyo para que funcione como es para mí.

En mi caso, si el primer día fue un sábado y mi workingDayCount = -1, quiero pasar el jueves (ya que mi fecha no puede ser un fin de semana o unas vacaciones ... tiene que ser un día de trabajo) .. en este caso, viernes.)

El código de Kev podría pasar un domingo ... el siguiente código lo llevará al día laboral anterior (generalmente un viernes, a menos que el viernes sea día de fiesta, cuando vuelva el jueves)

public static DateTime AddWorkDays(this DateTime date, int workingDays, params Holidays[] bankHolidays) 
    { 
     int direction = workingDays < 0 ? -1 : 1; 
     DateTime newDate = date; 
     // If a working day count of Zero is passed, return the date passed 
     if (workingDays == 0) 
     { 

      newDate = date; 
     } 
     else 
     { 
      while (workingDays != -direction) 
      { 
       if (newDate.DayOfWeek != DayOfWeek.Saturday && 
        newDate.DayOfWeek != DayOfWeek.Sunday && 
        Array.IndexOf(bankHolidays, newDate) < 0) 
       { 
        workingDays -= direction; 
       } 
       // if the original return date falls on a weekend or holiday, this will take it to the previous/next workday, but the "if" statement keeps it from going a day too far. 

       if (workingDays != -direction) 
       { newDate = newDate.AddDays(direction); } 
      } 
     } 
     return newDate; 
    } 

Aquí es mi clase simple Vacaciones:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace Clarity.Utilities 
{ 
    public class Holidays 
    { 
     public int Id { get; set; } 
     public DateTime dtHoliday { get; set; } 
     public string Desc { get; set; } 
     public bool Active { get; set; } 

    } 
} 

Aquí es cómo rellenar la matriz:

private Holidays[] PopulateArrayWithDates() 
    { 
     SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DBConn"].ConnectionString); 
     DateTime[] dtHolidays = new DateTime[] { }; 
     string sql = @"SELECT HolDate, HolName FROM [Server].DBName.dbo.tblHolidays"; 
     SqlCommand ADDCmd = new SqlCommand(sql, con); 
     DataTable table = new DataTable(); 
     DataTable tbl = new DataTable(); 
     Utilities.Holidays[] allRecords = null; 

     using (var command = new SqlCommand(sql, con)) 
     { 
      con.Open(); 
      using (var reader = command.ExecuteReader()) 
      { 
       var list = new List<Holidays>(); 
       while (reader.Read()) 
        list.Add(new Holidays { dtHoliday = reader.GetDateTime(0), Desc = reader.GetString(1) }); 
       allRecords = list.ToArray(); 
      } 
     } 
     return allRecords; 
    } 
0

He modificado las respuestas anteriores a enfoques más funcional. He proporcionado dos soluciones de abajo, uno usando IEnumerable y el otro con IObservable y extensiones reactivas

Usando IObservable

public static class DateTimeExtensions 
{ 
    public static DateTime AddWorkDays(this DateTime date, int workingDays) 
    { 
     return Observable 
      .Generate 
       (date, arg => true, arg => arg.AddDays(workingDays < 0 ? -1 : 1), arg => arg) 
      .Where(newDate => 
       (newDate.DayOfWeek != DayOfWeek.Saturday && 
       newDate.DayOfWeek != DayOfWeek.Sunday && 
       !newDate.IsHoliday())) 
      .Take(Math.Abs(workingDays) + 1) 
      .LastAsync() 
      .Wait(); 
    } 

    public static bool IsHoliday(this DateTime date) 
    { 
     return false; 
    } 
} 

Usando IEnumerable

public static class DateTimeExtensions 
{ 
    public static DateTime AddWorkDays(this DateTime date, int workingDays) 
    { 
     return date.GetDates(workingDays < 0) 
      .Where(newDate => 
       (newDate.DayOfWeek != DayOfWeek.Saturday && 
       newDate.DayOfWeek != DayOfWeek.Sunday && 
       !newDate.IsHoliday())) 
      .Take(Math.Abs(workingDays)) 
      .Last(); 
    } 

    private static IEnumerable<DateTime> GetDates(this DateTime date, bool isForward) 
    { 
     while (true) 
     { 
      date = date.AddDays(isForward ? -1 : 1); 
      yield return date; 
     } 
    } 

    public static bool IsHoliday(this DateTime date) 
    { 
     return false; 
    } 
} 
1

que estaba buscando a sumar y restar fechas saltarse los fines de semana y esta es la primera entrada en Google. No me gusta ninguna de las respuestas aquí, así que voy a añadir el que hice a mí mismo en caso de que alguien termina aquí como yo:

public static DateTime AddExcludingWeekends(this DateTime dateTime, int nDays) 
{ 
    var wholeWeeks = nDays/5; //since nDays does not include weekdays every week is considered as 5 days 
    var absDays = Math.Abs(nDays); 
    var remaining = absDays % 5; //results in the number remaining days to add or substract excluding the whole weeks 
    var direction = nDays/absDays;//results in 1 if nDays is posisive or -1 if it's negative 
    while (dateTime.DayOfWeek == DayOfWeek.Saturday || dateTime.DayOfWeek == DayOfWeek.Sunday) 
    dateTime = dateTime.AddDays(direction); //If we are already in a weekend, get out of it 
    while (remaining-- > 0) 
    {//add remaining days... 
    dateTime = dateTime.AddDays(direction); 
    if (dateTime.DayOfWeek == DayOfWeek.Saturday) 
     dateTime = dateTime.AddDays(direction * 2);//...skipping weekends 
    } 
    return dateTime.AddDays(wholeWeeks * 7); //Finally add the whole weeks as 7 days, thus skipping the weekends without checking for DayOfWeek 
} 

espero que esto ayude a alguien.

0

solución simple es aquí Pruébalo y disfruta de codificación

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     Double days= 7; 
     string s=DateTime.Now.AddDays(7).ToString("dd/MM/yyyy"); 
     DateTime dt= OrderDeliveryDate(days); 
     Console.WriteLine("dt"+dt.ToString("dd/MM/yyyy")); 


    } 

    public static DateTime OrderDeliveryDate(Double days) 
    { 

     Double count=0; 
     for(int i=0;i<days;i++) 
     { 
      if(DateTime.Now.AddDays(i).DayOfWeek.ToString() == "Saturday") 
      { 
       count= count+1; 
      } 
      else if(DateTime.Now.AddDays(i).DayOfWeek.ToString() == "Sunday") 
      { 
       count=count+1; 
      } 

     } 
     days=days+count; 
     return DateTime.Now.AddDays(days); 
    } 
}