V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
nutting
V2EX  ›  编程

oracle 计算时间差,排除非工作时间

  •  
  •   nutting · 2018-06-01 19:29:39 +08:00 · 2624 次点击
    这是一个创建于 2148 天前的主题,其中的信息可能已经有所发展或是发生改变。

    要求只计算 8-12,14-18,我现在 csdn 找见有人探讨写的算法,结果仔细一侧,有些临界的地方就算不对了,比如 17:50 到第二天 8:10,算出来不是 20 分钟,好复杂啊,就只用 oracle 的话到底怎么能写对?

    create or replace function wk_minutes_between(
        i_startTime varchar2, -- 起始时间:( 格式:'YYYY-MM-DD HH24:MI:SS' )
      i_endTime varchar2    -- 结束时间:( 格式:'YYYY-MM-DD HH24:MI:SS' )
    )
    return number
    is
      v_real_startTime date;
      v_real_endTime date;
      v_hours number(18,0);
      v_number number(18,4);
    begin
      v_real_startTime := to_date(i_startTime,'YYYY-MM-DD HH24:MI:SS');
      v_real_endTime := to_date(i_endTime,'YYYY-MM-DD HH24:MI:SS');
     
      if v_real_startTime > v_real_endTime -- 如果起始时间大于结束时间,将起始时间与结束时间替换
      then
        select v_real_startTime, v_real_endTime into v_real_endTime, v_real_startTime from dual;
      end if;
     
      if v_real_startTime > v_real_endTime -- 如果起始时间大于结束时间,将起始时间与结束时间替换
      then
        select v_real_startTime, v_real_endTime into v_real_endTime, v_real_startTime from dual;
      end if;
     
      if v_real_startTime<trunc(v_real_startTime,'dd')+8/24 -- 如果小于当天 8 点,将其置为当天 8 天(因为你是 8 点上班)
      then
        v_real_startTime:=trunc(v_real_startTime,'dd')+8/24;
      -- 如果大于当天 12 点,且小于当天 14 点,将其置为当天 14 点(因为你下午是 14 点上班)
      elsif v_real_startTime>trunc(v_real_startTime,'dd')+12/24 and v_real_startTime<trunc(v_real_startTime,'dd')+14/24
      then
        v_real_startTime:=trunc(v_real_startTime,'dd')+14/24;
      -- 如果大于当天 18 点,将其置为第二天 8 天
      elsif v_real_startTime>trunc(v_real_startTime,'dd')+18/24
      then
        v_real_startTime:=trunc(v_real_startTime+1,'dd')+8/24;
      end if;
     
      -- 如果小于当天 8 点,将其置为昨天 18 点
      if v_real_endTime<trunc(v_real_endTime,'dd')+8/24
      then
        v_real_endTime:=trunc(v_real_endTime-1,'dd')+18/24;
      -- 如果大于当天 12 点,且小于当天 14 点,将其置为当天 12 点(因为你上午是 12 点下班)
      elsif v_real_endTime>trunc(v_real_endTime,'dd')+12/24 and v_real_endTime<trunc(v_real_endTime,'dd')+14/24
      then
        v_real_endTime:=trunc(v_real_endTime,'dd')+12/24;
      elsif v_real_endTime>trunc(v_real_endTime,'dd')+18/24 -- 如果大于当天 18 点,将其置为当天 18 天(因为你是 18 点下班)
      then
        v_real_endTime:=trunc(v_real_endTime,'dd')+18/24;
      end if;
     
      with a as( select v_real_startTime+(level-1)/24 as cdate, 
                        trunc(v_real_startTime+(level-1)/24,'hh') as tr_cdate
                   from dual
                connect by level <= (v_real_endTime-v_real_startTime)*24+2 ),
           b as( select cdate, tr_cdate cdate2 from a /*where trunc(a.cdate) not in (select hdate from holidays) and to_char(a.cdate,'D') not in ('1','7')*/ ), -- 排除周六、日 和 节假日
           c as( select (case when to_char(t1.cdate,'hh24') in ('12','18') then trunc(t1.cdate,'hh') else t1.cdate end) as cdate1, 
                        (case when to_char(t2.cdate,'hh24') in ('14') then trunc(t2.cdate,'hh') else t2.cdate end) as cdate2
                 from b t1
                 left join b t2 on trunc(t1.cdate,'hh24')=trunc(t2.cdate+1/24,'hh24')
                order by (case when to_char(t1.cdate,'hh') in ('08','12','14','18') then trunc(t1.cdate,'hh') else t1.cdate end) ),
           d as ( select (case when c.cdate1>v_real_endTime then v_real_endTime
                               else c.cdate1 end) as cdate1,
                          c.cdate2
                    from c
                   where to_char(c.cdate1,'hh24') in ('09','10','11','12','15','16','17','18') )
          select sum(d.cdate1-nvl(d.cdate2,d.cdate1))*24 into v_number from d;
     
      return v_number;    
    end;
    
    
    测试:
    --这样算,480 分钟,正好是 8 个小时,说明算法基本没问题
    select   wk_minutes_between('2018-05-21 07:50:00','2018-05-21 18:10:00')*60 from dual;
    
    --下面这个就不对了,只算出来是 10 分钟
    select   wk_minutes_between('2018-05-21 17:50:00','2018-05-22 08:10:00')*60 from dual;
    
    1 条回复    2018-06-02 08:50:33 +08:00
    nutting
        1
    nutting  
    OP
       2018-06-02 08:50:33 +08:00
    没人感兴趣?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2970 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 15:04 · PVG 23:04 · LAX 08:04 · JFK 11:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.