Oracle DB中TO_TIMESTAMP_TZ和CAST AS TIMESTAMP与LOCAL TIME ZONE的结果不同

时间:2015-03-09 18:14:17

标签: sql oracle oracle11g timestamp-with-timezone

我有一个Oracle 11g数据库,我正在尝试使用TIMESTAMP数据类型(特别是从没有包含时区的传入数据创建的数据类型)来处理DST的处理方式。我看到使用TO_TIMESTAMP_TZ()与CAST(DATE为TIMESTAMP WITH LOCAL TIME ZONE)时的行为有所不同,我无法解释。我希望生成的数据类型是一个分区时间戳,无论它是如何创建的,并且对它的任何操作都是相同的,但似乎不是这种情况。

在使用CAST选项时,为什么在INTERVAL数学中没有考虑由Fall DST更改创建的“额外”小时?我希望下面的查询的两行都是相同的。

查询:

select to_timestamp_tz('11/1/2015 1:00 AM US/Pacific', 'MM/DD/YYYY HH:mi AM TZR') + interval '2' hour as DST_PLUS_2, -- this is a post DST jump time
       to_timestamp_tz('11/1/2015 12:59 AM US/Pacific', 'MM/DD/YYYY HH:mi AM TZR') + interval '2' hour as PRE_DST_PLUS_2, -- this is a pre DST jump time
       to_char(to_timestamp_tz('11/1/2015 1:00 AM US/Pacific', 'MM/DD/YYYY HH:mi AM TZR'), 'TZR') as TZR
  from dual
union all
select cast(to_date('11/1/2015 1:00 AM', 'MM/DD/YYYY HH:mi AM') as timestamp with local time zone) + interval '2' hour as DST_PLUS_2,
       cast(to_date('11/1/2015 12:59 AM', 'MM/DD/YYYY HH:mi AM') as timestamp with local time zone) + interval '2' hour as PRE_DST_PLUS_2,
       to_char(cast(to_date('11/1/2015 1:00 AM', 'MM/DD/YYYY HH:mi AM') as timestamp with local time zone), 'TZR') as TZR
  from dual;

结果:

DST_PLUS_2                                  PRE_DST_PLUS_2                              TZR
01-NOV-15 03.00.00.000000000 AM US/PACIFIC  01-NOV-15 01.59.00.000000000 AM US/PACIFIC  US/PACIFIC
01-NOV-15 03.00.00.000000000 AM US/PACIFIC  01-NOV-15 02.59.00.000000000 AM US/PACIFIC  US/PACIFIC

2 个答案:

答案 0 :(得分:1)

看起来这可归结为TO_TIMESTAMP_TZ尝试从日期推断TIMESTAMP的TZD元素,而CAST AS TIMESTAMP WITH LOCAL TIME ZONE将采用数据库的当前TZD,而不管日期是什么时候。或者他们只是选择不同的默认行为来挑选1AM时间(前或后时间变化)中的哪一个。这种行为差异导致结果小时不同。

谢谢ruudvan!

查询:

select to_char(to_timestamp_tz('11/1/2015 1:00 AM US/Pacific', 'MM/DD/YYYY HH:mi AM TZR'), 'TZD') as TZD_TO_TS_TZ_1,
       to_char(cast(to_date('11/1/2015 1:00 AM', 'MM/DD/YYYY HH:mi AM') as timestamp with local time zone), 'TZD') as TZD_CAST_1,
       to_char(to_timestamp_tz('11/1/2015 12:00 AM US/Pacific', 'MM/DD/YYYY HH:mi AM TZR'), 'TZD') as TZD_TO_TS_TZ_12,
       to_char(cast(to_date('11/1/2015 12:00 AM', 'MM/DD/YYYY HH:mi AM') as timestamp with local time zone), 'TZD') as TZD_CAST_12
  from dual;

结果:

TZD_TO_TS_TZ_1  TZD_CAST_1  TZD_TO_TS_TZ_12 TZD_CAST_12
PST             PDT         PDT             PDT

答案 1 :(得分:0)

数据类型TIMESTAMP WITH TIME ZONE存储时区信息。当您插入11/1/2015 1:00 AM US/Pacific时,即存储了该内容,选择后即得到了该结果。

数据类型TIMESTAMP WITH TIME LOCAL ZONE也存储时区信息。但是,该值在当前用户会话时区SESSIONTIMEZONE中始终显示为始终。原则上,Oracle始终将值放在({TIMESTAMP WITH TIME ZONE} value) AT TIME ZONE SESSIONTIMEZONE

DATE不存储任何时区信息。如果运行CAST({DATE value} as timestamp with local time zone),则Oracle基本运行FROM_TZ({DATE value}, SESSIONTIMEZONE) as timestamp with local time zone)。即它将当前用户会话时区(可能与US/Pacific附加到DATE值,然后根据需要转换时区。

因此,查询结果实际上取决于您当前的会话时区SESSIONTIMEZONE。请注意,这可能是US/Pacific+07:00 / +08:00。如果将其设置为US/Pacific,则考虑夏令时。对于诸如+07:00+08:00这样的UTC偏移量,时区是固定的,即不考虑夏令时。