On heavily loaded database with lot of jobs scheduled, sometimes we need to time jobs to run at exactly specific intervals in a day. Examples 1. Running a job at every 30 minutes, and timing exactly at 00:10, 00:40, 1:10, 1:40... 2. Running a job at every 6 hours, and timing exactly at 3:00, 9:00, 15:00 ...
Even if a specific instance of job runs at an random time, the next run should fall into timed schedule. It means, for a job that runs at every 6 hours starting with 3:00 (3:00, 9:00, 15:00..), if it's run at 4:30, next run should be at scheduled time 9:00 (not at 4:30+6 i.e 10:30).
Here is how we can derive interval property of a job to get next scheduled date and time.
date_time_of_next_scheduled_run = today_date + time_of_next_scheduled_run time_of_next_scheduled_run = time_of_last_scheduled_run + interval_between_runs time_of_last_scheduled_run = time_of_first_scheduled_run + (number_of_times_run_completed_today * interval_between_runs) number_of_times_run_completed_today = floor((present_time_of_day - time_of_first_scheduled_run)/interval_between_runs)
By substituting all the above, we can get an expression for interval
date_time_of_next_scheduled_run = today_date + time_of_first_scheduled_run + floor( (present_time_of_day - time_of_first_scheduled_run) /interval_between_runs ) * interval_between_runs + interval_between_runs
For example, a schedule for every 30 minutes, and timing at 00:10, 00:40, 1:10, 1:40...,
today_date = trunc(sysdate) time_of_first_scheduled_run (in seconds) = 00:10 = 10*60 interval_between_runs (in seconds) = 30*60 present_time_of_day (in seconds) = to_char(d,'SSSSS') date_time_of_next_scheduled_run = trunc(sysdate) + ( 10*60 + floor( (to_char(d,'SSSSS')-(10*60)) /(30*60) ) *(30*60) + (30*60) )/(24*60*60)We can test if this working by sample PL/SQL program which prints next scheduled time for every minute.
declare d date; begin for i in 0 .. 150 loop d := to_date('2014-05-15 00:00', 'YYYY-MM-DD HH24:MI') + i/(24*60); dbms_output.put(to_char(d, 'YYYY-MM-DD HH24:MI') || ' - '); dbms_output.put_line( to_char( trunc(d) + ( 10*60 + floor( (to_char(d,'SSSSS')-(10*60)) /(30*60) ) *(30*60) + (30*60) )/(24*60*60) , 'YYYY-MM-DD HH24:MI')); end loop; end; / 2014-05-15 00:00 - 2014-05-15 00:10 2014-05-15 00:01 - 2014-05-15 00:10 ... 2014-05-15 00:09 - 2014-05-15 00:10 2014-05-15 00:10 - 2014-05-15 00:40 2014-05-15 00:11 - 2014-05-15 00:40 ... 2014-05-15 00:39 - 2014-05-15 00:40 2014-05-15 00:40 - 2014-05-15 01:10 2014-05-15 00:41 - 2014-05-15 01:10 ... 2014-05-15 01:09 - 2014-05-15 01:10 2014-05-15 01:10 - 2014-05-15 01:40 2014-05-15 01:11 - 2014-05-15 01:40 ...
Other examples of interval expression
Schedule for every 6 hours starting with 3:00 (3:00, 9:00, 15:00..)
trunc(sysdate) + ( 3*60*60 + floor( (to_char(sysdate,'SSSSS')-(3*60*60)) /(6*60*60) ) *(6*60*60) + (6*60*60) )/(24*60*60)
Schedule for every 1 hour starting with 0:00 (0:00, 1:00, 2:00, 3:00..)
trunc(sysdate) + ( floor( (to_char(sysdate,'SSSSS')) /(1*60*60) ) *(1*60*60) + (1*60*60) )/(24*60*60)