我有一条select语句,我正在其中转换时区
Select
from_tz(cast(DATE_TIME as timestamp), 'US/Eastern') at time zone 'UTC' DATE_TIME_UTC
From Table1
但是对于某些行,由于DST而出现错误
ORA-01878: specified field not found in datetime or interval
我想写一个类似的查询
select
if error then do something else do the time conversion from table1
答案 0 :(得分:2)
当您使用12c时,可以使用增强的子查询因子来定义本地函数;可以尝试使用美国/东部进行转换,如果失败则回落到-4:00。
使用示例数据和几行额外的行将继续转换:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS TZR TZD';
with
function get_tstz(p_date in date) return timestamp with time zone is
dst_exception exception;
pragma exception_init(dst_exception, -1878);
begin
return from_tz(cast(p_date as timestamp), 'US/Eastern');
exception
when dst_exception then
return from_tz(cast(p_date as timestamp), '-04:00');
end get_tstz;
select date_time,
get_tstz(date_time) as date_time_converted,
get_tstz(date_time) at time zone 'UTC' as date_time_utc
from table1
/
DATE_TIME DATE_TIME_CONVERTED DATE_TIME_UTC
------------------- ---------------------------------- ---------------------------
2018-03-11 01:59:00 2018-03-11 01:59:00 US/EASTERN EST 2018-03-11 06:59:00 UTC UTC
2018-03-11 02:06:00 2018-03-11 02:06:00 -04:00 -04:00 2018-03-11 06:06:00 UTC UTC
2018-03-11 02:08:00 2018-03-11 02:08:00 -04:00 -04:00 2018-03-11 06:08:00 UTC UTC
2018-03-11 02:21:00 2018-03-11 02:21:00 -04:00 -04:00 2018-03-11 06:21:00 UTC UTC
2018-03-11 02:48:00 2018-03-11 02:48:00 -04:00 -04:00 2018-03-11 06:48:00 UTC UTC
2018-03-11 02:06:00 2018-03-11 02:06:00 -04:00 -04:00 2018-03-11 06:06:00 UTC UTC
2018-03-11 02:33:00 2018-03-11 02:33:00 -04:00 -04:00 2018-03-11 06:33:00 UTC UTC
2018-03-11 03:00:00 2018-03-11 03:00:00 US/EASTERN EDT 2018-03-11 07:00:00 UTC UTC
我已经调整了我的NLS设置,以便您可以看到转换后的值的差异,例如EST,EDT或固定的-4:00。
正如评论中提到的那样,您将忽略潜在的数据问题,而更正更正已知错误的数据会更好-假设您可以确定为什么它是错误的,从而可以安全地进行修复;或确认您断言原始数据都应该是美国/东部。
从根本上讲,由于某些人显然并不是真正的美国/东部人,因此信任任何数据似乎都不安全。如果不知道这些特定记录如何以及为什么具有您不期望的值,则无法确定其他任何值也是您期望的。无论插入那些日期的任何应用程序,工具或过程可能已经(并且可能确实)插入了其他时间,这些时间看起来不错,但实际上也不是美国/东部时间。其余的都可以无误地进行转换,但这并不意味着UTC时间必须具有代表性。
您还有一个次要问题,因为您不知道记录为2017-11-05 01:00:00的日期最初是美国东部时间01:00还是美国东部时间01:00,因为该时间重复了夏季结束时。 Oracle只会为您选择。
答案 1 :(得分:1)
您可以创建一个自定义函数,并检查其是否带有时区的有效时间戳,并在查询的where子句中使用该函数,例如,如下所示。
create table t(x varchar(100));
insert into t
select '21-FEB-2009 18:00:00'
from dual
union all
select '31-FEB-2009 18:00:00' /*Junk date here..*/
from dual;
create or replace function fn_test(dt in varchar2)
return int
as
l_timestamp timestamp with time zone;
begin
l_timestamp :=from_tz(to_timestamp(dt,'DD-MON-YYYY hh24:mi:ss'), 'US/Eastern') at time zone 'UTC';
return 1;
exception
when others then
return null;
end;
/
select from_tz(to_timestamp(x,'DD-MON-YYYY hh24:mi:ss'),'US/Eastern') at time zone 'UTC'
from t
where fn_test(x) is not null
答案 2 :(得分:0)
我收到此错误消息的原因有两个:
最有可能的是:您正在尝试转换由于夏令时切换的原因不存在的本地时间,例如“28-MAR-21 02:34”在德国(柏林/欧洲时区)不存在,因为时钟在夜间从凌晨 1:59 跳到凌晨 3:00。解决方法:加一小时,UTC 就会反映正确的时间。
不太可能:时区字符串中的拼写错误:“Europe/Berlin”或“Berlin/Europe” - 两者都是错误的,正确的是“Europe/Berlin”(模式为大陆/城市)