根据给定的开始日期和 Working/Lunch 小时 PL/SQL 计算的截止日期

Due Date Calculated Given Start Date and Working/Lunch Hours PL/SQL

我需要一些 PL/SQL 帮助。我正在尝试计算给定任务的截止日期,因为最长时间为 8 个工作小时,并且这段时间不包括中午 12 点至下午 1 点的午餐。 例如,如果任务在上午 8 点到达,则应在下午 5 点截止。如果任务在上午 11 点到达,则在第二天上午 11 点到期。我认为这会相当容易,但我是 PL/SQL 的新手并且才刚刚开始。我的想法是使用 sysdate,但这行不通。请帮助并为没有发布代码而道歉,但我没有任何帮助。

搞砸了,下面的内容对你来说应该是一个很好的起点,请按你认为合适的方式进行调整。

需要开始日期和工作时数,returns 需要截止日期。请注意,它四舍五入到最接近的小时(因此,如果开始 date/time 是今天 3:45pm,则它使用下午 4 点作为实际开始 date/time):

create or replace function get_due_date(i_start_date in date default sysdate, i_hours in number default 8)
return date
as
    l_dte date;
    l_hours number;
begin

    if (i_hours < 1 OR i_hours > 24) then
        raise_application_error(-20001, 'Hours must be between 1 and 24');
    end if;

    l_hours := i_hours + 1;

    select dte 
    into l_dte
    from 
    (
        select dte, to_char(dte, 'HH24') hr, levl, row_number() over(order by levl) rnum
        from (
            -- rounding to nearest hour
            select round(i_start_date, 'HH24') + ((level-1)/24) as dte, level levl
            from dual
            connect by level <= 72
        )
        where to_char(dte, 'HH24') between '08' and '17'
        -- skip lunch hour
        and NOT(to_char(dte, 'HH24') = '12')
    ) x
    where rnum = l_hours;

    return l_dte;

end;

例如:

select sysdate, get_due_date(sysdate, 8) from dual;

输出:

4/10/2015 3:45:21 PM    4/11/2015 3:00:00 PM

您可以使用 Oracle SCHEDULER SCHEDULE。默认情况下,它用于 SCHEDULER JOBS,但是我看不出有任何理由不将它用于其他目的。

应该是这个:

CREATE OR REPLACE FUNCTION GetDueDate(start_date IN TIMESTAMP DEFAULT SYSTIMESTAMP, duration IN INTEGER DEFAULT 8) RETURN TIMESTAMP AS
    next_run_date TIMESTAMP := start_date;
BEGIN
    FOR i IN 1..duration LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=HOURLY;INTERVAL=1;BYHOUR=7,8,9,10,11,13,14,15,16,17;BYDAY=MON,TUE,WED,THU,FRI', NULL, next_run_date, next_run_date);
    END LOOP;
    RETURN next_run_date;
END;

一些测试:

BEGIN
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-04-10 16:20:00'), 'Day yyyy-mm-dd hh24:mi') );
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-04-11 07:20:00'), 'Day yyyy-mm-dd hh24:mi') );
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-04-13 07:20:00'), 'Day yyyy-mm-dd hh24:mi') );
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-04-13 09:20:00'), 'Day yyyy-mm-dd hh24:mi') );
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-04-13 11:20:00'), 'Day yyyy-mm-dd hh24:mi') );
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-04-13 17:20:00'), 'Day yyyy-mm-dd hh24:mi') );
END;

Monday    2015-04-13 14:20
Monday    2015-04-13 15:20
Monday    2015-04-13 16:20
Tuesday   2015-04-14 07:20
Tuesday   2015-04-14 09:20
Tuesday   2015-04-14 15:20

你可以让它更复杂,并考虑假期,例如

BEGIN
    DBMS_SCHEDULER.CREATE_SCHEDULE('NEW_YEARS_DAY', repeat_interval => 'FREQ=YEARLY;INTERVAL=1;BYDATE=0101');
    DBMS_SCHEDULER.CREATE_SCHEDULE('MARTIN_LUTHER_KING_DAY', repeat_interval => 'FREQ=YEARLY;BYMONTH=JAN;BYDAY=3 FRI', comments => 'Third Monday of January');
    DBMS_SCHEDULER.CREATE_SCHEDULE('WASHINGTONS_BIRTHDAY', repeat_interval => 'FREQ=YEARLY;BYMONTH=FEB;BYDAY=3 MON', comments => 'Third Monday of February');
    DBMS_SCHEDULER.CREATE_SCHEDULE('MEMORIAL_DAY', repeat_interval => 'FREQ=YEARLY;BYMONTH=MAY;BYDAY=-1 MON', comments => 'Last Monday of May');
    DBMS_SCHEDULER.CREATE_SCHEDULE('INDEPENDENCE_DAY', repeat_interval => 'FREQ=YEARLY;INTERVAL=1;BYDATE=0704');
    DBMS_SCHEDULER.CREATE_SCHEDULE('CHRISTMAS_DAY', repeat_interval => 'FREQ=YEARLY;INTERVAL=1;BYDATE=1225');
    DBMS_SCHEDULER.CREATE_SCHEDULE('SPRING_BREAK', repeat_interval => 'FREQ=YEARLY;BYDATE=0301+SPAN:7D');
END;


CREATE OR REPLACE FUNCTION GetDueDate(start_date IN TIMESTAMP DEFAULT SYSTIMESTAMP, duration IN INTEGER DEFAULT 8) RETURN TIMESTAMP AS
    next_run_date TIMESTAMP := start_date;
BEGIN
    FOR i IN 1..duration LOOP
        DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING('FREQ=HOURLY;INTERVAL=1;BYHOUR=7,8,9,10,11,13,14,15,16,17;BYDAY=MON,TUE,WED,THU,FRI; EXCLUDE=NEW_YEARS_DAY,MARTIN_LUTHER_KING_DAY,WASHINGTONS_BIRTHDAY,MEMORIAL_DAY,INDEPENDENCE_DAY,CHRISTMAS_DAY,SPRING_BREAK', NULL, next_run_date, next_run_date);
    END LOOP;
    RETURN next_run_date;
END;

BEGIN
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-12-24 07:20:00'), 'Day yyyy-mm-dd hh24:mi') );
DBMS_OUTPUT.PUT_LINE ( TO_CHAR(GetDueDate(TIMESTAMP '2015-12-24 16:20:00'), 'Day yyyy-mm-dd hh24:mi') );
END;

Thursday  2015-12-24 16:20
Monday    2015-12-28 14:20

在此处查看日历语法:Calendaring Syntax