C# AddBusinessDays 和 GetBusinessDays

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1044688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 06:53:17  来源:igfitidea点击:

AddBusinessDays and GetBusinessDays

c#.net

提问by Adrian Zanescu

I need to find 2 elegant complete implementations of

我需要找到 2 个优雅的完整实现

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) preferable (no loops).

O(1) 更可取(无循环)。

EDIT: By business days i mean working days (Monday, Tuesday, Wednesday, Thursday, Friday). No holidays, just weekends excluded.

编辑:我所说的工作日是指工作日(星期一、星期二、星期三、星期四、星期五)。没有节假日,只有周末除外。

I already have some ugly solutions that seem to work but i wonder if there are elegant ways to do this. Thanks

我已经有一些看起来可行的丑陋解决方案,但我想知道是否有优雅的方法来做到这一点。谢谢



This is what i've written so far. It works in all cases and does negatives too. Still need a GetBusinessDays implementation

这是我到目前为止所写的。它适用于所有情况,也适用于底片。仍然需要一个 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);
}

采纳答案by Patrick McDonald

Latest attempt for your first function:

第一个函数的最新尝试:

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

}

The second function, GetBusinessDays, can be implemented as follows:

第二个函数 GetBusinessDays 可以实现如下:

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

回答by Jamie Ide

The only real solution is to have those calls access a database table that defines the calendar for your business. You could code it for a Monday to Friday workweek without too much difficult but handling holidays would be a challenge.

唯一真正的解决方案是让这些调用访问为您的企业定义日历的数据库表。您可以为周一至周五的工作周编写代码而不会太困难,但处理假期将是一个挑战。

Edited to add non-elegant and non-tested partial solution:

编辑添加非优雅和未经测试的部分解决方案:

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

Also I violated the no loops requirement.

我也违反了无循环要求。

回答by LukeH

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

回答by Simon

using Fluent DateTime:

使用流畅的日期时间

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

internal code is as follows

内部代码如下

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

回答by Arjen

I created an extension that allows you to add or subtract business days. Use a negative number of businessDays to subtract. I think it's quite an elegant solution. It seems to work in all cases.

我创建了一个扩展程序,允许您增加或减少工作日。使用负数的工作日来减去。我认为这是一个非常优雅的解决方案。它似乎适用于所有情况。

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

Example:

例子:

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

回答by user2686690

Hope this helps someone.

希望这可以帮助某人。

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

回答by Alex

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

回答by Hugo Yates

For me I had to have a solution that would skip weekends and go in either negative or positive. My criteria was if it went forward and landed on a weekend it would need to advance to Monday. If it was going back and landed on a weekend it would have to jump to Friday.

对我来说,我必须有一个解决方案,可以跳过周末并进入消极或积极的状态。我的标准是,如果它前进并在周末着陆,则需要提前到星期一。如果它要返回并在周末降落,则必须跳到周五。

For example:

  • Wednesday - 3 business days = Last Friday
  • Wednesday + 3 business days = Monday
  • Friday - 7 business days = Last Wednesday
  • Tuesday - 5 business days = Last Tuesday

例如:

  • 周三 - 3 个工作日 = 上周五
  • 星期三 + 3 个工作日 = 星期一
  • 周五 - 7 个工作日 = 上周三
  • 周二 - 5 个工作日 = 上周二

Well you get the idea ;)

反正你懂这个意思 ;)

I ended up writing this extension class

我最终编写了这个扩展类

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

It uses this method I thought would be useful to use elsewhere...

它使用这种方法,我认为在其他地方使用会很有用......

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

If you don't want to bother with that you can just replace out if (MyClass.IsBusinessDay(date))with if if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

如果你不想打扰,你可以if (MyClass.IsBusinessDay(date))用 if代替if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

So now you can do

所以现在你可以做

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

or

或者

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

Here are the results from some testing:

以下是一些测试的结果:

Test                         Expected   Result
Wednesday -4 business days   Thursday   Thursday
Wednesday -3 business days   Friday     Friday
Wednesday +3 business days   Monday     Monday
Friday -7 business days      Wednesday  Wednesday
Tuesday -5 business days     Tuesday    Tuesday
Friday +1 business days      Monday     Monday
Saturday +1 business days    Monday     Monday
Sunday -1 business days      Friday     Friday
Monday -1 business days      Friday     Friday
Monday +1 business days      Tuesday    Tuesday
Monday +0 business days      Monday     Monday

回答by Max Bolingbroke

I wanted an "AddBusinessDays" that supported negative numbers of days to add, and I ended up with this:

我想要一个支持负天数添加的“AddBusinessDays”,我最终得到了这个:

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

No loop required, so it should be reasonably fast even for "big" additions.

不需要循环,因此即使对于“大”添加,它也应该相当快。

It works with days expressed as a number of calendar days since the epoch, since that's exposed by the new JDK8 LocalDate class and I was working in Java. Should be simple to adapt to other settings though.

它使用自纪元以来的日历天数表示的天数,因为新的 JDK8 LocalDate 类公开了这一点,而我正在使用 Java。不过应该很容易适应其他设置。

The fundamental properties are that addDaysalways returns a weekday, and that for all dand n, daysBetween(d, addDays(d, n)) == n

基本属性是addDays总是返回一个工作日,并且对于所有dndaysBetween(d, addDays(d, n)) == n

Note that theoretically speaking adding 0 days and subtracting 0 days should be different operations (if your date is a Sunday, adding 0 days should take you to Monday, and subtracting 0 days should take you to Friday). Since there's no such thing as negative 0 (outside of floating point!), I've chosen to interpret an argument n=0 as meaning addzero days.

请注意,理论上加0天和减0天应该是不同的操作(如果你的日期是星期天,加0天应该带你到星期一,减0天应该带你到星期五)。由于没有负 0(浮点之外!),我选择将参数 n=0 解释为意味着添加零天。

回答by Boneless

I'm coming late for the answer, but I made a little library with all the customization needed to do simple operations on working days... I leave it here : Working Days Management

我迟到了答案,但我制作了一个小库,其中包含在工作日进行简单操作所需的所有自定义...我将其留在这里:工作日管理