【问题标题】:How to get business days or hours between two dates如何获取两个日期之间的工作日或小时数
【发布时间】:2012-08-14 13:17:42
【问题描述】:

如何在 oracle 10g 中计算两个日期之间的营业时间或天数?

例如我们有两个日期; 14/08/2012 9:30 和 16/08/2012 12:00 我们工作日的工作时间是 09:30 到 18:30。

如何使用 oracle 10g 计算不包括国定假日、周六和周日的工作时间或天数?

【问题讨论】:

    标签: oracle oracle10g


    【解决方案1】:

    你不能。就这么简单。世界各地的国定假日各不相同,每年都有所不同,并且可以随时增加或取消额外的假期。此外,一些司法管辖区会将周末的国定假日延续到下周;其他人没有。

    您需要在此创建一个日历表并标记国定假日/周末等。

    例如

    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'
    

    【讨论】:

    • 此外,对于银行等特殊企业,工作日的定义可能不同。例如在德国,Christmas EveNew Year's Eve 不是国家法定假日,而是国家银行假日。
    • 嗨,Ben 我尝试了您的选择,但我卡在插入数据中,它给了我 ORA-01846 错误
    • 我使用 to_char 而不是 to_Date,然后我能够将数据插入到日历表中。但是如何计算工作时间?
    • @leelavinodh,听起来您没有创建带有日期的表格。我强烈建议使用日期而不是字符来存储日期。要查找工作小时数,只需在最终查询中将count(*) 更改为count(*) * 8;或者如果你不每天工作 8 小时,不管你做什么。
    【解决方案2】:

    在表格中找到了计算除周末和节假日之外的营业时间的解决方案。

    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 ;
    

    【讨论】:

      【解决方案3】:

      我刚刚做了类似的事情。这是一个 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 函数,以通过为每一天生成行来查看其工作原理。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-07
        • 2014-07-13
        相关资源
        最近更新 更多