如何安全地安排Oracle dbms_scheduler作业时区和DST

时间:2014-01-15 15:25:40

标签: oracle11g timezone dst job-scheduling dbms-scheduler

我正在尝试设置DBMS_SCHEDULER作业,以便在每年1月1日凌晨1点在Oracle 11g上运行。如何设置其属性以确保它不会在错误的时间执行,因为时区差异或夏令时。

我花了很多时间浏览Oracle文档,但我还没有达到确定性水平。

顺便说一句,以下是我发现并考虑与该主题相关的规则:

工作属性

start_date 此属性指定计划启动此作业的第一个日期。如果start_date和repeat_interval保留为null,则作业将在计划启动后立即运行。 对于重复使用日历表达式指定重复间隔的作业,start_date用作参考日期。第一次安排作业运行是当前日期或之后的日历表达式的第一个匹配。 调度程序无法保证作业将在确切的时间内执行,因为系统可能过载,因此资源不可用。

repeat_interval 此属性指定作业重复的频率。您可以使用日历或PL / SQL表达式指定重复间隔。 评估指定的表达式以确定下次运行作业的时间。如果未指定repeat_interval,则作业将仅在指定的开始日期运行一次。有关详细信息,请参阅“日历语法”。

日历语法中的规则

  • 日历语法不允许您指定时区。 而是调度程序从start_date检索时区 论点。如果工作必须遵循夏令时调整,您必须 确保为时区指定区域名称 开始日期。例如,将start_date时区指定为 纽约的“美国/东方”将确保夏令时 自动应用调整。如果是时区 start_date设置为绝对偏移量,例如'-5:00', 不遵循夏令时调整和您的工作执行 将在一年半的时间里休息。
  • 当start_date为NULL时,调度程序将确定重复间隔的时区,如下所示:
  • 它将检查会话时区是否为区域名称。会话时区可以通过以下任一方式设置: 发出ALTER SESSION语句,例如:SQL>改变会话 SET time_zone ='亚洲/上海';设置ORA_SDTZ环境 变量
  • 如果会话时区是绝对偏移而不是区域名称,则调度程序将使用DEFAULT_TIMEZONE Scheduler属性的值。有关更多信息,请参阅SET_SCHEDULER_ATTRIBUTE过程。
  • 如果DEFAULT_TIMEZONE属性为NULL,则调度程序将在启用作业或窗口时使用systimestamp的时区。

4 个答案:

答案 0 :(得分:1)

我不确定这个答案是否真的通过了本网站上的答案规则,但在花了很多时间用Google搜索后,我想出了以下解决方案:

start_date      => CAST(trunc(sysdate, 'YEAR')+2/24 AS TIMESTAMP) at time zone 'Europe/Berlin'

我认为这是最接近最安全的解决方案,因为:

  • 它使用时间戳而不是日期 - 我相信它会强制在给定时区内在给定时间内真正执行作业,同时忽略DMBS_SCHEDULER default_timezone。我还发现了一些建议,说使用直接时间戳也是不安全的,只有这个演员是安全的
  • 我手动选择了我需要的时区,希望它不会与本地设置发生冲突。至于我不清楚,现在它是否真的与SESSIONTIMEZONE或DBTIMEZONE无关,是否会影响正常的运行时间。
  • 我使用了一点点黑客,即使要求工作应该在午夜之后开始,我已将其设置为凌晨2点,希望即使在时区不好和夏令时不好的情况下,它也会被移动到最大值+ -2小时。

我对这个解决方案感到满意,如果我完全清楚当作业实际执行的时间与服务器的本地时间,SESSIONTIMEZONE,DBTIMEZONE,start_date时区和DBMS_SCHEDULER时区有关。

我对时区规范也不满意,因为它有4个与之相关的缩写--LMT,CET,CEST,CEMT,其中CEST在我看来是完全错误的。我的目标是使用CET和夏令时(冬天!=夏天)。

答案 1 :(得分:1)

您可以使用它来确保传递带时区的时间戳,并且开始日期将具有时区名称(美国/东部)而不是偏移量(例如:+5:00)。这样,正如oracle docs提到的上述片段一样,Scheduler将跟踪DST。

- 创建SCHEDULE

declare 
 v_start_date timestamp with time zone;
BEGIN 

select localtimestamp at time zone 'US/Eastern' into v_start_date from dual; --US/Eastern

DBMS_SCHEDULER.CREATE_SCHEDULE(
      schedule_name => 'SAMPLE_SCHEDULE',
      start_date => v_start_date,
      repeat_interval => 'FREQ=DAILY; BYHOUR=10; BYMINUTE= 15',
      comments => 'Runs daily at the specified hour.'); 
END;

要确保您已正确设置,可以运行以下命令: ALTER SESSION SET nls_timestamp_tz_format =' MM-DD-YYYY HH24:MI:SS tzr tzd';

现在,创建两个调度,一个如上,一个使用sysdate作为start_date参数,并执行下面的查询。

- 检查TIMEZONE 从USER_SCHEDULER_SCHEDULES;

中选择*

V1: 27-MAR-14 11.44.24.929282 AM US / EASTERN

V2:

27-MAR-14 05.44.54.000000 PM +05:00

答案 2 :(得分:1)

实际上,我从来没有尝试过使用.CREATE_SCHEDULE方法,但是.CREATE_JOB也有start_date参数,对我来说很简单

start_date => TO_TIMESTAMP_TZ('00:10 Europe/Rome','hh24:mi tzr'

当我查询dba_scheduler_jobs时,它保留“欧洲/罗马”:

SELECT job_name, TO_CHAR(start_date) start_date,
                 TO_CHAR(next_run_date) next_run_date
    FROM dba_scheduler_jobs;

答案 3 :(得分:0)

要在此添加更多信息,以检查修改是否成功。 运行查询:从all_scheduler_jobs中选择*,其中owner ='schema_name'。 在该字段中,您可以看到start_date(其类型为带有时区的timestamp),其中包含以下数据:2017-12-05 01:55:00,000000000 EUROPE / YOUR_CITY 末尾带有时区信息可确认已正确保存了该时区信息。 然后,将next_run_date与start_date对齐,并且还应显示时区详细信息。