如何在 oracle 10g 中计算两个日期之间的营业时间或天数?
例如我们有两个日期;14/08/2012 9:30 和 16/08/2012 12:00 我们工作日的工作时间为 09:30 至 18:30。
如何使用 oracle 10g 计算不包括国定假日、周六和周日的工作时间或天数?
你不能。就这么简单。世界各地的国定假日各不相同,每年都有所不同,并且可以随时增加或取消额外的假期。此外,一些司法管辖区会将周末的国定假日延续到下周;其他人没有。
您需要在此创建一个日历表并标记国定假日/周末等。
例如
create table calender
( day date
, weekend varchar2(1)
, holiday varchar2(1)
);
然后在其中插入一些数据...
insert into calender (day, weekend)
select trunc(sysdate + level)
, case when to_date(sysdate + level,'fmDAY') in ('SATURDAY','SUNDAY')
then 'Y' else 'N' end
from dual
connect by level <= 365
最后,手动更新您认为是国定假日的内容。
然后,您可以选择工作日,具体取决于您使用以下内容填充它的方式:
select count(*)
from calender
where day between :startdate and :enddate
and weekend = 'N'
and holiday = 'N'
在表格中找到了计算除周末和节假日之外的营业时间的解决方案。
https://forums.oracle.com/forums/thread.jspa?messageID=9322860
create or replace
FUNCTION business_hours(
in_start_dt IN DATE DEFAULT SYSDATE ,
in_end_dt IN DATE DEFAULT SYSDATE )
RETURN NUMBER DETERMINISTIC
IS
-- business_hours returns the number of work hours (9.30 am through 6.30 pm,
-- Monday through Friday) between in_start_dt and in_end_dt.
-- If in_start_dt > in_end_dt, the results will be <= 0.
d NUMBER; -- Hours of either start_dt or end_dt after midnight
end_dt DATE := GREATEST (in_start_dt, in_end_dt); -- In case dates were in wrong order
return_val NUMBER; -- Total number of working hours
start_dt DATE := LEAST (in_start_dt, in_end_dt); -- In case dates were in wrong order
BEGIN
WITH all_days AS
(SELECT TRUNC(start_dt) + LEVEL - 1 AS a_dt
FROM dual
CONNECT BY LEVEL <= 1 + TRUNC (end_dt) - TRUNC (start_dt)
MINUS
SELECT hol_dt FROM holiday
)
SELECT SUM (9)
INTO return_val
FROM all_days
WHERE TO_CHAR ( a_dt , 'Dy' , 'NLS_DATE_LANGUAGE = ''ENGLISH''' ) NOT IN ('Sat', 'Sun');
-- Adjust hours from start_dt, if necessary
IF TO_CHAR ( start_dt , 'Dy' , 'NLS_DATE_LANGUAGE = ''ENGLISH''' ) NOT IN ('Sat', 'Sun') THEN
d := 24 * (start_dt - TRUNC (start_dt));
IF d >= 18.5 THEN -- Don't count start_dt itself
return_val := return_val - 9;
ELSIF d > 9.5 THEN -- Don't count part of start_dt
return_val := return_val - (d - 9.5);
END IF;
END IF;
-- Adjust hours from end_dt, if necessary
IF TO_CHAR ( end_dt , 'Dy' , 'NLS_DATE_LANGUAGE = ''ENGLISH''' ) NOT IN ('Sat', 'Sun') THEN
d := 24 * (end_dt - TRUNC (end_dt));
IF d <= 9.5 THEN -- Don't count end_dt itself
return_val := return_val - 9;
ELSIF d < 18.5 THEN -- Don't count part of end_dt
return_val := return_val - (18.5 - d);
END IF;
END IF;
IF in_start_dt > in_end_dt THEN
return_val := -return_val;
END IF;
RETURN return_val;
END business_hours ;
我只是做了类似的事情。这是一个 sql 代码段,用于计算表 T 中员工在 stime 和 etime 之间完成的工作
create table t ( NAME varchar(50), stime date, etime date, clockin number,clockout number );
insert into t values ( 'JOHN', to_date( '18/12/2003 11:40','dd/mm/yyyy hh24:mi'), to_date( '22/12/2003 14:00', 'dd/mm/yyyy hh24:mi'),8, 17 );
insert into t values ( 'JOHN', to_date( '19/12/2003 13:40','dd/mm/yyyy hh24:mi'), to_date( '21/12/2003 15:00', 'dd/mm/yyyy hh24:mi'),8, 17 );
insert into t values ( 'TOM', to_date( '19/12/2003 13:40','dd/mm/yyyy hh24:mi'), to_date( '21/12/2003 15:00', 'dd/mm/yyyy hh24:mi'),8, 17 );
with oo as (SELECT LEVEL-1 rn FROM dual CONNECT BY LEVEL <= 365) --JUST A TABLE WITH INTEGER RECORDS FROM 1 To 365
select
t.NAME ,sum(least( trunc(stime)+18.5/24+rn, etime )-greatest( stime, trunc(stime)+9.5/24+rn))*24 as WorkHours -- Get workhours between 09:30-18:30
from oo
inner join t on oo.rn < (trunc(etime)-trunc(stime)+1)
and to_char(stime+rn,'Dy') not in ( 'Sat', 'Sun' ) --For eliminating Weekends
and to_char(trunc(stime)+rn,'DD.MM') != '04.07' -- For eliminating Holidays
group by t.NAME
您可以逐行删除组并删除 sum 函数,以通过为每一天生成行来查看它是如何工作的。