如何在给定日期前 14 天避免假期

Posted

技术标签:

【中文标题】如何在给定日期前 14 天避免假期【英文标题】:How to get 14 days prior to the given date avoiding holidays 【发布时间】:2012-06-07 10:01:00 【问题描述】:

在我的系统中,账单的到期日必须是开具日期之后的 14 天。 我有截止日期,我想知道签发日期。 我必须计算:

issued date = 14 days prior to the due date

14天必须是工作日,而不是节假日。 假期像这样存储在表 'tblHolidayMaster' 中,

日期                   描述 2012/05/13         妈妈的 日子2012 年 6 月 2 日         星期六2012 年 12 月 25 日         圣诞节

如何计算避开节假日的签发日期? 感谢您的所有关注和回复。

【问题讨论】:

我从表格中选择了所有的假期并计算得到发布日期。有没有更简单的解决方案?? 不,您的解决方案是正确的。假期没有公式。 使用我的解决方案,我必须选择所有数据,即使是大约 2 年、3 年的旧数据:( 最好有一个日历表(而不是只有一个假期表)(一个例子here)。从长远来看,它使编写许多与日期相关的查询变得更容易。 给定日期是否保证为工作日?如果不是,您想如何处理非假日目标日期? 【参考方案1】:

我会使用如下函数(我使用的)计算日期

public static DateTime AddBusinessDays(DateTime date, int 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;
 

int extraDaysForHolidays =-1;
//Load holidays from DB into list
List<DateTime> dates = GetHolidays();

while(extraDaysForHolidays !=0)


 var days =  dates.Where(x => x >= date  && x <= date.AddDays(extraDays)).Count;
 extraDaysForHolidays =days;
 extraDays+=days;  



return date.AddDays(extraDays);

还没有测试过假期的 ast 部分

【讨论】:

我不会那样做内联 SQL。我宁愿将日期放入一个列表(按日期排序)并对其进行一次迭代。 我认为您的假期代码与周末的交互不正确。 这不重要@chaos,因为周末不会有假期 @CodeInChaos 将日期放入列表需要将完整的表格加载到内存中。通常这不是问题,但有时会。 (但是,如果您需要这样的单独查询,请使用参数。) holyday代码有几个bug:1)如果区间内至少有一个假期,循环不会终止(除非int溢出) 2)临近周末的假期可以推返回值到周末。 3) 假期可以在周末。至少在德国。例如复活节星期天。【参考方案2】:

我选择了直接循环的解决方案,所以长时间间隔会很慢。但是对于像 14 天这样的短时间间隔,它应该是相当快的。

你需要在构造函数中传入假期。 BusinessDays 的实例是不可变的并且可以重用。在实践中,您可能会使用 IoC 单例或类似的构造来获取它。

如果开始日期是非工作日,AddBusinessDays 会抛出 ArgumentException,因为您没有指定如何处理这种情况。特别是AddBusinessDays(0) 在非工作日会有奇怪的属性。它要么打破时间反转对称性,要么返回非工作日。

public class BusinessDays

    private HashSet<DateTime> holidaySet;
    public ReadOnlyCollection<DayOfWeek> WeekendDaysget; private set;

    public BusinessDays(IEnumerable<DateTime> holidays, IEnumerable<DayOfWeek> weekendDays)
    
        WeekendDays = new ReadOnlyCollection<DayOfWeek>(weekendDays.Distinct().OrderBy(x=>x).ToArray());
        if(holidays.Any(d => d != d.Date))
            throw new ArgumentException("holidays", "A date must have time set to midnight");
        holidaySet = new HashSet<DateTime>(holidays);
    

    public BusinessDays(IEnumerable<DateTime> holidays)
        :this(holidays, new[]DayOfWeek.Saturday, DayOfWeek.Sunday)
    
    

    public bool IsWeekend(DayOfWeek dayOfWeek)
    
        return WeekendDays.Contains(dayOfWeek);
    

    public bool IsWeekend(DateTime date)
    
        return IsWeekend(date.DayOfWeek);
    

    public bool IsHoliday(DateTime date)
    
        return holidaySet.Contains(date.Date);
    

    public bool IsBusinessDay(DateTime date)
    
        return !IsWeekend(date) && !IsHoliday(date);
    

    public DateTime AddBusinessDays(DateTime date, int days)
    
        if(!IsBusinessDay(date))
            throw new ArgumentException("date", "date bust be a business day");
        int sign = Math.Sign(days);
        while(days != 0)
        
            do
            
              date.AddDays(sign);
             while(!IsBusinessDay(date));
            days -= sign;
        
        return date;
    

【讨论】:

【参考方案3】:

我认为这就是您所需要的。它很简单,我已经对其进行了测试,它正在工作......在数据库中编写函数或 SP 而不是在 C# 中编写复杂的代码并不是一个坏方法......(更改日期的列名,如您的分贝)

使其功能或 SP 成为你想要的。

注意:注释“星期六”和“星期日”的检查。如果它已经添加到您的表记录中。

declare @NextWorkingDate datetime
declare @CurrentDate datetime
set @CurrentDate = GETDATE()
set @NextWorkingDate = @CurrentDate 
declare @i int = 0
While(@i < 14)
Begin
    if(((select COUNT(*) from dbo.tblHolidayMaster where convert(varchar(10),[Date],101) like convert(varchar(10),@NextWorkingDate,101)) > 0) OR DATENAME(WEEKDAY,@NextWorkingDate) = 'Saturday' OR DATENAME(WEEKDAY,@NextWorkingDate) = 'Sunday')
    Begin
        print 'a '  
        print @NextWorkingDate
        set @NextWorkingDate = @NextWorkingDate + 1
        CONTINUE
    End
    else
    Begin
        print  'b ' 
        print @NextWorkingDate
        set @NextWorkingDate = @NextWorkingDate + 1
        set @i = @i + 1
        CONTINUE
    End
End
print @NextWorkingDate 

【讨论】:

【参考方案4】:

我仅从您的表 'tblHolidayMaster' 计算发布日期以避免您的假期。

 int addDay = -14;
  DateTime dtInputDay = System.DateTime.Now;//Your input day
  DateTime dtResultDate = new DateTime();
  dtResultDate = dtInputDay.AddDays(addDay);
  bool result = false;
  string strExpression;
  DataView haveHoliday;
  while (!result) 
      strExpression = "Date >='" + Convert.ToDateTime(dtResultDate.ToString("yyyy/MM/dd")) + "' and Date <='" + Convert.ToDateTime(dtInputDay.ToString("yyyy/MM/dd")) + "'";
      haveHoliday = new DataView(tblHolidayMaster);
      haveHoliday.RowFilter = strExpression;
      if (haveHoliday.Count == 0)           
        result = true;
       else 
          addDay = -(haveHoliday.Count);
          dtInputDay = dtResultDate.AddDays(-1);
          dtResultDate = dtResultDate.AddDays(addDay);
      
                        

您的签发日期是 dtResultDate

【讨论】:

【参考方案5】:

试试下面的链接,

http://www.c-sharpcorner.com/uploadfile/tirthacs/difference-between-two-dates-excluding-weekends/

【讨论】:

以上是关于如何在给定日期前 14 天避免假期的主要内容,如果未能解决你的问题,请参考以下文章

国庆第三天如何避免无聊

如何在特定日期前 2 天触发 UserNotifications

如何获得当前日期前 30 天?

如何在给定日期和时间的情况下让一天倒退 24 小时?

我想在我的第一个视图中保存带有日期和日期的假期列表。我们如何做到这一点?

如何在 SQL Server 中生成日期范围