9
votes

C #: Ajout de jours ouvrables à partir d'une certaine date

J'ai du mal à faire ça. Je crée une méthode qui ajoutez des jours ouvrables à une date précise. Par exemple, je souhaite ajouter 3 jours ouvrables au 15 septembre 2010 (mercredi), la méthode reviendrait le 20 septembre (lundi la semaine prochaine). Cela ignore samedi et dimanche parce que sa journée non ouvrable ..

Quelque chose comme ça en C #: xxx

Je ne considère pas les jours fériés spéciaux sur les calculs, je viens de Je veux littéralement ajouter des jours sauf le samedi et le dimanche .. Merci d'avance! =)


0 commentaires

6 Réponses :


19
votes

Si vous n'avez pas besoin d'envisager des vacances, je vous suggérerais de faire quelque chose comme ceci: XXX

C'est inefficace, mais facile à comprendre. Pour une version efficace, vous allez déterminer le nombre de semaines complètes à ajouter comme avant, mais ensuite avoir une cartographie de n'importe quel "jour en cours de la semaine" et "jours ouvrables restants pour ajouter" à "Nombre de réel < / em> jours à ajouter ". Ensuite, vous pouvez simplement travailler le nombre total de jours à ajouter et le faire dans un appel.

Edit: En termes de niveau d'inefficacité ... ce n'est vraiment pas très mauvais. Ça n'effectuera que manuel "Est-ce un week-end" vérifie jusqu'à 4 jours, ce qui n'est pas trop mauvais. En particulier, malgré les affirmations d'Igor (actuelles au moment de l'affichage), il est plutôt plus rapide que son approche, des repères défectueux nonobstant;)

Notez qu'il ne faut pas gérer les intrants négatifs, je n'ai pas encore vérifié.

L'une des raisons de l'approche que j'utilise est qu'elle ne repose pas sur moi ou le lecteur de code sachant quelles valeurs dans le jour énum sont. Je me fiche de savoir s'il est 0-6, 1-7 du lundi-dimanche, samedi-vendredi ... ou même s'il y a des valeurs complètement bizarres. Je comparais seulement pour l'égalité, ce qui rend le code plus "évidemment correct".


16 commentaires

Jon, serait-il plus efficace d'utiliser WEURDAYSTADD = WEURDAYSTOADD% 5; Date = date.adddays (workingdaysAdd); Si (date.dayofeek == Dayofweek.Saturday) Date.Adddays (2); Si (date.dayofeek == dayofweek.sunday) date.adddays (1); plutôt que la construction de boucle? Juste curieux.


Je l'ai testé et cela fonctionne à ce dont j'ai besoin exactement. L'avez-vous fait à la volée? En moins de 5 minutes depuis que je l'ai posté .. Homme, c'est assez génial .. mais j'accueillerais des réponses plus efficaces .. Merci BTW ..


Je ne dirais pas que c'est inefficace, mais toutes les choses sont relatives. La réponse comptait des semaines à l'avance, de sorte que la plupart d'entre elles auront jamais à boucle est 6 fois (max 4 pour les jours ouvrables% 5, max 2 pour les jours de week-end). Pas un coup énorme.


@Lazarus: Ce code ne fonctionnera pas si vous essayez d'ajouter 3 jours au vendredi - cela donnera lundi au lieu de mercredi.


@CSHARPNOOB: Oui. Heureux que ça marche. Je ne peux pas dire que j'ai testé ou même le compilé ... :( @anthony: Bien sûr, il est probable que c'est probablement assez rapide dans la plupart des cas ... mais il y a de la place pour améliorer si cela devient une goulot.


Merci Jon. Je vais le convertir en extension .. =)


@ Jon-Skeet: fissuré à la fin si (((int) spécifiqueDate.dayofweek + wunnighdaystadd> 5) spécificdate = Spécificadatedays.addays (2); remplace la boucle.


@Lazarus: Yup, quelque chose comme ça fonctionnera ... Mais je trouverais plus difficile de lire. Ce n'est pas aussi évidemment Droit ... En particulier, vous devez connaître les valeurs ENUM. Je ne sais pas le sommet de ma tête quelles sont les valeurs de samedi et dimanche ... C'est pourquoi j'ai écrit le code pour ne pas s'en soucier.


@ Jon-Skeet: Vous avez brisé mes illusions ... quelque chose que vous ne savez pas du haut de votre tête! Je vous donnerai que ceci est un cadre et non c # alors votre statut reste peut-être que votre statut reste intact, bien qu'un peu tremblant :) dimanche = 0, samedi = 6, donc quelque chose de plus grand que 5 (vendredi) signifie que nous avons frappé un week-end et avez besoin d'insérer 2 jours.


@Lazarus: Il y a un point plus grand ici bien que ... Voulez-vous compter sur Tous ceux qui lisent le code pour connaître les valeurs ENUM afin de comprendre ce que cela va? C'est ce que j'essaie de m'éloigner.


@ Jon-Skeet: Je vois ce que vous dites et je suis d'accord que vous devriez avoir à recourir à la documentation pour être certain de ce que je faisais où vous pouviez vous asseoir avec un stylo et un papier pour traverser votre boucle pour la comprendre. Sur le papier pour vendredi + 3 jours ouvrables, je reçois mardi comme résultat. @ i == 0 (date = vendredi, date.adddays (1) = Samedi,! Isweekday, date.addayes (1) = dimanche), @ i == 1 (date = dimanche, date.adddays (1 ) = Lundi, isweekday), @ i == 2 (date = lundi, date.addayes (1) = mardi), date de retour = mardi Qu'est-ce que je manque?


@Lazarus: Vous manquez le fait que c'est une boucle de temps, pas seulement un seul test. Fondamentalement, j'ajoute une journée, puis saute le week-end complètement.


@ Jon-Skeet: Je réclamez le N L'amendement "manque de café" et se retirez-vous au coin :)


@Jonskeet Voici un algorithme testé pour le faire sans boucle: Stackoverflow.com/a/33943576/4389984 (deuxième solution ) En dehors de la connaissance du jour de la semaine de cartographie (1-7) et de la lisibilité, voyez-vous une faille dans la logique? Merci!


@Anmol: Le manque de lisibilité rend beaucoup plus difficile à rechercher des défauts, d'être honnête. C'est pourquoi j'aime l'option de bouclage - elle est morte facile à comprendre, et à moins que vous ne sachiez que vous sont ajouter beaucoup de jours de travail (pas le cas dans cette question) Je favoriserais la lisibilité sur l'efficacité. En outre, il est vraiment facile d'aller d'une implémentation naïf qui ignore les jours fériés à une implémentation naïve qui inclut des jours fériés, compte tenu de la liste des jours fériés - c'est beaucoup plus difficile à faire la même chose avec une version calculatrice.


Je comprends. Surtout compte tenu des jours fériés, est vraiment complexe dans le calcul de la version. Merci pour l'aperçu!



0
votes

Voici ce dont vous avez besoin:

mis à jour: xxx


2 commentaires

Mais le paramètre DateTime (Démarrer) peut aussi être dimanche et saturrday .. :( .. Si samedi et dimanche, il doit retourner mercredi de la semaine prochaine,


N'est-ce pas un peu trop compliqué? Je pense que cela peut être fait de manière beaucoup plus simple



0
votes
class Program
    {

        public static DateTime AddWorkingDays(DateTime specificDate,
                                      int workingDaysToAdd)
        {
            int completeWeeks = workingDaysToAdd / 5;
            DateTime date = specificDate.AddDays(completeWeeks * 7);
            workingDaysToAdd = workingDaysToAdd % 5;
            for (int i = 0; i < workingDaysToAdd; i++)
            {
                date = date.AddDays(1);
                while (!IsWeekDay(date))
                {
                    date = date.AddDays(1);
                }
            }
            return date;
        }

        private static bool IsWeekDay(DateTime date)
        {
            DayOfWeek day = date.DayOfWeek;
            return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
        }

        public static DateTime MyAddWorkingDays(DateTime specificDate,
                                      int workingDaysToAdd)
        {
            int foundWorkingDays = 0;
            while (foundWorkingDays < workingDaysToAdd)
            {
                specificDate = specificDate.AddDays(1);
                if (specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday)
                    foundWorkingDays++;

            }
            return specificDate;
        }


        static void Main(string[] args)
        {

            DateTime specificDate = DateTime.Now;

            Stopwatch globalTimer = Stopwatch.StartNew();
            Console.WriteLine(AddWorkingDays(specificDate, 300));  // 100000 :)
            globalTimer.Stop();
            Console.WriteLine(globalTimer.ElapsedMilliseconds);

            globalTimer = Stopwatch.StartNew();
            Console.WriteLine(MyAddWorkingDays(specificDate, 300)); // 100000 :)
            globalTimer.Stop();
            Console.WriteLine(globalTimer.ElapsedMilliseconds);



            Console.ReadLine();
        }
    }

9 commentaires

Est-ce plus efficace que M.. La suggestion de Jon Skeet?


@CSHARPNOOB, non. C'est essentiellement la même logique sans manipuler des semaines entières à l'avant. Donc, au lieu d'une boucle pouvant être de 1 à 4 (plus de deux jours de week-end), vous avez une boucle qui sera de 1 à n (plus tout week-end jours)


Quelle est la différence entre MyAdDDworkingdays et Addworkingdays dans votre code?


@CSHARPNOOB MYADDDDORDS est principal, addworkingdays est M.. Jon Skeet's One. Je n'ai pas testé d'autres. Essayez-les tous si vous avez besoin


essayé mais cela ajoute seulement 1 jour ouvrable si le jour spécifié est le lundi au vendredi et ajoute 2 si Sat / Sun .. =)


@CSHARPNOOB Le premier code a la typographie "CouranteDate" (je l'ai déjà corrigée). Essayez le deuxième! :)


Merci Igor, je l'ai testé à nouveau et cela fonctionne désormais parfaitement, c'est plus court que Jon et la performance sage comme vous le dites, c'est mieux .. et je vais le convertir en extension .. Merci beaucoup ..


@IGOR: Votre référence est horriblement défectueux. Essayez d'échanger autour de ce qui aboutit à imprimer en premier ... Les résultats Basculent également. Vous y compris la compilation JIT, y compris la compilation JIT de la console.writeine. Essayez d'exécuter les deux versions 10000 fois dans une boucle, même pendant 300 jours, et vous trouverez ma version est beaucoup plus rapide que la vôtre ... et cela devrait donc être, étant donné que vous testez Que ce soit chaque jour est le week-end, plutôt que quelques-uns d'entre eux.


@Jon Skeet Oh, merci! Oui bien sûr, vous avez raison. il était attendu résultat. Votre seul est plus rapide, désolé.



2
votes

une manière cool (je pense) est mise que dans une méthode d'extension, comme: xxx pré>

de sorte que votre code final ressemblera à: p>

specificDate.AddWorkingDays(3);


2 commentaires

Comme Csharpnoob a souligné, ce code ne fonctionne pas bien correctement, mais j'aime vraiment l'approche d'utiliser une méthode d'extension pour cela.


Oui, c'est faux, je n'ai pas bien testé avant la poste. désolé gars, ma faute.



0
votes

est un ancien poste mais quelqu'un pourrait être intéressé par une extension qui traite également des jours négatifs. (J'ai retravaillé @jon Réponse)

    public static DateTime AddWeekDays(this DateTime start, int days)
    {
        int direction = Math.Sign(days);

        int completeWeeks = days / 5;
        int remaining = days % 5;

        DateTime end = start.AddDays(completeWeeks * 7);

        for (int i = 0; i < remaining * direction; i++)
        {
            end = end.AddDays(direction * 1);
            while (!IsWeekDay(end))
            {
                end = end.AddDays(direction * 1);
            }
        }
        return end;
    }

    private static bool IsWeekDay(DateTime date)
    {
        DayOfWeek day = date.DayOfWeek;
        return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
    }


0 commentaires

0
votes

Cela me semble le moyen le plus propre: xxx


0 commentaires