AddBusinessDays und GetBusinessDays

93

Ich muss 2 elegante vollständige Implementierungen von finden

public static DateTime AddBusinessDays(this DateTime date, int days)
{
 // code here
}

and 

public static int GetBusinessDays(this DateTime start, DateTime end)
{
 // code here
}

O (1) bevorzugt (keine Schleifen).

BEARBEITEN: Mit Werktagen meine ich Arbeitstage (Montag, Dienstag, Mittwoch, Donnerstag, Freitag). Keine Feiertage, nur Wochenenden ausgeschlossen.

Ich habe bereits einige hässliche Lösungen, die zu funktionieren scheinen, aber ich frage mich, ob es elegante Möglichkeiten gibt, dies zu tun. Vielen Dank


Das habe ich bisher geschrieben. Es funktioniert in allen Fällen und macht auch Negative. Benötigen Sie noch eine GetBusinessDays-Implementierung

public static DateTime AddBusinessDays(this DateTime startDate,
                                         int businessDays)
{
    int direction = Math.Sign(businessDays);
    if(direction == 1)
    {
        if(startDate.DayOfWeek == DayOfWeek.Saturday)
        {
            startDate = startDate.AddDays(2);
            businessDays = businessDays - 1;
        }
        else if(startDate.DayOfWeek == DayOfWeek.Sunday)
        {
            startDate = startDate.AddDays(1);
            businessDays = businessDays - 1;
        }
    }
    else
    {
        if(startDate.DayOfWeek == DayOfWeek.Saturday)
        {
            startDate = startDate.AddDays(-1);
            businessDays = businessDays + 1;
        }
        else if(startDate.DayOfWeek == DayOfWeek.Sunday)
        {
            startDate = startDate.AddDays(-2);
            businessDays = businessDays + 1;
        }
    }

    int initialDayOfWeek = (int)startDate.DayOfWeek;

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

    if((direction == 1 && addDays + initialDayOfWeek > 5) ||
         (direction == -1 && addDays >= initialDayOfWeek))
    {
        addDays += 2;
    }

    int totalDays = (weeksBase * 7) + addDays;
    return startDate.AddDays(totalDays * direction);
}
Adrian Zanescu
quelle
14
Gibt es elegante Lösungen, wenn es um etwas so Unlogisches wie Datteln geht?
Wyatt Barnett
Sind Sie mit Feiertagen beschäftigt? - James Conigliaro. Nein
Adrian Zanescu
9
Menschen abzustimmen, die versuchen zu helfen, ist keine erfolgreiche Strategie.
Jamie Ide
1
Kurzer Hinweis zur AddBusinessDaysImplementierung in der obigen Frage (die eigentlich eine gelöschte Antwort war, die ich zum Wiederherstellen vorgeschlagen habe; ein Mod hat diese Antwort stattdessen auf die Frage kopiert): Meiner Meinung nach ist diese Lösung besser als alle bisherigen Antworten, da sie die einzige ist eine, die mit negativen Werten korrekt umgeht, Samstag und Sonntag als Quelle und keine Drittanbieter-Bibliothek benötigt. (Ich habe ein kleines Programm erstellt, um die verschiedenen Lösungen hier zu testen.) Ich würde nur if (businessDays == 0) return startDate;am Anfang der Methode hinzufügen , um auch für diesen Randfall das richtige Ergebnis zu erhalten.
Slauma
1
@AZ.: Die erste Löschung war ziemlich alt. Nach meiner Aufforderung, deine Antwort wiederherzustellen, hatte ein Mod die Antwort (für 30 Sekunden) gelöscht, um den Inhalt unter deiner Frage zu kopieren, und er löschte sie dann erneut. Aus diesem Grund hat Ihre Antwort diesen aktuellen Zeitstempel zum Löschen. Ich habe den obigen Kommentar geschrieben, weil Sie für meinen Zweck AddBusinessDaysdie allgemeinste Lösung waren, die in allen von mir benötigten Fällen funktioniert hat. Ich habe es in eines meiner aktuellen Projekte kopiert (nach geringfügiger Änderung und Übersetzung in C ++), danke für den Code :) Es hat sehr geholfen, da es überraschend schwierig ist, alle Randfälle richtig zu machen.
Slauma

Antworten:

134

Letzter Versuch für Ihre erste Funktion:

public static DateTime AddBusinessDays(DateTime date, int days)
{
    if (days < 0)
    {
        throw new ArgumentException("days cannot be negative", "days");
    }

    if (days == 0) return date;

    if (date.DayOfWeek == DayOfWeek.Saturday)
    {
        date = date.AddDays(2);
        days -= 1;
    }
    else if (date.DayOfWeek == DayOfWeek.Sunday)
    {
        date = date.AddDays(1);
        days -= 1;
    }

    date = date.AddDays(days / 5 * 7);
    int extraDays = days % 5;

    if ((int)date.DayOfWeek + extraDays > 5)
    {
        extraDays += 2;
    }

    return date.AddDays(extraDays);

}

Die zweite Funktion, GetBusinessDays, kann wie folgt implementiert werden:

public static int GetBusinessDays(DateTime start, DateTime end)
{
    if (start.DayOfWeek == DayOfWeek.Saturday)
    {
        start = start.AddDays(2);
    }
    else if (start.DayOfWeek == DayOfWeek.Sunday)
    {
        start = start.AddDays(1);
    }

    if (end.DayOfWeek == DayOfWeek.Saturday)
    {
        end = end.AddDays(-1);
    }
    else if (end.DayOfWeek == DayOfWeek.Sunday)
    {
        end = end.AddDays(-2);
    }

    int diff = (int)end.Subtract(start).TotalDays;

    int result = diff / 7 * 5 + diff % 7;

    if (end.DayOfWeek < start.DayOfWeek)
    {
        return result - 2;
    }
    else{
        return result;
    }
}
Patrick McDonald
quelle
Für die zweite besteht eine Lösung darin, die Differenz zwischen Datum und Datum + Tagen zu ermitteln. Dies ist insofern schön, als es garantiert, dass die beiden Funktionen ordnungsgemäß synchronisiert werden, und Redundanz beseitigt.
Brian
Feed aktuelles Datum, läuft für 0 bis 10 Werktage, es schlägt immer am Mittwoch fehl.
Adrian Godong
1
Ja, wir sind am Ende dort angekommen. (Ich sage 'wir' für meinen winzigen Beitrag!) Für die Mühe gestimmt.
Noldorin
Vielen Dank für Ihre Eingabe Noldorin, ich kann Ihre Kommentare leider nur positiv bewerten!
Patrick McDonald
3
DateTime.AddDays arbeitet mit negativen Zahlen. Dies folgt nicht dem gleichen Muster wie die Verwendung negativer Zahlen mit AddBusinessDays, mit denen nicht geschäftliche Tage ausgewählt werden können.
Ristogod
63

mit Fluent DateTime :

var now = DateTime.Now;
var dateTime1 = now.AddBusinessDays(3);
var dateTime2 = now.SubtractBusinessDays(5);

Der interne Code lautet wie folgt

    /// <summary>
    /// Adds the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be added.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime AddBusinessDays(this DateTime current, int days)
    {
        var sign = Math.Sign(days);
        var unsignedDays = Math.Abs(days);
        for (var i = 0; i < unsignedDays; i++)
        {
            do
            {
                current = current.AddDays(sign);
            }
            while (current.DayOfWeek == DayOfWeek.Saturday ||
                current.DayOfWeek == DayOfWeek.Sunday);
        }
        return current;
    }

    /// <summary>
    /// Subtracts the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be subtracted.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime SubtractBusinessDays(this DateTime current, int days)
    {
        return AddBusinessDays(current, -days);
    }
Simon
quelle
Dies ist die einzige Lösung, die bei der Umstellung auf VB.Net
Nicholas
1
OP hat keine Schleifen angefordert, während diese eindeutig Schleifen hat. Es ist nichts Elegantes daran, etwas auf die am wenigsten effiziente Weise zu tun.
Neolisk
13

Ich habe eine Erweiterung erstellt, mit der Sie Werktage hinzufügen oder entfernen können. Verwenden Sie zum Subtrahieren eine negative Anzahl von businessDays. Ich denke, es ist eine ziemlich elegante Lösung. Es scheint in allen Fällen zu funktionieren.

namespace Extensions.DateTime
{
    public static class BusinessDays
    {
        public static System.DateTime AddBusinessDays(this System.DateTime source, int businessDays)
        {
            var dayOfWeek = businessDays < 0
                                ? ((int)source.DayOfWeek - 12) % 7
                                : ((int)source.DayOfWeek + 6) % 7;

            switch (dayOfWeek)
            {
                case 6:
                    businessDays--;
                    break;
                case -6:
                    businessDays++;
                    break;
            }

            return source.AddDays(businessDays + ((businessDays + dayOfWeek) / 5) * 2);
        }
    }
}

Beispiel:

using System;
using System.Windows.Forms;
using Extensions.DateTime;

namespace AddBusinessDaysTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            label1.Text = DateTime.Now.AddBusinessDays(5).ToString();
            label2.Text = DateTime.Now.AddBusinessDays(-36).ToString();
        }
    }
}
Arjen
quelle
Das Ergebnis ist fraglich, ob das Quelldatum ein Samstag oder Sonntag ist. Zum Beispiel: Samstag + 1 Werktag ergibt Dienstag, wo ich lieber Montag erwarten würde.
Slauma
3
@Slauma: So arbeiten die meisten Unternehmen in Kanada. +1 Werktag = "nächster Werktag", im Falle von Samstag ist Dienstag. Montag wäre "gleicher Werktag".
Neolisk
3
@ Slauma-Programm funktioniert wie vorgesehen. Denken Sie logisch darüber nach. Wenn etwas Geschäftliches am Samstag beginnt und Sie einen Werktag einplanen müssen, damit die Leute während des genannten Geschäftstages reagieren können, ist es sinnvoll, ihnen mitzuteilen, dass dies bis Montag erledigt sein muss?!
Riegardt Steyn
8

Für mich musste ich eine Lösung haben, die Wochenenden überspringt und entweder negativ oder positiv ist. Meine Kriterien waren, wenn es vorwärts ging und an einem Wochenende landete, würde es auf Montag vorrücken müssen. Wenn es zurückgehen und an einem Wochenende landen würde, müsste es auf Freitag springen.

Beispielsweise:

  • Mittwoch - 3 Werktage = Letzter Freitag
  • Mittwoch + 3 Werktage = Montag
  • Freitag - 7 Werktage = Letzter Mittwoch
  • Dienstag - 5 Werktage = Letzter Dienstag

Na du kommst auf die Idee;)

Am Ende habe ich diese Erweiterungsklasse geschrieben

public static partial class MyExtensions
{
    public static DateTime AddBusinessDays(this DateTime date, int addDays)
    {
        while (addDays != 0)
        {
            date = date.AddDays(Math.Sign(addDays));
            if (MyClass.IsBusinessDay(date))
            {
                addDays = addDays - Math.Sign(addDays);
            }
        }
        return date;
    }
}

Es verwendet diese Methode, von der ich dachte, dass sie nützlich wäre, um sie an anderer Stelle zu verwenden ...

public class MyClass
{
    public static bool IsBusinessDay(DateTime date)
    {
        switch (date.DayOfWeek)
        {
            case DayOfWeek.Monday:
            case DayOfWeek.Tuesday:
            case DayOfWeek.Wednesday:
            case DayOfWeek.Thursday:
            case DayOfWeek.Friday:
                return true;
            default:
                return false;
        }
    }
}

Wenn Sie sich nicht darum kümmern möchten, können Sie es einfach durch if (MyClass.IsBusinessDay(date))if ersetzenif ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

Jetzt können Sie es also tun

var myDate = DateTime.Now.AddBusinessDays(-3);

oder

var myDate = DateTime.Now.AddBusinessDays(5);

Hier sind die Ergebnisse einiger Tests:

Erwarten Sie das erwartete Ergebnis
Mittwoch -4 Werktage Donnerstag Donnerstag
Mittwoch -3 Werktage Freitag Freitag
Mittwoch +3 Werktage Montag Montag
Freitag -7 Werktage Mittwoch Mittwoch
Dienstag -5 Werktage Dienstag Dienstag
Freitag +1 Werktage Montag Montag
Samstag +1 Werktage Montag Montag
Sonntag -1 Werktage Freitag Freitag
Montag -1 Werktage Freitag Freitag
Montag +1 Werktage Dienstag Dienstag
Montag +0 Werktage Montag Montag
Hugo Yates
quelle
Ich habe die 2. Methode auch zu einer Erweiterungsmethode gemacht: public static bool IsBusinessDay (dieses DateTime-Datum)
Andy B
2
public static DateTime AddBusinessDays(this DateTime date, int days)
{
    date = date.AddDays((days / 5) * 7);

    int remainder = days % 5;

    switch (date.DayOfWeek)
    {
        case DayOfWeek.Tuesday:
            if (remainder > 3) date = date.AddDays(2);
            break;
        case DayOfWeek.Wednesday:
            if (remainder > 2) date = date.AddDays(2);
            break;
        case DayOfWeek.Thursday:
            if (remainder > 1) date = date.AddDays(2);
            break;
        case DayOfWeek.Friday:
            if (remainder > 0) date = date.AddDays(2);
            break;
        case DayOfWeek.Saturday:
            if (days > 0) date = date.AddDays((remainder == 0) ? 2 : 1);
            break;
        case DayOfWeek.Sunday:
            if (days > 0) date = date.AddDays((remainder == 0) ? 1 : 0);
            break;
        default:  // monday
            break;
    }

    return date.AddDays(remainder);
}
LukeH
quelle
1

Ich komme zu spät, um die Antwort zu erhalten, aber ich habe eine kleine Bibliothek mit allen Anpassungen erstellt, die für einfache Vorgänge an Arbeitstagen erforderlich sind ... Ich lasse es hier: Working Days Management

Ohne Knochen
quelle
2
Leider ist dies GNU-lizenziert, so dass "legales Gift" für jede kommerzielle App gilt. Gibt es eine Chance, dies auf "MIT" oder "Apache" zu lockern?
Tony O'Hagan
Einige statische Listen sollten wahrscheinlich Arrays sein (und keine verknüpften Listen).
Tony O'Hagan
1
Ich habe gerade die Lizenz in MIT geändert (ich möchte nichts auf etwas so Einfachem blockieren). Ich werde Ihren anderen Vorschlag untersuchen.
Ohne Knochen
Schön, es wäre interessant, die Verwaltung der Arbeitstage nach Ländern zu sehen, da einige Länder möglicherweise andere Arbeitstage als Montag bis Freitag haben.
Serializer
1

Die einzige echte Lösung besteht darin, dass diese Anrufe auf eine Datenbanktabelle zugreifen, die den Kalender für Ihr Unternehmen definiert. Sie könnten es für eine Arbeitswoche von Montag bis Freitag ohne allzu große Schwierigkeiten codieren, aber der Umgang mit Feiertagen wäre eine Herausforderung.

Bearbeitet, um nicht elegante und nicht getestete Teillösung hinzuzufügen:

public static DateTime AddBusinessDays(this DateTime date, int days)
{
    for (int index = 0; index < days; index++)
    {
        switch (date.DayOfWeek)
        {
            case DayOfWeek.Friday:
                date = date.AddDays(3);
                break;
            case DayOfWeek.Saturday:
                date = date.AddDays(2);
                break;
            default:
                date = date.AddDays(1);
                break;
         }
    }
    return date;
}

Außerdem habe ich die No-Loops-Anforderung verletzt.

Jamie Ide
quelle
Ich glaube nicht, dass der Fall am Samstag jemals getroffen werden würde.
CoderDennis
@ Tennis - es wäre, wenn das Datum ein Samstag ist.
Jamie Ide
Ich habe mir erlaubt, Ihren Code zu bearbeiten, damit er funktioniert. Bitte testen Sie den Code, bevor Sie ihn das nächste Mal veröffentlichen. Vielen Dank.
Bytecode77
Und ich dachte, die Null-Upvotes sprachen für sich. Vielen Dank!
Jamie Ide
1

Ich belebe diesen Beitrag wieder, weil ich heute einen Weg finden musste, nicht nur Samstag- und Sonntag- Wochentage, sondern auch Feiertage auszuschließen . Insbesondere musste ich verschiedene Arten von möglichen Feiertagen behandeln, einschließlich:

  • Länderinvariante Feiertage (zumindest für die westlichen Länder - wie der 1. Januar).
  • berechnete Feiertage (wie Ostern und Ostermontag).
  • länderspezifische Feiertage (wie der italienische Befreiungstag oder der US-amerikanische ID4).
  • stadtspezifische Feiertage (wie der St. St. Patron Day in Rom).
  • Jeder andere maßgeschneiderte Urlaub (z. B. "Morgen wird unser Büro geschlossen").

Schließlich kam ich mit den folgenden Hilfs- / Erweiterungsklassen heraus: Obwohl sie nicht besonders elegant sind, da sie ineffiziente Schleifen massiv nutzen, sind sie anständig genug, um meine Probleme endgültig zu lösen. Ich lasse den gesamten Quellcode hier in diesem Beitrag fallen und hoffe, dass er auch für andere nützlich ist.

Quellcode

/// <summary>
/// Helper/extension class for manipulating date and time values.
/// </summary>
public static class DateTimeExtensions
{
    /// <summary>
    /// Calculates the absolute year difference between two dates.
    /// </summary>
    /// <param name="dt1"></param>
    /// <param name="dt2"></param>
    /// <returns>A whole number representing the number of full years between the specified dates.</returns>
    public static int Years(DateTime dt1,DateTime dt2)
    {
        return Months(dt1,dt2)/12;
        //if (dt2<dt1)
        //{
        //    DateTime dt0=dt1;
        //    dt1=dt2;
        //    dt2=dt0;
        //}

        //int diff=dt2.Year-dt1.Year;
        //int m1=dt1.Month;
        //int m2=dt2.Month;
        //if (m2>m1) return diff;
        //if (m2==m1 && dt2.Day>=dt1.Day) return diff;
        //return (diff-1);
    }

    /// <summary>
    /// Calculates the absolute year difference between two dates.
    /// Alternative, stand-alone version (without other DateTimeUtil dependency nesting required)
    /// </summary>
    /// <param name="start"></param>
    /// <param name="end"></param>
    /// <returns></returns>
    public static int Years2(DateTime start, DateTime end)
    {
        return (end.Year - start.Year - 1) +
            (((end.Month > start.Month) ||
            ((end.Month == start.Month) && (end.Day >= start.Day))) ? 1 : 0);
    }

    /// <summary>
    /// Calculates the absolute month difference between two dates.
    /// </summary>
    /// <param name="dt1"></param>
    /// <param name="dt2"></param>
    /// <returns>A whole number representing the number of full months between the specified dates.</returns>
    public static int Months(DateTime dt1,DateTime dt2)
    {
        if (dt2<dt1)
        {
            DateTime dt0=dt1;
            dt1=dt2;
            dt2=dt0;
        }

        dt2=dt2.AddDays(-(dt1.Day-1));
        return (dt2.Year-dt1.Year)*12+(dt2.Month-dt1.Month);
    }

    /// <summary>
    /// Returns the higher of the two date time values.
    /// </summary>
    /// <param name="dt1">The first of the two <c>DateTime</c> values to compare.</param>
    /// <param name="dt2">The second of the two <c>DateTime</c> values to compare.</param>
    /// <returns><c>dt1</c> or <c>dt2</c>, whichever is higher.</returns>
    public static DateTime Max(DateTime dt1,DateTime dt2)
    {
        return (dt2>dt1?dt2:dt1);
    }

    /// <summary>
    /// Returns the lower of the two date time values.
    /// </summary>
    /// <param name="dt1">The first of the two <c>DateTime</c> values to compare.</param>
    /// <param name="dt2">The second of the two <c>DateTime</c> values to compare.</param>
    /// <returns><c>dt1</c> or <c>dt2</c>, whichever is lower.</returns>
    public static DateTime Min(DateTime dt1,DateTime dt2)
    {
        return (dt2<dt1?dt2:dt1);
    }

    /// <summary>
    /// Adds the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be added.</param>
    /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime AddBusinessDays(
        this DateTime current, 
        int days, 
        IEnumerable<DateTime> holidays = null)
    {
        var sign = Math.Sign(days);
        var unsignedDays = Math.Abs(days);
        for (var i = 0; i < unsignedDays; i++)
        {
            do
            {
                current = current.AddDays(sign);
            }
            while (current.DayOfWeek == DayOfWeek.Saturday
                || current.DayOfWeek == DayOfWeek.Sunday
                || (holidays != null && holidays.Contains(current.Date))
                );
        }
        return current;
    }

    /// <summary>
    /// Subtracts the given number of business days to the <see cref="DateTime"/>.
    /// </summary>
    /// <param name="current">The date to be changed.</param>
    /// <param name="days">Number of business days to be subtracted.</param>
    /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param>
    /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns>
    public static DateTime SubtractBusinessDays(
        this DateTime current, 
        int days,
        IEnumerable<DateTime> holidays)
    {
        return AddBusinessDays(current, -days, holidays);
    }

    /// <summary>
    /// Retrieves the number of business days from two dates
    /// </summary>
    /// <param name="startDate">The inclusive start date</param>
    /// <param name="endDate">The inclusive end date</param>
    /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param>
    /// <returns></returns>
    public static int GetBusinessDays(
        this DateTime startDate, 
        DateTime endDate,
        IEnumerable<DateTime> holidays)
    {
        if (startDate > endDate)
            throw new NotSupportedException("ERROR: [startDate] cannot be greater than [endDate].");

        int cnt = 0;
        for (var current = startDate; current < endDate; current = current.AddDays(1))
        {
            if (current.DayOfWeek == DayOfWeek.Saturday
                || current.DayOfWeek == DayOfWeek.Sunday
                || (holidays != null && holidays.Contains(current.Date))
                )
            {
                // skip holiday
            }
            else cnt++;
        }
        return cnt;
    }

    /// <summary>
    /// Calculate Easter Sunday for any given year.
    /// src.: https://stackoverflow.com/a/2510411/1233379
    /// </summary>
    /// <param name="year">The year to calcolate Easter against.</param>
    /// <returns>a DateTime object containing the Easter month and day for the given year</returns>
    public static DateTime GetEasterSunday(int year)
    {
        int day = 0;
        int month = 0;

        int g = year % 19;
        int c = year / 100;
        int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30;
        int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11));

        day = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28;
        month = 3;

        if (day > 31)
        {
            month++;
            day -= 31;
        }

        return new DateTime(year, month, day);
    }

    /// <summary>
    /// Retrieve holidays for given years
    /// </summary>
    /// <param name="years">an array of years to retrieve the holidays</param>
    /// <param name="countryCode">a country two letter ISO (ex.: "IT") to add the holidays specific for that country</param>
    /// <param name="cityName">a city name to add the holidays specific for that city</param>
    /// <returns></returns>
    public static IEnumerable<DateTime> GetHolidays(IEnumerable<int> years, string countryCode = null, string cityName = null)
    {
        var lst = new List<DateTime>();

        foreach (var year in years.Distinct())
        {
            lst.AddRange(new[] {
                new DateTime(year, 1, 1),       // 1 gennaio (capodanno)
                new DateTime(year, 1, 6),       // 6 gennaio (epifania)
                new DateTime(year, 5, 1),       // 1 maggio (lavoro)
                new DateTime(year, 8, 15),      // 15 agosto (ferragosto)
                new DateTime(year, 11, 1),      // 1 novembre (ognissanti)
                new DateTime(year, 12, 8),      // 8 dicembre (immacolata concezione)
                new DateTime(year, 12, 25),     // 25 dicembre (natale)
                new DateTime(year, 12, 26)      // 26 dicembre (s. stefano)
            });

            // add easter sunday (pasqua) and monday (pasquetta)
            var easterDate = GetEasterSunday(year);
            lst.Add(easterDate);
            lst.Add(easterDate.AddDays(1));

            // country-specific holidays
            if (!String.IsNullOrEmpty(countryCode))
            {
                switch (countryCode.ToUpper())
                {
                    case "IT":
                        lst.Add(new DateTime(year, 4, 25));     // 25 aprile (liberazione)
                        break;
                    case "US":
                        lst.Add(new DateTime(year, 7, 4));     // 4 luglio (Independence Day)
                        break;

                    // todo: add other countries

                    case default:
                        // unsupported country: do nothing
                        break;
                }
            }

            // city-specific holidays
            if (!String.IsNullOrEmpty(cityName))
            {
                switch (cityName)
                {
                    case "Rome":
                    case "Roma":
                        lst.Add(new DateTime(year, 6, 29));  // 29 giugno (s. pietro e paolo)
                        break;
                    case "Milano":
                    case "Milan":
                        lst.Add(new DateTime(year, 12, 7));  // 7 dicembre (s. ambrogio)
                        break;

                    // todo: add other cities

                    default:
                        // unsupported city: do nothing
                        break;

                }
            }
        }
        return lst;
    }
}

Nutzungsinformationen

Der Code ist ziemlich selbsterklärend. Hier sind jedoch einige Beispiele, um zu erklären, wie Sie ihn verwenden können.

Fügen Sie 10 Werktage hinzu (überspringen Sie nur die Wochentage Samstag und Sonntag).

var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10);

Fügen Sie 10 Werktage hinzu (Überspringen von Samstag, Sonntag und allen länderinvarianten Feiertagen für 2019)

var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019));

Fügen Sie 10 Werktage hinzu (Überspringen von Samstag, Sonntag und allen italienischen Feiertagen für 2019)

var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019, "IT"));

Fügen Sie 10 Werktage hinzu (Überspringen von Samstag, Sonntag, allen italienischen Feiertagen und den Rom-spezifischen Feiertagen für 2019)

var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019, "IT", "Rome"));

Die obigen Funktionen und Codebeispiele werden in diesem Beitrag meines Blogs näher erläutert .

Darkseal
quelle
0
    public static DateTime AddBusinessDays(DateTime date, int days)
    {
        if (days == 0) return date;
        int i = 0;
        while (i < days)
        {
            if (!(date.DayOfWeek == DayOfWeek.Saturday ||  date.DayOfWeek == DayOfWeek.Sunday)) i++;  
            date = date.AddDays(1);
        }
        return date;
    }
Alex
quelle
in der Zukunft fügen Sie ein bisschen mehr Kontext für die Antwort und vielleicht, warum Sie setzen, was Sie haben :)
dax
0

Ich wollte einen "AddBusinessDays", der eine negative Anzahl von Tagen unterstützt, und am Ende kam ich zu folgendem Ergebnis:

// 0 == Monday, 6 == Sunday
private static int epochDayToDayOfWeek0Based(long epochDay) {
    return (int)Math.floorMod(epochDay + 3, 7);
}

public static int daysBetween(long fromEpochDay, long toEpochDay) {
    // http://stackoverflow.com/questions/1617049/calculate-the-number-of-business-days-between-two-dates
    final int fromDOW = epochDayToDayOfWeek0Based(fromEpochDay);
    final int toDOW = epochDayToDayOfWeek0Based(toEpochDay);
    long calcBusinessDays = ((toEpochDay - fromEpochDay) * 5 + (toDOW - fromDOW) * 2) / 7;

    if (toDOW   == 6) calcBusinessDays -= 1;
    if (fromDOW == 6) calcBusinessDays += 1;
    return (int)calcBusinessDays;
}

public static long addDays(long epochDay, int n) {
    // https://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/
    // NB: in .NET, Sunday == 0, but in our code Monday == 0
    final int dow = (epochDayToDayOfWeek0Based(epochDay) + 1) % 7;
    final int wds = n + (dow == 0 ? 1 : dow); // Adjusted number of working days to add, given that we now start from the immediately preceding Sunday
    final int wends = n < 0 ? ((wds - 5) / 5) * 2
                            : (wds / 5) * 2 - (wds % 5 == 0 ? 2 : 0);
    return epochDay - dow + // Find the immediately preceding Sunday
           wds +            // Add computed working days
           wends;           // Add weekends that occur within each complete working week
}

Keine Schleife erforderlich, daher sollte sie auch für "große" Ergänzungen relativ schnell sein.

Es funktioniert mit Tagen, die als Anzahl von Kalendertagen seit der Epoche ausgedrückt werden, da dies von der neuen JDK8 LocalDate-Klasse verfügbar gemacht wird und ich in Java gearbeitet habe. Sollte jedoch einfach an andere Einstellungen anzupassen sein.

Die grundlegenden Eigenschaften sind, dass addDaysimmer ein Wochentag zurückgegeben wird, und das für alle dund n,daysBetween(d, addDays(d, n)) == n

Beachten Sie, dass das Hinzufügen von 0 Tagen und das Subtrahieren von 0 Tagen theoretisch unterschiedliche Vorgänge sein sollten (wenn Ihr Datum ein Sonntag ist, sollten Sie durch Hinzufügen von 0 Tagen bis Montag und durch Subtrahieren von 0 Tagen bis Freitag geführt werden). Da es keine negative 0 gibt (außerhalb des Gleitkommas!), Habe ich beschlossen, ein Argument n = 0 so zu interpretieren , dass es null Tage addiert .

Max Bolingbroke
quelle
0

Ich glaube, dies könnte ein einfacherer Weg zu GetBusinessDays sein:

    public int GetBusinessDays(DateTime start, DateTime end, params DateTime[] bankHolidays)
    {
        int tld = (int)((end - start).TotalDays) + 1; //including end day
        int not_buss_day = 2 * (tld / 7); //Saturday and Sunday
        int rest = tld % 7; //rest.

        if (rest > 0)
        {
            int tmp = (int)start.DayOfWeek - 1 + rest;
            if (tmp == 6 || start.DayOfWeek == DayOfWeek.Sunday) not_buss_day++; else if (tmp > 6) not_buss_day += 2;
        }

        foreach (DateTime bankHoliday in bankHolidays)
        {
            DateTime bh = bankHoliday.Date;
            if (!(bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday) && (start <= bh && bh <= end))
            {
                not_buss_day++;
            }
        }
        return tld - not_buss_day;
    }
Carlos.Cândido
quelle
0

Hier ist mein Code mit dem Abreisedatum und dem Lieferdatum beim Kunden.

            // Calculate departure date
            TimeSpan DeliveryTime = new TimeSpan(14, 30, 0); 
            TimeSpan now = DateTime.Now.TimeOfDay;
            DateTime dt = DateTime.Now;
            if (dt.TimeOfDay > DeliveryTime) dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Saturday) dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Sunday) dt = dt.AddDays(1);
            dt = dt.Date + DeliveryTime;
            string DepartureDay = "today at "+dt.ToString("HH:mm");
            if (dt.Day!=DateTime.Now.Day)
            {
                DepartureDay = dt.ToString("dddd at HH:mm", new CultureInfo(WebContextState.CurrentUICulture));
            }
            Return DepartureDay;

            // Caclulate delivery date
            dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Saturday) dt = dt.AddDays(1);
            if (dt.DayOfWeek == DayOfWeek.Sunday) dt = dt.AddDays(1);
            string DeliveryDay = dt.ToString("dddd", new CultureInfo(WebContextState.CurrentUICulture));
            return DeliveryDay;

Viel Spaß beim Codieren.

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

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

    return date;
}
tocqueville
quelle
0
public static int GetBusinessDays(this DateTime start, DateTime end)
            {
                return Enumerable.Range(0, (end- start).Days)
                                .Select(a => start.AddDays(a))
                                .Where(a => a.DayOfWeek != DayOfWeek.Sunday)
                                .Where(a => a.DayOfWeek != DayOfWeek.Saturday)
                                .Count();
    
            }
Kokul Jose
quelle
-1

Hoffe das hilft jemandem.

private DateTime AddWorkingDays(DateTime addToDate, int numberofDays)
    {
        addToDate= addToDate.AddDays(numberofDays);
        while (addToDate.DayOfWeek == DayOfWeek.Saturday || addToDate.DayOfWeek == DayOfWeek.Sunday)
        {
            addToDate= addToDate.AddDays(1);
        }
        return addToDate;
    }
user2686690
quelle
2
Das ist falsch. In den meisten Fällen wird es nicht funktionieren. Es ist unwahrscheinlich, dass jemand hilft.
Neolisk