AddBusinessDays et GetBusinessDays

93

J'ai besoin de trouver 2 implémentations complètes élégantes de

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) préférable (pas de boucles).

EDIT: Par jours ouvrables, j'entends les jours ouvrables (lundi, mardi, mercredi, jeudi, vendredi). Pas de vacances, juste les week-ends exclus.

J'ai déjà des solutions laides qui semblent fonctionner mais je me demande s'il existe des moyens élégants de le faire. Merci


C'est ce que j'ai écrit jusqu'à présent. Cela fonctionne dans tous les cas et fait aussi des négatifs. Encore besoin d'une implémentation GetBusinessDays

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
la source
14
Existe-t-il des solutions élégantes quand il s'agit de quelque chose d'aussi illogique que les dates?
Wyatt Barnett
Êtes-vous préoccupé par les vacances? - James Conigliaro. Non
Adrian Zanescu
9
Voter contre les personnes qui essaient d'aider n'est pas une stratégie gagnante.
Jamie Ide
1
Brève note sur la AddBusinessDaysmise en œuvre dans la question ci-dessus (qui était en fait une réponse supprimée que j'ai proposé d'annuler; un mod a copié cette réponse à la question à la place): À mon avis, cette solution est meilleure que toutes les réponses jusqu'à présent car c'est la seule celui qui traite correctement les valeurs négatives, samedi et dimanche comme source et n'a pas besoin d'une bibliothèque tierce. (J'ai fait un petit programme pour tester les différentes solutions ici.) Je voudrais seulement ajouter if (businessDays == 0) return startDate;au début de la méthode pour obtenir le résultat correct pour ce cas de bord également.
Slauma
1
@AZ .: La première suppression était assez ancienne. Après ma demande d'annuler la suppression de votre réponse, un mod avait annulé la réponse (pendant 30 secondes) pour copier le contenu sous votre question, puis il l'a à nouveau supprimée. C'est pourquoi votre réponse a cet horodatage de suppression récent. J'ai écrit le commentaire ci-dessus parce que pour mon propos, votre AddBusinessDayssolution était la plus générale qui fonctionnait dans tous les cas dont j'ai besoin. Je l'ai copié dans l'un de mes projets actuels (après une légère modification et une traduction en C ++), merci pour le code :) Cela a beaucoup aidé car il est étonnamment difficile d'obtenir tous les cas limites.
Slauma

Réponses:

134

Dernière tentative pour votre première fonction:

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

}

La deuxième fonction, GetBusinessDays, peut être implémentée comme suit:

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
la source
Pour le second, une solution est de prendre la différence entre date et date + jours. C'est bien en ce sens que cela garantit que les deux fonctions se synchroniseront correctement, et cela supprime la redondance.
Brian
Date actuelle du flux, exécutée pendant 0 à 10 jours ouvrables, elle échoue toujours le mercredi.
Adrian Godong
1
Ouais, nous y sommes arrivés à la fin. (Je dis «nous» pour ma petite contribution!) J'ai voté pour l'effort.
Noldorin
Merci pour votre contribution Noldorin, je ne peux que voter pour vos commentaires malheureusement!
Patrick McDonald
3
DateTime.AddDays fonctionne avec des nombres négatifs. Cela ne suit pas correctement le même modèle que l'utilisation de nombres négatifs avec AddBusinessDays permet de sélectionner des jours non ouvrables.
Ristogod
63

en utilisant Fluent DateTime :

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

le code interne est le suivant

    /// <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
la source
C'est la seule solution qui a réellement fonctionné pour moi une fois convertie en VB.Net
Nicholas
1
OP n'a demandé aucune boucle, alors que celle-ci a clairement des boucles. Il n'y a rien d'élégant à faire quelque chose de la manière la moins efficace.
Neolisk
13

J'ai créé une extension qui vous permet d'ajouter ou de soustraire des jours ouvrables. Utilisez un nombre négatif de BusinessDays pour soustraire. Je pense que c'est une solution assez élégante. Cela semble fonctionner dans tous les cas.

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

Exemple:

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
la source
Le résultat est discutable si la date source est un samedi ou un dimanche. Par exemple: samedi + 1 jour ouvrable donne le mardi, où je préfère m'attendre à lundi.
Slauma
3
@Slauma: C'est ainsi que fonctionnent la plupart des entreprises au Canada. +1 jour ouvrable = "jour ouvrable suivant", qui en cas de samedi est mardi. Le lundi serait le «même jour ouvrable».
Neolisk
3
Le programme @Slauma fonctionne comme prévu. Pensez-y logiquement. Si quelque chose lié aux affaires démarre samedi et que vous devez prévoir 1 jour ouvrable pour que les gens réagissent pendant la durée dudit jour ouvrable, serait-il logique de leur dire que cela doit être fait d'ici lundi?!
Riegardt Steyn le
8

Pour moi, je devais avoir une solution qui passerait les week-ends et serait négative ou positive. Mon critère était que s'il allait de l'avant et atterrissait un week-end, il devrait avancer jusqu'à lundi. S'il devait rentrer et atterrir un week-end, il devrait passer au vendredi.

Par exemple:

  • Mercredi - 3 jours ouvrables = Vendredi dernier
  • Mercredi + 3 jours ouvrés = lundi
  • Vendredi - 7 jours ouvrables = mercredi dernier
  • Mardi - 5 jours ouvrables = mardi dernier

Eh bien, vous avez l'idée;)

J'ai fini par écrire cette classe d'extension

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

Il utilise cette méthode que je pensais utile d'utiliser ailleurs ...

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

Si vous ne voulez pas vous en soucier, vous pouvez simplement remplacer if (MyClass.IsBusinessDay(date))par ifif ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

Alors maintenant tu peux faire

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

ou

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

Voici les résultats de certains tests:

Résultat attendu du test
Mercredi -4 jours ouvrables jeudi jeudi
Mercredi -3 jours ouvrables vendredi vendredi
Mercredi +3 jours ouvrables lundi lundi
Vendredi -7 jours ouvrables mercredi mercredi
Mardi -5 jours ouvrables Mardi Mardi
Vendredi +1 jour ouvrable Lundi Lundi
Samedi +1 jour ouvrable lundi lundi
Dimanche -1 jour ouvrable vendredi vendredi
Lundi -1 jour ouvrable vendredi vendredi
Lundi +1 jour ouvrable Mardi Mardi
Lundi +0 jours ouvrables Lundi Lundi
Hugo Yates
la source
J'ai également fait de la 2ème méthode une méthode d'extension: public static bool IsBusinessDay (cette date DateTime)
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
la source
1

J'arrive en retard pour la réponse, mais j'ai fait une petite bibliothèque avec toute la personnalisation nécessaire pour faire des opérations simples les jours ouvrables ... Je la laisse ici: Gestion des jours ouvrables

Sans os
la source
2
Malheureusement, il s'agit d'une licence GNU, tout comme le "poison légal" pour toute application commerciale. Y a-t-il une chance que vous détendiez cela avec "MIT" ou "Apache"?
Tony O'Hagan
Certaines listes statiques devraient probablement être des tableaux (plutôt que des listes chaînées).
Tony O'Hagan
1
Je viens de changer la licence en MIT (je ne veux rien bloquer sur quelque chose d'aussi simple). Je vais examiner votre autre proposition.
Désossé
Bien, il serait intéressant de voir la gestion des jours ouvrables par pays car certains pays peuvent avoir d'autres jours ouvrables que du lundi au vendredi.
sérialiseur
1

La seule vraie solution est de permettre à ces appels d'accéder à une table de base de données qui définit le calendrier de votre entreprise. Vous pouvez le coder pour une semaine de travail du lundi au vendredi sans trop de difficulté, mais la gestion des vacances serait un défi.

Modifié pour ajouter une solution partielle non élégante et non testée:

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

J'ai également violé l'exigence de non-boucle.

Jamie Ide
la source
Je ne pense pas que l'affaire du samedi serait un jour touchée.
CoderDennis
@Dennis - ce serait le cas si la date passée était un samedi.
Jamie Ide
J'ai pris la liberté d'éditer votre code afin de le faire fonctionner. Veuillez tester le code avant de le publier la prochaine fois, merci.
bytecode77
Et je pensais que le zéro vote positif parlait de lui-même. Merci!
Jamie Ide le
1

Je ressuscite ce message car aujourd'hui je devais trouver un moyen d'exclure non seulement les samedis et dimanches en semaine, mais aussi les jours fériés. Plus précisément, j'avais besoin de gérer divers ensembles de vacances possibles, notamment:

  • les jours fériés indifférents au pays (au moins pour les pays occidentaux - comme le 1er janvier).
  • jours fériés calculés (comme Pâques et le lundi de Pâques).
  • les jours fériés spécifiques au pays (comme le jour de la libération italienne ou l'ID4 des États-Unis).
  • les jours fériés spécifiques à la ville (comme le jour de la Saint-Patron de Rome).
  • tout autre jour férié sur mesure (tel que «demain notre bureau sera fermé»).

Finalement, je suis sorti avec l'ensemble suivant de classes d'assistance / d'extensions: bien qu'elles ne soient pas d'une élégance flagrante, car elles utilisent massivement des boucles inefficaces, elles sont assez décentes pour résoudre mes problèmes pour de bon. Je laisse tomber tout le code source ici dans cet article, en espérant qu'il sera également utile à quelqu'un d'autre.

Code source

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

Informations d'utilisation

Le code est assez explicite, mais voici quelques exemples pour expliquer comment vous pouvez l'utiliser.

Ajoutez 10 jours ouvrables (sautez uniquement les jours de la semaine samedi et dimanche)

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

Ajoutez 10 jours ouvrables (sautez le samedi, le dimanche et tous les jours fériés en fonction du pays pour 2019)

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

Ajoutez 10 jours ouvrables (sautez le samedi, le dimanche et tous les jours fériés italiens pour 2019)

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

Ajoutez 10 jours ouvrables (sautez le samedi, le dimanche, tous les jours fériés italiens et les jours fériés spécifiques à Rome pour 2019)

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

Les fonctions et exemples de code ci-dessus sont expliqués plus en détail dans cet article de mon blog.

Darkseal
la source
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
la source
à l'avenir, ajoutez un peu plus de contexte pour la réponse et peut-être pourquoi vous avez mis ce que vous avez :)
dax
0

Je voulais un "AddBusinessDays" prenant en charge des nombres négatifs de jours à ajouter, et je me suis retrouvé avec ceci:

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

Aucune boucle n'est requise, elle devrait donc être raisonnablement rapide même pour les "gros" ajouts.

Cela fonctionne avec des jours exprimés en nombre de jours calendaires depuis l'époque, car cela est exposé par la nouvelle classe JDK8 LocalDate et je travaillais en Java. Cela devrait cependant être simple à adapter à d'autres paramètres.

Les propriétés fondamentales sont que addDaysrenvoie toujours un jour de la semaine, et que pour tous det n,daysBetween(d, addDays(d, n)) == n

Notez qu'en théorie, ajouter 0 jour et soustraire 0 jour devrait être une opération différente (si votre date est un dimanche, ajouter 0 jour devrait vous amener au lundi, et soustraire 0 jour devrait vous amener au vendredi). Comme il n'y a pas de négatif 0 (en dehors de la virgule flottante!), J'ai choisi d'interpréter un argument n = 0 comme signifiant ajouter zéro jour.

Max Bolingbroke
la source
0

Je pense que cela pourrait être un moyen plus simple de GetBusinessDays:

    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
la source
0

Voici mon code avec la date de départ et la date de livraison chez le client.

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

Bon codage.

JanBorup
la source
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
la source
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
la source
-1

J'espère que cela aide quelqu'un.

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
la source
2
Ceci est une erreur. Dans la plupart des cas, cela ne fonctionnera pas. Peu de chances d’aider qui que ce soit.
Neolisk