2011-01-05 28 views
37

Ho uno scenario in cui dato una data (DateTime), che data più/meno x giorni (ottenuto con DateTime.AddDays) devono aggiungere o sottrarre x giorni lavorativi, cioè, saltare fine settimana e festivi. Come posso farlo per farlo? Devo implementare la mia versione personale e allegarla a un calendario o qualcosa del genere?C# DateTime per aggiungere/Sottrarre giorni lavorativi

+3

Come fai a sapere in quali giorni sono le vacanze? –

+0

si assume che disponga di tali dati – Aks

+0

È possibile estendere il metodo indicato da @Taz per includere le festività. –

risposta

49

vorrei suggerire che si deve per la sua attuazione da soli, e lo farei all'interno di un metodo di estensione in questo modo:

 

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

Questo codice genera un'eccezione 'ArgumentOutOfRangeException'. Inoltre non gestisce i giorni negativi. – Kev

+4

Sì, lo so. Questo codice mostra solo il concetto maleducato e deve essere implementato in modo più sofisticato. Penso che ci siano libs pronte per l'uso su codeplex. – sprinter252

0

Si dovrebbe verificare se il giorno sta lavorando da soli, in quanto classe DateTime non può sapere in quali giorni sarà vacanze di quest'anno :)

0

Probabilmente si dovrebbe avere un database di vacanze per controllare contro, e se il valore di giorno più/meno x è uguale a un valore nel database aggiungi/sottrai un altro, poiché non tutti hanno le stesse festività.

40

Sulla base 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

ho fatto questo recentemente:

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; 
} 

Avrete bisogno di controllare il comportamento per tutti i giorni, li aggiungo sempre e solo!

2

Mi ci è voluto un po 'di tempo per elaborare ... Ho creato un tavolo DB che inserisco in un array con i miei giorni di vacanza. All Credit to Kev (on this post) .. Ho dovuto modificarlo per funzionare come lo è per me.

Nel mio caso, se il primo giorno era un sabato, e il mio workingDayCount = -1, voglio passare giovedì (dato che la mia data non può cadere in un fine settimana o in vacanza ... deve essere un giorno lavorativo .. in questo caso il Venerdì)

codice di Kev potrebbe passare di nuovo una Domenica ... il codice qui sotto lo porterà alla giornata lavorativa precedente (di solito un Venerdì -. a meno che Venerdì è un giorno festivo, quando sarebbe passare indietro Giovedi).

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; 
    } 

Qui è la mia semplice classe Vacanze:

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; } 

    } 
} 

Ecco come popolare la matrice:

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

Ho modificato le precedenti risposte ad approcci più funzionali. Ho fornito due soluzioni di seguito, uno utilizzando IEnumerable e uno che utilizza IObservable e le estensioni reattivi

Utilizzando 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; 
    } 
} 

Utilizzando 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

stavo cercando di aggiungere e sottrarre date saltare fine settimana e questa è la prima voce in Google. Non mi piaceva nessuna delle risposte qui quindi mi aggiungere quella che ho io stesso fatto nel caso in cui qualcuno finisce qui, come me:

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 
} 

Spero che questo aiuta qualcuno.

0

semplice soluzione è qui Provalo e godere di codifica

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); 
    } 
} 
Problemi correlati