8

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

我花了很多时间浏览 Oracle 文档,但我仍然没有达到确定的程度。

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

工作属性

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

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

日历语法中的规则

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

5 回答 5

2

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

-- 创建一个时间表

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 参数并执行下面的查询。

-- Check the TIMEZONE 
select * from 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**
于 2014-03-27T15:46:42.600 回答
1

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

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

我相信这是最安全的解决方案,因为:

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

如果我绝对清楚地知道作业何时在服务器的本地时间、SESSIONTIMEZONE、DBTIMEZONE、start_date 时区和 DBMS_SCHEDULER 时区方面实际执行,我会对解决方案感到满意。

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

于 2014-01-16T10:40:20.347 回答
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;
于 2019-10-09T09:50:18.627 回答
0

当您想检查修改是否成功时,要为此添加更多信息。运行查询:select * from all_scheduler_jobs where owner='schema_name'。您可以在 start_date 字段中看到,它的类型为带时区的时间戳,它包含如下数据:2017-12-05 01:55:00,000000000 EUROPE/YOUR_CITY 最后有时区信息确认它已正确保存为了工作。然后,next_run_date 也与 start_date 对齐,它还应该显示时区详细信息。

于 2018-07-03T23:46:52.753 回答
0
SELECT DBMS_SCHEDULER.STIME FROM DUAL;

参考

于 2022-02-04T15:06:15.700 回答