到期日计算给定的开始日期和工作/午餐时间PL / SQL

时间:2015-04-10 17:11:44

标签: oracle plsql

我需要一些PL / SQL帮助。我正在尝试计算给定任务的截止日期,因为最长时间是8个工作小时,而下午12点到晚上12点的午餐不包括在这个时间内。 例如,如果任务在早上8点进入,则应在下午5点到期。如果任务在上午11点进入,则应在第二天上午11点到期。我认为这相当容易,但我是PL / SQL的新手,刚刚开始。我的思维过程是使用sysdate,但这不会起作用。如果没有发布代码,请提供帮助和道歉,但我没有任何有用的信息。

2 个答案:

答案 0 :(得分:2)

搞清楚这一点,以下应该是一个很好的起点,请你认为合适。

它需要一个开始日期和工作小时数,并返回截止日期。请注意,它会舍入到最近的小时(因此,如果开始日期/时间是今天下午3:45,那么它将使用下午4点作为实际开始日期/时间):

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

答案 1 :(得分:0)

您可以使用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