c#添加/减去工作日的日期时间

时间:2011-01-05 13:21:58

标签: c# datetime

我的情况是,给定日期(DateTime),该日期加/减x天(使用DateTime.AddDays实现)必须添加或减去x个工作日,即跳过周末和假期。我怎么能这样做呢?我应该实现自己的版本并将其附加到日历或其他东西?

10 个答案:

答案 0 :(得分:54)

我建议您必须自己实现它,并且会在这样的扩展方法中执行:


public static class DateTimeExtensions
{
    public static DateTime AddWorkdays(this DateTime originalDate, int workDays)
    {
        DateTime tmpDate = originalDate;
        while (workDays > 0)
        {
            tmpDate = tmpDate.AddDays(1);
            if (tmpDate.DayOfWeek < DayOfWeek.Saturday && 
                tmpDate.DayOfWeek > DayOfWeek.Sunday &&
                !tmpDate.IsHoliday())
                workDays--;
        }
        return tmpDate;
    }

    public static bool IsHoliday(this DateTime originalDate)
    {
        // INSERT YOUR HOlIDAY-CODE HERE!
        return false;
    }
}

答案 1 :(得分:50)

基于Taz's link

public static class DateTimeExtensions
{
  public static DateTime AddWorkDays(this DateTime date, int workingDays)
  {
    int direction = workingDays < 0 ? -1 : 1;
    DateTime newDate = date;
    while (workingDays != 0)
    {
      newDate = newDate.AddDays(direction);
      if (newDate.DayOfWeek != DayOfWeek.Saturday && 
          newDate.DayOfWeek != DayOfWeek.Sunday && 
          !newDate.IsHoliday())
      {
        workingDays -= direction;
      }
    }
    return newDate;
  }

  public static bool IsHoliday(this DateTime date)
  {
    // You'd load/cache from a DB or file somewhere rather than hardcode
    DateTime[] holidays = 
    new DateTime[] { 
      new DateTime(2010,12,27),
      new DateTime(2010,12,28),
      new DateTime(2011,01,03),
      new DateTime(2011,01,12),
      new DateTime(2011,01,13)
    };

    return holidays.Contains(date.Date);
  }
}

答案 2 :(得分:8)

我最近用一点LINQ做了这个:

private DateTime CalculateFutureDate(DateTime fromDate, int numberofWorkDays, ICollection<DateTime> holidays)
{
    var futureDate = fromDate;
    var daterange = Enumerable.Range(1, numberofWorkDays * 2);
    var dateSet = daterange.Select (d => futureDate.AddDays(d));
    var dateSetElim = dateSet.Except(holidays).Except(dateSet.Where( s =>s.DayOfWeek == DayOfWeek.Sunday).Except(dateSet.Where  (s=>s.DayOfWeek==DayOfWeek.Saturday) ));

    //zero-based array
    futureDate = dateSetElim.ElementAt(numberofWorkDays-1);
    return futureDate;
}

答案 3 :(得分:2)

我花了一些时间来解决这个问题...我已经创建了一个数据库表,我在假期里把它拉成一个数组。All Credit to Kev (on this post) ..我不得不修改他的工作对我来说是这样的。

在我的情况下,如果第一天是星期六,而我的workingDayCount = -1,我想在星期四回来(因为我的约会不能在周末或假期......但它必须是工作日。在这种情况下星期五。)

Kev的代码可以传回一个星期天...下面的代码将把它带到前一个工作日(通常是星期五 - 除非星期五是假期,星期四它会回来)。

public static DateTime AddWorkDays(this DateTime date, int workingDays, params Holidays[] bankHolidays)
    {
        int direction = workingDays < 0 ? -1 : 1;
        DateTime newDate = date;
        // If a working day count of Zero is passed, return the date passed
        if (workingDays == 0)
        {

            newDate = date;
        }
        else
        {
            while (workingDays != -direction)
            {
                if (newDate.DayOfWeek != DayOfWeek.Saturday &&
                    newDate.DayOfWeek != DayOfWeek.Sunday &&
                    Array.IndexOf(bankHolidays, newDate) < 0)
                {
                    workingDays -= direction;
                }
                // if the original return date falls on a weekend or holiday, this will take it to the previous / next workday, but the "if" statement keeps it from going a day too far.

                if (workingDays != -direction)
                { newDate = newDate.AddDays(direction); }
            }
        }
        return newDate;
    }

这是我简单的假期课程:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Clarity.Utilities
{
    public class Holidays 
    {
        public int Id { get; set; }
        public DateTime dtHoliday  { get; set; }
        public string Desc { get; set; }
        public bool Active { get; set; }

    }
}

以下是填充数组的方法:

private Holidays[] PopulateArrayWithDates()
    {
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DBConn"].ConnectionString);
        DateTime[] dtHolidays = new DateTime[] { };
        string sql = @"SELECT HolDate, HolName FROM [Server].DBName.dbo.tblHolidays";
        SqlCommand ADDCmd = new SqlCommand(sql, con);
        DataTable table = new DataTable();
        DataTable tbl = new DataTable();
        Utilities.Holidays[] allRecords = null;

        using (var command = new SqlCommand(sql, con))
        {
            con.Open();
            using (var reader = command.ExecuteReader())
            {
                var list = new List<Holidays>();
                while (reader.Read())
                    list.Add(new Holidays { dtHoliday = reader.GetDateTime(0), Desc = reader.GetString(1) });
                allRecords = list.ToArray();
            }
        }
        return allRecords;
    }

答案 4 :(得分:1)

我希望在周末添加和减去日期,这是Google的第一个条目。我不喜欢这里的任何答案所以我会添加我自己制作的那个以防万一有人像我这样结束:

   jQuery.ajax({url:'./ajax.html', async: true, success: function(response){

                        var addcode=" ";
                        var i=1;

                        $.each(response, function(key,value) {

                                addcode +=  '<ul>' + (i++)  + '. ' + key;
                                addcode += '<li>' + value + '</li>';
                                addcode += '</ul>';

                        });
                        jQuery('#catcher').html(addcode);
    }})    

我希望这有助于某人。

答案 5 :(得分:0)

你应该自己检查一天是否正常工作,因为DateTime课程无法知道今年哪些天会是假期:)

答案 6 :(得分:0)

你应该有一个假期数据库来检查,如果day plus / minus x的值等于数据库中的值加/减另一个,因为不是每个人都有相同的假期。

答案 7 :(得分:0)

我已经修改了以前的更多功能方法的答案。我在下面提供了两个解决方案,一个使用IEnumerable,一个使用IObservable和Reactive Extensions

使用IObservable

public static class DateTimeExtensions
{
    public static DateTime AddWorkDays(this DateTime date, int workingDays)
    {
        return Observable
            .Generate
                (date, arg => true, arg => arg.AddDays(workingDays < 0 ? -1 : 1), arg => arg)
            .Where(newDate =>
                (newDate.DayOfWeek != DayOfWeek.Saturday &&
                 newDate.DayOfWeek != DayOfWeek.Sunday &&
                 !newDate.IsHoliday()))
            .Take(Math.Abs(workingDays) + 1)
            .LastAsync()
            .Wait();
    }

    public static bool IsHoliday(this DateTime date)
    {
        return false;
    }
}

使用IEnumerable

public static class DateTimeExtensions
{
    public static DateTime AddWorkDays(this DateTime date, int workingDays)
    {
        return date.GetDates(workingDays < 0)
            .Where(newDate =>
                (newDate.DayOfWeek != DayOfWeek.Saturday &&
                 newDate.DayOfWeek != DayOfWeek.Sunday &&
                 !newDate.IsHoliday()))
            .Take(Math.Abs(workingDays))
            .Last();
    }

    private static IEnumerable<DateTime> GetDates(this DateTime date, bool isForward)
    {
        while (true)
        {
            date = date.AddDays(isForward ? -1 : 1);
            yield return date;
        }
    } 

    public static bool IsHoliday(this DateTime date)
    {
        return false;
    }
}

答案 8 :(得分:0)

简单的解决方案就在这里尝试并享受编码

public class Program
{
    public static void Main(string[] args)
    {
        Double days= 7;
        string s=DateTime.Now.AddDays(7).ToString("dd/MM/yyyy");  
        DateTime dt= OrderDeliveryDate(days);
        Console.WriteLine("dt"+dt.ToString("dd/MM/yyyy"));


    }

    public static DateTime OrderDeliveryDate(Double days)
    {

        Double count=0;
        for(int i=0;i<days;i++)
        {
            if(DateTime.Now.AddDays(i).DayOfWeek.ToString() == "Saturday")
            {
               count= count+1;
            }
            else if(DateTime.Now.AddDays(i).DayOfWeek.ToString() == "Sunday")
            {
                count=count+1;
            }

        }
        days=days+count;
        return DateTime.Now.AddDays(days);
    }
}

答案 9 :(得分:0)

    public static DateTime AddBussinessDays(this DateTime originalDate, int workDays)
    {
        if (workDays == 0)
        {
            return originalDate;
        }

        originalDate = originalDate.AddDays(workDays);

        if (originalDate.IsHoliday() || originalDate.DayOfWeek == DayOfWeek.Saturday || originalDate.DayOfWeek == DayOfWeek.Sunday)
        {
            return originalDate.AddBussinessDays(workDays < 0 ? -1 : 1);
        }

        return originalDate;
    }

我为您提出了一个递归版本的解决方案,该方法也可以通过将负整数值完全传递给AddDays方法来减去天数。