Close

Time Zones, Daylight Saving Time, and DBMS_SCHEDULER

As we approach the end of Daylight Saving Time in the United States for 2019, I thought it would be a good time to double check on some of the job schedules defined in the database.

If we have a job scheduled to run at 4pm every day, we don’t want it to become a 5pm Eastern Standard Time job in November because the schedule is still running in Eastern Daylight Time.

Using a fixed offset time zone produces a schedule with a fixed offset. Note the highlighted parameter value with time zone “-04:00”.

SQL> BEGIN
  2      DBMS_SCHEDULER.drop_job(job_name => 'SAMPLE_DST_JOB');
  3  END;
  4  /

PL/SQL procedure successfully completed.

SQL> BEGIN
  2      DBMS_SCHEDULER.create_job(
  3          job_name          => 'SAMPLE_DST_JOB',
  4          start_date        => TO_TIMESTAMP_TZ('2019-10-11 18:42:54 -04:00', 'yyyy-mm-dd hh24:mi:ss TZH:TZM'),
  5          repeat_interval   => 'FREQ=daily',
  6          job_type          => 'PLSQL_BLOCK',
  7          job_action        => 'begin null; end;');
  8  END;
  9  /

PL/SQL procedure successfully completed.

SQL> SELECT TO_CHAR(start_date, 'yyyy-mm-dd hh24:mi:ss tzh:tzm , tzr') start_date,
  2         repeat_interval
  3    FROM user_scheduler_jobs
  4   WHERE job_name = 'SAMPLE_DST_JOB';

START_DATE                            REPEAT_INTERVAL
------------------------------------  --------------------
2019-10-11 18:42:54 -04:00 , -04:00   FREQ=daily

SQL> DECLARE
  2      v_calendar     user_scheduler_jobs.repeat_interval%TYPE;
  3      v_start        user_scheduler_jobs.start_date%TYPE;
  4      v_after_this   TIMESTAMP WITH TIME ZONE;
  5      v_next         TIMESTAMP WITH TIME ZONE;
  6  BEGIN
  7      SELECT start_date, repeat_interval
  8        INTO v_start, v_calendar
  9        FROM user_scheduler_jobs
 10       WHERE job_name = 'SAMPLE_DST_JOB';
 11
 12      DBMS_OUTPUT.put_line(TO_CHAR(v_start, 'yyyy-mm-dd hh24:mi:ss tzh:tzm , tzr'));
 13
 14      v_after_this := v_start;
 15
 16      --- Generate 30 days of start times
 17      FOR i IN 1 .. 30
 18      LOOP
 19          DBMS_SCHEDULER.evaluate_calendar_string(calendar_string     => v_calendar,
 20                                                  start_date          => v_start,
 21                                                  return_date_after   => v_after_this,
 22                                                  next_run_date       => v_next);
 23
 24          DBMS_OUTPUT.put_line(TO_CHAR(v_next, 'yyyy-mm-dd hh24:mi:ss tzh:tzm , tzr'));
 25          v_after_this := v_next;
 26      END LOOP;
 27  END;
 28  /
2019-10-11 18:42:54 -04:00 , -04:00
2019-10-12 18:42:54 -04:00 , -04:00
2019-10-13 18:42:54 -04:00 , -04:00
2019-10-14 18:42:54 -04:00 , -04:00
2019-10-15 18:42:54 -04:00 , -04:00
2019-10-16 18:42:54 -04:00 , -04:00
2019-10-17 18:42:54 -04:00 , -04:00
2019-10-18 18:42:54 -04:00 , -04:00
2019-10-19 18:42:54 -04:00 , -04:00
2019-10-20 18:42:54 -04:00 , -04:00
2019-10-21 18:42:54 -04:00 , -04:00
2019-10-22 18:42:54 -04:00 , -04:00
2019-10-23 18:42:54 -04:00 , -04:00
2019-10-24 18:42:54 -04:00 , -04:00
2019-10-25 18:42:54 -04:00 , -04:00
2019-10-26 18:42:54 -04:00 , -04:00
2019-10-27 18:42:54 -04:00 , -04:00
2019-10-28 18:42:54 -04:00 , -04:00
2019-10-29 18:42:54 -04:00 , -04:00
2019-10-30 18:42:54 -04:00 , -04:00
2019-10-31 18:42:54 -04:00 , -04:00
2019-11-01 18:42:54 -04:00 , -04:00
2019-11-02 18:42:54 -04:00 , -04:00
2019-11-03 18:42:54 -04:00 , -04:00
2019-11-04 18:42:54 -04:00 , -04:00
2019-11-05 18:42:54 -04:00 , -04:00
2019-11-06 18:42:54 -04:00 , -04:00
2019-11-07 18:42:54 -04:00 , -04:00
2019-11-08 18:42:54 -04:00 , -04:00
2019-11-09 18:42:54 -04:00 , -04:00
2019-11-10 18:42:54 -04:00 , -04:00

PL/SQL procedure successfully completed.

Note the time offset remains -04:00 from GMT/UTC even after the DST transition.

Using a named time zone that observes DST transistions will produce a schedule with a variable offset in the time zone, observing DST changes. Here the highlighted start_date value uses “US/Eastern”.

SQL> BEGIN
  2      DBMS_SCHEDULER.drop_job(job_name => 'SAMPLE_DST_JOB');
  3  END;
  4  /

PL/SQL procedure successfully completed.

SQL> BEGIN
  2      DBMS_SCHEDULER.create_job(
  3          job_name          => 'SAMPLE_DST_JOB',
  4          start_date        => TO_TIMESTAMP_TZ('2019-10-11 18:42:54 US/Eastern', 'yyyy-mm-dd hh24:mi:ss TZR'),
  5          repeat_interval   => 'FREQ=daily',
  6          job_type          => 'PLSQL_BLOCK',
  7          job_action        => 'begin null; end;');
  8  END;
  9  /

PL/SQL procedure successfully completed.

SQL> SELECT TO_CHAR(start_date, 'yyyy-mm-dd hh24:mi:ss tzh:tzm , tzr') start_date,
  2         repeat_interval
  3    FROM user_scheduler_jobs
  4   WHERE job_name = 'SAMPLE_DST_JOB';

START_DATE                                REPEAT_INTERVAL
----------------------------------------  --------------------
2019-10-11 18:42:54 -04:00 , US/Eastern   FREQ=daily

SQL> DECLARE
  2      v_calendar     user_scheduler_jobs.repeat_interval%TYPE;
  3      v_start        user_scheduler_jobs.start_date%TYPE;
  4      v_after_this   TIMESTAMP WITH TIME ZONE;
  5      v_next         TIMESTAMP WITH TIME ZONE;
  6  BEGIN
  7      SELECT start_date, repeat_interval
  8        INTO v_start, v_calendar
  9        FROM user_scheduler_jobs
 10       WHERE job_name = 'SAMPLE_DST_JOB';
 11
 12      DBMS_OUTPUT.put_line(TO_CHAR(v_start, 'yyyy-mm-dd hh24:mi:ss tzh:tzm , tzr'));
 13
 14      v_after_this := v_start;
 15
 16      --- Generate 30 days of start times
 17      FOR i IN 1 .. 30
 18      LOOP
 19          DBMS_SCHEDULER.evaluate_calendar_string(calendar_string     => v_calendar,
 20                                                  start_date          => v_start,
 21                                                  return_date_after   => v_after_this,
 22                                                  next_run_date       => v_next);
 23
 24          DBMS_OUTPUT.put_line(TO_CHAR(v_next, 'yyyy-mm-dd hh24:mi:ss tzh:tzm , tzr'));
 25          v_after_this := v_next;
 26      END LOOP;
 27  END;
 28  /
2019-10-11 18:42:54 -04:00 , US/Eastern
2019-10-12 18:42:54 -04:00 , US/Eastern
2019-10-13 18:42:54 -04:00 , US/Eastern
2019-10-14 18:42:54 -04:00 , US/Eastern
2019-10-15 18:42:54 -04:00 , US/Eastern
2019-10-16 18:42:54 -04:00 , US/Eastern
2019-10-17 18:42:54 -04:00 , US/Eastern
2019-10-18 18:42:54 -04:00 , US/Eastern
2019-10-19 18:42:54 -04:00 , US/Eastern
2019-10-20 18:42:54 -04:00 , US/Eastern
2019-10-21 18:42:54 -04:00 , US/Eastern
2019-10-22 18:42:54 -04:00 , US/Eastern
2019-10-23 18:42:54 -04:00 , US/Eastern
2019-10-24 18:42:54 -04:00 , US/Eastern
2019-10-25 18:42:54 -04:00 , US/Eastern
2019-10-26 18:42:54 -04:00 , US/Eastern
2019-10-27 18:42:54 -04:00 , US/Eastern
2019-10-28 18:42:54 -04:00 , US/Eastern
2019-10-29 18:42:54 -04:00 , US/Eastern
2019-10-30 18:42:54 -04:00 , US/Eastern
2019-10-31 18:42:54 -04:00 , US/Eastern
2019-11-01 18:42:54 -04:00 , US/Eastern
2019-11-02 18:42:54 -04:00 , US/Eastern
2019-11-03 18:42:54 -05:00 , US/Eastern
2019-11-04 18:42:54 -05:00 , US/Eastern
2019-11-05 18:42:54 -05:00 , US/Eastern
2019-11-06 18:42:54 -05:00 , US/Eastern
2019-11-07 18:42:54 -05:00 , US/Eastern
2019-11-08 18:42:54 -05:00 , US/Eastern
2019-11-09 18:42:54 -05:00 , US/Eastern
2019-11-10 18:42:54 -05:00 , US/Eastern

PL/SQL procedure successfully completed.

Here the schedule changed from -04:00 to -05:00 to go along with the transition from Daylight to Standard time.

There may be occasions to maintain a consistent schedule, and of course, if your job runs in an area that does not observe DST changes then you won’t want a changing schedule. For those that do though, it’s important to note the difference in schedule definitions.

In the examples above the START_DATE was defined within the job itself. The same time zone and daylight saving time observation applies if using a named schedule with the START_DATE defined there.

If your job already exists, you don’t need to drop and recreate it to change the time zone. You can set that attribute directly. Here I use FROM_TZ to help highlight the intention of setting the time zone.

BEGIN
    DBMS_SCHEDULER.set_attribute(
        name        => 'SAMPLE_DST_JOB',
        attribute   => 'START_DATE',
        VALUE       => FROM_TZ(TIMESTAMP '2019-10-11 18:42:54', 'US/Eastern')
    );
END;

1 thought on “Time Zones, Daylight Saving Time, and DBMS_SCHEDULER

  1. Steven Green pointed out “at time zone” syntax I left out of my examples.
    That is the “at time zone” modifier for timestamp with time zone values

    for example:

    systimestamp at time zone ‘US/Eastern’

Comments are closed.