如何在Oracle SQL上比较转换为UTC的当前时间戳和转换为UTC的另一个时间戳?

时间:2019-04-12 20:30:16

标签: sql oracle

我正在尝试从oracle SQL表中提取距特定时间不超过30分钟的行。但是时间不会存储为日期字段,而是以“ 2019-04-04T21:32:38 + 0000”格式存储在VARCHAR2字段中

在SQL查询中是否可以做到这一点?

尝试花费时间并将其转换,但我只能得到时间戳,而且我不知道如何正确地补偿时间

2 个答案:

答案 0 :(得分:2)

您需要做的第一件事是将字符串转换为日期时间类型。由于您的字符串具有时区值,因此会将其转换为TIMESTAMP WITH TIME ZONE数据类型。

to_timestamp_tz( '2019-04-04T21:32:38+0000', 'yyyy-mm-dd"T"hh24:mi:sstzhtzm')

这给了我“ 04-APR-19 09.32.38.000000000 PM GMT”,它是日期/时间值,而不是字符值。

您说您正在将其与其他值进行比较,但是没有提供任何详细信息,因此我无法再进一步了。

此外,请尽量不要将日期/时间存储为varchar2s。只会造成问题。

答案 1 :(得分:0)

您无需转换为UTC。如@eaolson所示,您可以将您需要的字符串转换为带有时区值的时间戳。然后,您可以将其与具有时区值的任何其他时间戳直接进行比较-Oracle将无形地处理任何调整。当然,您可以转换为UTC,但不需要。

  

我不确定如何将当前时间转换为TZ

systimestampcurrent_timestamp都已经具有时区信息。

因此,为了展示一些查询的一致性,我们将它们紧密结合在一起:

alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF1 TZR';

select current_timestamp, current_timestamp at time zone 'GMT' as now_as_gmt
from dual;

CURRENT_TIMESTAMP                   NOW_AS_GMT               
----------------------------------- -------------------------
2019-04-15 16:02:29.6 EUROPE/LONDON 2019-04-15 15:02:29.6 GMT

并在截止30分钟之前和之后使用CTE生成一些数据:

-- CTE for sample data
with your_table (some_time) as (
  select '2019-04-04T21:32:38+0000' from dual
  union all
  select to_char(current_timestamp at time zone 'Africa/Nairobi'
    - interval '30' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
  union all
  select to_char(current_timestamp at time zone 'Europe/London'
    - interval '29' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
  union all
  select to_char(current_timestamp at time zone 'America/New_York'
    - interval '28' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
  union all
  select to_char(current_timestamp at time zone 'UTC'
    - interval '27' minute, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') from dual
)
-- query
select some_time,
  to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') some_time_as_tstz,
  to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') at time zone 'GMT' some_time_as_gmt
from your_table;

SOME_TIME                SOME_TIME_AS_TSTZ            SOME_TIME_AS_GMT         
------------------------ ---------------------------- -------------------------
2019-04-04T21:32:38+0000 2019-04-04 21:32:38.0 GMT    2019-04-04 21:32:38.0 GMT
2019-04-15T17:32:29+0300 2019-04-15 17:32:29.0 +03:00 2019-04-15 14:32:29.0 GMT
2019-04-15T15:33:29+0100 2019-04-15 15:33:29.0 +01:00 2019-04-15 14:33:29.0 GMT
2019-04-15T10:34:29-0400 2019-04-15 10:34:29.0 -04:00 2019-04-15 14:34:29.0 GMT
2019-04-15T14:35:29+0000 2019-04-15 14:35:29.0 GMT    2019-04-15 14:35:29.0 GMT

您可以看到已转换为时间戳的字符串的实际值及其GMT等效项-​​再次,不需要,仅用于视觉验证。

然后,您可以在过滤器中使用current_timestampsystimestamp,将其向后调整30分钟:

-- same CTE omitted
select some_time,
  to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') some_time_as_tstz,
  to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM') at time zone 'GMT' some_time_as_gmt
from your_table
where to_timestamp_tz(some_time, 'YYYY-MM-DD"T"HH24:MI:SSTZHTZM')
  > current_timestamp - interval '30' minute;

SOME_TIME                SOME_TIME_AS_TSTZ            SOME_TIME_AS_GMT         
------------------------ ---------------------------- -------------------------
2019-04-15T15:33:29+0100 2019-04-15 15:33:29.0 +01:00 2019-04-15 14:33:29.0 GMT
2019-04-15T10:34:29-0400 2019-04-15 10:34:29.0 -04:00 2019-04-15 14:34:29.0 GMT
2019-04-15T14:35:29+0000 2019-04-15 14:35:29.0 GMT    2019-04-15 14:35:29.0 GMT

排除了过去30分钟或更长时间的两个CTE行。比较时会考虑它们的实际时区或您的会话/系统的时区,而不必将任何内容显式转换为任何特定的时区。

  

提前30分钟或比当前时间戳短

然后在一个时间范围内检查您的值:

where initial_proc_etr >= current_timestamp - interval '30' minute;
and initial_proc_etr < current_timestamp + interval '30' minute

如您在评论中所述,假定该列具有时区成分。