从日期计算中排除周末和自定义日期(即假期)

时间:2009-10-22 01:49:05

标签: sql sql-server sql-server-2005 tsql

目前,我正在根据开始日期(日期时间)和持续时间(天数)来计算完成日期,但我的计算并未考虑周末或假日。

所以,我的解决方案不正确。这只是一个起点。

我在那里阅读了一些文章,其中一种方法是创建一个巨大的日历表,其中包含未来50年的所有周末和假期。我想这个想法是根据日历表查询日期范围并减去周末和/或假期的数量。

问题是我正在处理的软件允许用户设置自己的项目日历。 考虑到软件允许用户管理多个项目,表格不会变得很大吗?

所以,我想我的问题是如何开始以及解决这个问题的可能方法是什么?

基本上,对于每个项目任务,我需要在给定START日期和DURATION的情况下计算任务完成日期,但要考虑周末和自定义日期(即假日)。

有什么想法吗?

BTW:我正在使用SQL Server 2005.

6 个答案:

答案 0 :(得分:1)

创建一个包含[长时间]剩余时间的所有周末和假日的大日历,将其设置为仅选择。然后,每次创建新项目时,将所需的日期复制到日历中,并复制到项目的日历中。

答案 1 :(得分:1)

  

我在那里阅读了一些文章,其中一种方法是创建一个巨大的日历表,其中包含未来50年的所有周末和假期。我想这个想法是根据日历表查询日期范围并减去周末和/或假期的数量。

这是因为有些假期不会一直在同一天。劳动节例如 - 九月的第一个星期一。它更容易和在数据库中占用较少的空间来存储每年的日期,而不是尝试编写规则来计算它。

其他考虑因素是周六/周日降落的假期 - 如果休息日将在周一或周五下降,那将是一个折腾。有些假期将是联邦政府,而其他假期则是当地的......

答案 2 :(得分:0)

假设您有一个名为AllDays的表,其中包含名为theDay和IsPublicHoliday的列。另外假设您的@@ DATEFIRST设置为1,因此您的周末是第1天和第7天。您想在@StartDate中找到@n天的日期。

WITH NumberedDays AS
(
SELECT theDay, ROW_NUMBER() OVER (ORDER BY theDay) AS DayNum
FROM AllDays
WHERE DATEPART(dw, theDay) NOT IN (1,7)
AND IsPublicHoliday = 0
AND theDay > @StartDate
)
SELECT theDay
FROM NumberedDays
WHERE DayNum = @n
;

如果你没有名为AllDays的表,那么你可以轻松使用数字表,其中theDay是DATEADD(day,num,@ StartDate)。您可以在不合格的日期列表中进行LEFT JOIN(当然应该编入索引)。

答案 3 :(得分:0)

@Stuart:是的,50天是一个类型= P.我的意思是50年。

@rexem: 确实如此。计算过于复杂且容易出错。

@David:创建一个只选的主日历表,然后复制每个项目所需的日期听起来是个好主意。

(原谅,我的推特般的回应,哈哈)

感谢您的回复!

答案 4 :(得分:0)

嗨,这是我解决它的问题:

首先我创建了一个日历表(tb_cal),其中包含两个字段date_day(smalldate),holiday(bit)

CREATE TABLE [user].[tb_cal](
[date_day] [smalldatetime] NULL,
[holiday] [bit] NULL
) ON [PRIMARY]

然后这个功能:

CREATE FUNCTION [user].[fc_get_labor_days]
(@from datetime, @to datetime)
RETURNS int
AS
BEGIN
return ( 
select count(*) as total 
from tb_cal 
where datepart(dw, date_day) not in (1,7)   
and holiday <> 1 
and date_day > @from and date_day <= @to )
END 

您可以通过传递参数(from,to)

来调用此函数
SELECT user.fc_get_labor_days(my_date_from, my_date_to) as [days]

希望这有帮助

答案 5 :(得分:0)

在排除周末和假期后,使用以下代码获取下一个工作日期

Declare @AddDay as integer = 3
Declare @NextWorkingDate  DateTime
Declare @StartDate  DateTime = Cast(getdate() as date)

While  @AddDay > 0 
    begin

        Select @NextWorkingDate =  @StartDate + @AddDay +
        (datediff(wk, @StartDate, @StartDate+ @AddDay  ) * 2) -- add weekend 

        --Exclude weekend
        If datepart(dw,@NextWorkingDate ) = 1 or datepart(dw,@NextWorkingDate ) = 7  --Add 2 days if target date is either Saturday or Sunday
            set @NextWorkingDate = @NextWorkingDate + 2 

        --Count no of holidays if falling within start date and nextwrking date
        Select @AddDay = Count(*)  from HolidayTable ST --Holiday list
                    where ST.OffDate between @StartDate+1 and @NextWorkingDate
        Set @StartDate = @NextWorkingDate
    End         

Select @NextWorkingDate