有些job中跑应用程序,希望记下时间戳,但是取了current_timestamp之后,发现时间和实际的时间不准,查了几个小时。这是因为在job中跑的时候,current_timestamp是GMT格林尼治时间。
见下面的testcase,我们设置数据库服务器的时区是东八区的北京时间;客户端plsql所在的时间是东九区的首尔时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
--create table for testing drop table runlog_b; CREATE TABLE runlog_b AS SELECT SYSDATE SYS_DATE ,current_timestamp curr_timestamp,SESSIONTIMEZONE sess_timezone,current_date curr_date, LOCALTIMESTAMP local_timestamp,SYSTIMESTAMP sys_timestamp FROM dual where 1=2; --create procedure for testing Create or REPLACE PROCEDURE nested_loop_b IS BEGIN insert into runlog_b SELECT SYSDATE,current_timestamp,SESSIONTIMEZONE,current_date,LOCALTIMESTAMP,SYSTIMESTAMP FROM dual; commit; END nested_loop_b; / --在客户端plsqldev创建job,注:客户端所在的时区是+9:0,数据库服务器端的时区是北京的+8:0,可以看到如下: SQL> SELECT SYSDATE SYS_DATE ,current_timestamp curr_timestamp,SESSIONTIMEZONE sess_timezone,current_date curr_date, 2 LOCALTIMESTAMP local_timestamp,SYSTIMESTAMP sys_timestamp FROM dual; SYS_DATE CURR_TIMESTAMP SESS_TIMEZONE CURR_DATE LOCAL_TIMESTAMP SYS_TIMESTAMP ------------------------------ -------------------------------------------------------------------------------- --------------------------------------------------------------------------- -------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- 2014/2/21 11:51:42 21-FEB-14 12.51.42.238619 PM +09:00 +09:00 2014/2/21 12:51:42 21-FEB-14 12.51.42.238619 PM 21-FEB-14 11.51.42.238616 AM +08:00 SQL> --创建一个job跑上面的存储过程: SQL> 跑job的结果: SYS_DATE CURR_TIMESTAMP SESS_TIMEZONE CURR_DATE LOCAL_TIMESTAMP SYS_TIMESTAMP ------------------- ---------------------------------------- -------------------- ------------------- ------------------------------ -------------------------------------------------- 2014-02-21 11:00:49 21-FEB-14 03.00.49.010388 AM +00:00 +00:00 2014-02-21 03:00:49 21-FEB-14 03.00.49.010388 AM 21-FEB-14 11.00.49.010371 AM +08:00 2014-02-21 11:03:04 21-FEB-14 03.03.04.063177 AM +00:00 +00:00 2014-02-21 03:03:04 21-FEB-14 03.03.04.063177 AM 21-FEB-14 11.03.04.063174 AM +08:00 2014-02-21 11:06:04 21-FEB-14 03.06.04.137326 AM +00:00 +00:00 2014-02-21 03:06:04 21-FEB-14 03.06.04.137326 AM 21-FEB-14 11.06.04.137303 AM +08:00 |
可以看到sessiontimezone是+0:0,是格林尼治时间。
因此,如果我们要在job取时间戳,可以取systimestamp这个值。这个值是DB服务器上的时间的时间戳。
或者用加一条set time_zone也是一样的效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Create or REPLACE PROCEDURE nested_loop_b IS BEGIN execute immediate 'alter session set time_zone = ''+08:00'''; insert into runlog_b SELECT SYSDATE,current_timestamp,SESSIONTIMEZONE,current_date,LOCALTIMESTAMP,SYSTIMESTAMP FROM dual; commit; END nested_loop_b; / -- SYS_DATE CURR_TIMESTAMP SESS_TIMEZONE CURR_DATE LOCAL_TIMESTAMP SYS_TIMESTAMP ------------------- --------------------------------------------------------------------------- ------------------------------ ------------------------------ ------------------------------ -------------------------------------------------- 2014-02-21 12:03:01 21-FEB-14 12.03.01.035054 PM +08:00 +08:00 2014-02-21 12:03:01 21-FEB-14 12.03.01.035054 PM 21-FEB-14 12.03.01.035051 PM +08:00 2014-02-21 12:06:01 21-FEB-14 12.06.01.108673 PM +08:00 +08:00 2014-02-21 12:06:01 21-FEB-14 12.06.01.108673 PM 21-FEB-14 12.06.01.108671 PM +08:00 SQL> |
解决方案:
1 2 |
在job中的存储过程用systimestamp取时间戳,而不是用current_timestamp 或者,在存储过程中先execute immediate 'alter session set time_zone = ''+08:00'''; |