2011-01-05 17 views
37

Mam scenariusz, gdzie daną datę (DateTime), data plus/minus x dni (uzyskiwana z DateTime.AddDays) należy dodać lub odjąć x dni robocze, tj pominąć weekendy i święta. Jak mogę to zrobić? Czy powinienem wdrożyć własną wersję i dołączyć ją do kalendarza czy coś takiego?C# DateTime do Dodaj/odejmij Dni Roboczych

+3

Skąd wiesz, które dni są dniami? –

+0

pozwala założyć, że mam te dane. – Aks

+0

Możesz rozszerzyć metodę wskazaną przez @Taz, aby uwzględnić święta. –

Odpowiedz

49

Sugerowałbym, że trzeba wprowadzić je w swój własny, i zrobi to wewnątrz metodę rozszerzenia jak ten:

 

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

Ten kod zgłasza wyjątek 'ArgumentOutOfRangeException'. Również nie obsługuje negatywnych dni. – Kev

+4

Tak, wiem o tym. Ten kod pokazuje jedynie niegrzeczną koncepcję i musi być implementowany bardziej wyrafinowany. Myślę, że są gotowe do użycia biblioteki na codepleksie. – sprinter252

0

Należy sprawdzić, czy dzień pracuje sam, ponieważ klasa DateTime nie może wiedzieć, które dni będą ferie w tym roku :)

0

powinny Prawdopodobnie masz baza wakacji do sprawdzenia przed, a jeżeli wartość dzień plus/minus x jest równy wartości w bazie danych dodaj/odejmij inny, ponieważ nie każdy ma takie same święta.

40

oparciu o 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

Zrobiłem to ostatnio:

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

Musisz sprawdzić zachowanie przez całe życie, tylko je dodam!

2

Zajęło mi trochę czasu, aby to rozwiązać ... Stworzyłem tabelę DB, którą wciągam do tablicy z dniami świątecznymi. All Credit to Kev (on this post) .. Musiałem zmodyfikować jego pracę tak, jak jest dla mnie.

W moim przypadku, jeśli pierwszy dzień był sobotą, a moja workingDayCount = -1, chcę odejść w czwartek (ponieważ moja randka nie może przypadać na weekend lub na wakacje ... musi to być dzień roboczy .. w tym przypadku piątek.)

Kod Kev może odejść w niedzielę ... poniższy kod przeniesie go do poprzedniego dnia roboczego (zazwyczaj w piątek - chyba że piątek jest świętem, kiedy minie czwartek).

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

Oto mój prosty klasa Urlop:

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

    } 
} 

Oto jak wypełnić tablicę:

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

Mam zmodyfikowano dotychczasowe odpowiedzi podejść bardziej funkcjonalne. I dostarczyły dwa rozwiązania poniżej, jeden przy użyciu IEnumerable i jeden przy użyciu IObservable i biernej Rozszerzenia

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

Korzystanie 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

Szukałem dodawać i odejmować daty pomijanie weekendy i to jest pierwszy wpis w Google. Nie podoba ci się żaden z odpowiedzi tutaj więc dodam ten, zrobiłem sobie w przypadku gdy ktoś kończy się tutaj, jak ja:

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 
} 

Mam nadzieję, że ktoś pomaga.

0

Prostym rozwiązaniem jest tutaj Wypróbuj go i cieszyć się kodowanie

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