现有数据库一表分配时间 实际工时 完成时间
2009-12-15 09:00:00 2 2009-12-15 16:00:00现在要利用 分配时间 和 预计工时 算出 任务是否提前完成 即 是否小于完成时间
有张表记录节假日情况日期 描述 是否休假
2010-01-01 元旦 是另外公司是8:00 --- 17:00 上班 午休12:00-13:00 周六日休息也就是说 如果下午5点分配的工作,预计工时3小时, 如果是正常工作日 完成时间在第二天11点前,
都算提前完成工作现在求一函数
function GetPlanTiem(分配时间,预计工时)
{
考虑节假日,
遇到节假日和下班,时间顺延,Return 计划完成时间
}博客园有人提出个方案 http://space.cnblogs.com/question/11091/
但感觉不完善,请高人登场
2009-12-15 09:00:00 2 2009-12-15 16:00:00现在要利用 分配时间 和 预计工时 算出 任务是否提前完成 即 是否小于完成时间
有张表记录节假日情况日期 描述 是否休假
2010-01-01 元旦 是另外公司是8:00 --- 17:00 上班 午休12:00-13:00 周六日休息也就是说 如果下午5点分配的工作,预计工时3小时, 如果是正常工作日 完成时间在第二天11点前,
都算提前完成工作现在求一函数
function GetPlanTiem(分配时间,预计工时)
{
考虑节假日,
遇到节假日和下班,时间顺延,Return 计划完成时间
}博客园有人提出个方案 http://space.cnblogs.com/question/11091/
但感觉不完善,请高人登场
工作日处理函数(标准节假日)
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDay]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDay]
GO--计算两个日期相差的工作天数
CREATE FUNCTION f_WorkDay(
@dt_begin datetime, --计算的开始日期
@dt_end datetime --计算的结束日期
)RETURNS int
AS
BEGIN
DECLARE @workday int,@i int,@bz bit,@dt datetime
IF @dt_begin>@dt_end
SELECT @bz=1,@dt=@dt_begin,@dt_begin=@dt_end,@dt_end=@dt
ELSE
SET @bz=0
SELECT @i=DATEDIFF(Day,@dt_begin,@dt_end)+1,
@workday=@i/7*5,
@dt_begin=DATEADD(Day,@i/7*7,@dt_begin)
WHILE @dt_begin<=@dt_end
BEGIN
SELECT @workday=CASE
WHEN (@@DATEFIRST+DATEPART(Weekday,@dt_begin)-1)%7 BETWEEN 1 AND 5
THEN @workday+1 ELSE @workday END,
@dt_begin=@dt_begin+1
END
RETURN(CASE WHEN @bz=1 THEN -@workday ELSE @workday END)
END
GO/*=================================================================*/if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDayADD]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDayADD]
GO--在指定日期上,增加指定工作天数后的日期
CREATE FUNCTION f_WorkDayADD(
@date datetime, --基础日期
@workday int --要增加的工作日数
)RETURNS datetime
AS
BEGIN
DECLARE @bz int
--增加整周的天数
SELECT @bz=CASE WHEN @workday<0 THEN -1 ELSE 1 END
,@date=DATEADD(Week,@workday/5,@date)
,@workday=@workday%5
--增加不是整周的工作天数
WHILE @workday<>0
SELECT @date=DATEADD(Day,@bz,@date),
@workday=CASE WHEN (@@DATEFIRST+DATEPART(Weekday,@date)-1)%7 BETWEEN 1 AND 5
THEN @workday-@bz ELSE @workday END
--避免处理后的日期停留在非工作日上
WHILE (@@DATEFIRST+DATEPART(Weekday,@date)-1)%7 in(0,6)
SET @date=DATEADD(Day,@bz,@date)
RETURN(@date)
END工作日处理函数(自定义节假日)
if exists (select * from dbo.sysobjects where id = object_id(N'[tb_Holiday]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [tb_Holiday]
GO--定义节假日表
CREATE TABLE tb_Holiday(
HDate smalldatetime primary key clustered, --节假日期
Name nvarchar(50) not null) --假日名称
GOif exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDay]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDay]
GO--计算两个日期之间的工作天数
CREATE FUNCTION f_WorkDay(
@dt_begin datetime, --计算的开始日期
@dt_end datetime --计算的结束日期
)RETURNS int
AS
BEGIN
IF @dt_begin>@dt_end
RETURN(DATEDIFF(Day,@dt_begin,@dt_end)
+1-(
SELECT COUNT(*) FROM tb_Holiday
WHERE HDate BETWEEN @dt_begin AND @dt_end))
RETURN(-(DATEDIFF(Day,@dt_end,@dt_begin)
+1-(
SELECT COUNT(*) FROM tb_Holiday
WHERE HDate BETWEEN @dt_end AND @dt_begin)))
END
GOif exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_WorkDayADD]') and xtype in (N'FN', N'IF', N'TF'))
drop function [dbo].[f_WorkDayADD]
GO--在指定日期上增加工作天数
CREATE FUNCTION f_WorkDayADD(
@date datetime, --基础日期
@workday int --要增加的工作日数
)RETURNS datetime
AS
BEGIN
IF @workday>0
WHILE @workday>0
SELECT @date=@date+@workday,@workday=count(*)
FROM tb_Holiday
WHERE HDate BETWEEN @date AND @date+@workday
ELSE
WHILE @workday<0
SELECT @date=@date+@workday,@workday=-count(*)
FROM tb_Holiday
WHERE HDate BETWEEN @date AND @date+@workday
RETURN(@date)
END
如果你还要考虑时间,就有点麻烦了.
--还有几个情况得考虑
--> 测试数据:[vacation]
--假日表
if object_id('[vacation]') is not null drop table [vacation]
create table [vacation]([日期] varchar(10),[描述] varchar(4),[是否休假] varchar(2))
insert [vacation]
select '2010-01-01','元旦','是'--select * from [vacation]declare @AllocationTime datetime,-- 分配时间
@hour int--预计工时select @AllocationTime = '2009-12-15 09:00:00',@hour = 50declare @day int,--天数
@weekend int, --周末天数
@vacationday int --法定假日天数select @day = ceiling(@hour*1.0/8)declare @PlanTime datetime --计划完成时间select
datepart(weekday,dateadd(day,number,@AllocationTime)) as [type],
convert(varchar(10),dateadd(day,number,@AllocationTime),120) as [date]
into #temp
from master..spt_values
where type = 'P' and number<@day
--周末天数
select @weekend = count(1) from #temp where [type] in (1,7)
--假日天数
select @vacationday = count(1) from #temp
where [date] in (select [日期] from [vacation] where [是否休假] = '是')
--实际天数
select @day = @day + @weekend + @vacationdayselect @PlanTime = dateadd(day,@day-1,@AllocationTime)
--剩余小时数
select @hour = @day%8select @PlanTime = dateadd(hour,@hour,@PlanTime)select @PlanTimedrop table #temp
-----------------
2009-12-23 10:00:00.000
IF OBJECT_ID('t1') IS NOT NULL
DROP TABLE t1
GO
--节日表
IF OBJECT_ID('t2') IS NOT NULL
DROP TABLE t2
GO
--8:00 --- 17:00 上班 午休12:00-13:00 周六日休息 CREATE TABLE t1(id iNT IDENTITY,d1 DATETIME, span INT , d2 DATETIME)
GO
INSERT t1 SELECT '2009-12-15 09:00:00',2,'2009-12-15 16:00:00'
UNION ALL SELECT '2009-09-30 15:00:00',7,'2009-10-14 09:00:00'
GO
CREATE TABLE t2(d DATETIME,s VARCHAR(20))
GO
INSERT t2 SELECT '2009-10-01','国庆'
INSERT t2 SELECT '2009-10-02','国庆'
INSERT t2 SELECT '2009-10-03','国庆'
INSERT t2 SELECT '2009-01-01','元旦'
GOSELECT id,d1,d2,
CASE WHEN span <
--发布任务起至下班所余工作小时 a
DATEDIFF(hh,d1,DATEADD(dd,1,CONVERT(VARCHAR(10),d1,120))) - CASE WHEN DATEPART(hh,d1)<12 THEN 8 ELSE 7 END
+
--上班至结束任务前使用工作小时 b
DATEPART(hh,d2) - CASE WHEN DATEPART(hh,d2)>=12 THEN 9 ELSE 8 END
+
8 *
(
--d2,d1之天数差
CASE WHEN DATEDIFF(dd,d1,d2) - 1 <0 THEN 0 ELSE DATEDIFF(dd,d1,d2)-1 END
-
(
--d2,d1间周末的天数
((DATEDIFF(dd,d1,DATEADD(dd,-(DATEPART(dw,d2)-1) + 1,d2)) + 5 )/7 ) * 2
+
--d2,d1间节日的天数
COUNT(d)
-
--可能节日与周末有重合,则去掉重复计算的部分
SUM(CASE WHEN DATEPART(dw,d) IN (1,7) THEN 1 ELSE 0 END)
)
) --*8得到d1,d2间间隔天数的工作小时 c, 则 a+b+c为使用之总小时数
THEN '超时'
ELSE '正常'
END FROM t1 a
LEFT JOIN t2 b
ON d BETWEEN d1 AND d2
GROUP BY id,d1,d2,span
if object_id('[vacation]') is not null drop table [vacation]
create table [vacation]([日期] varchar(10),[描述] varchar(4),[是否休假] varchar(2))
insert [vacation]
select '2010-01-01','元旦','是'--select * from [vacation]declare @AllocationTime datetime,-- 分配时间
@hour int--预计工时select @AllocationTime = '2009-12-15 13:00:00',@hour = 7declare @day int,--天数
@weekend int, --周末天数
@vacationday int --法定假日天数select @day = ceiling(@hour*1.0/8)declare @PlanTime datetime --计划完成时间select
datepart(weekday,dateadd(day,number,@AllocationTime)) as [type],
convert(varchar(10),dateadd(day,number,@AllocationTime),120) as [date]
into #temp
from master..spt_values
where type = 'P' and number<@day--周末天数
select @weekend = count(1) from #temp where [type] in (1,7)
--假日天数
select @vacationday = count(1) from #temp
where [date] in (select [日期] from [vacation] where [是否休假] = '是')
and [type] not in (1,7)--实际天数
select @day = @day + @weekend + @vacationdayselect @PlanTime = dateadd(day,@day-1,@AllocationTime)
--剩余小时数
select @hour = case when @hour <= 8 then @hour else @hour%8 endselect @PlanTime = dateadd(hour,@hour,@PlanTime)select @PlanTime = case when convert(varchar(2),@AllocationTime,108)<='12'
and convert(varchar(2),@AllocationTime,108)>='13'
then dateadd(hour,1,@PlanTime) else @PlanTime end
select @PlanTime = case when convert(varchar(2),@PlanTime,108)>'17'
then dateadd(hour,cast(convert(varchar(2),@PlanTime,108) as int) + 8 - 17,
dateadd(day,1,convert(varchar(10),@PlanTime)))
else @PlanTime endselect @PlanTimedrop table #temp