带时间的Oracle SQL sysdate

时间:2018-08-02 16:44:26

标签: sql oracle timezone

我正在使用Oracle SQL。我正在尝试使用sysdate和时间来查询查询结果。我在where子句中放置了一个时间,但是我需要它是自动的,并且使用sysdate并将其转换为本地时间是正确的方法。有什么想法吗?

SELECT RESOURCE, AVG(SALES) AS SALES
FROM Z_HOURLY_RESOURCE
WHERE DATE_TIME_START BETWEEN to_date(to_char(FROM_TZ( CAST( (to_date('2018-08-02T05:00:00','yyyy-MM-dd"T"HH24:mi:ss') )AS TIMESTAMP ), 'America/Los_Angeles') AT TIME ZONE 'UTC', 'yyyy-MM-dd"T"HH24:mi:ss'),'yyyy-MM-dd"T"HH24:mi:ss')
  AND to_date(to_char(FROM_TZ( CAST( (to_date('2018-08-02T13:00:00','yyyy-MM-dd"T"HH24:mi:ss')+1) AS TIMESTAMP ), 'America/Los_Angeles') AT TIME ZONE 'UTC', 'yyyy-MM-dd"T"HH24:mi:ss'),'yyyy-MM-dd"T"HH24:mi:ss') 

2 个答案:

答案 0 :(得分:3)

在没有样本数据的情况下很难满足您的需求,但是听起来您想将本地会话时区(例如LA)中的05:00到13:00的时间范围转换为UTC以便与表中基于UTC的时间戳。

您可以执行以下操作:

WHERE DATE_TIME_START >= sys_extract_utc(cast(trunc(current_date) + 5/24 as timestamp with time zone))
  AND DATE_TIME_START <  sys_extract_utc(cast(trunc(current_date) + 13/24 as timestamp with time zone))

在您确实希望最多 13:00的假设下,我使用了>=<而不是between,通常情况是时间范围。如果您确实希望完全按照13:00:00的格式包含数据,则将<更改为<=,或返回到between

解释正在执行的操作,但是:current_date为您提供会话时区中的日期/时间。截断会将时间设置为午夜(默认情况下),因此您可以添加5或13个小时来获取所需的时间。那仍然是一个日期,因此您可以将其强制转换为带有时区的时间戳,以便它再次代表您的会话时区中的时间。然后,您可以使用sys_extract_utc()来获取与UTC等效的时间戳。

演示这些步骤:

alter session set time_zone = 'America/Los_Angeles';
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF1';
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF1 TZH:TZM';

select sysdate as a,
  current_date as b,
  trunc(current_date) as c,
  trunc(current_date) + 5/24 as d,
  cast(trunc(current_date) + 5/24 as timestamp with time zone) as e,
  sys_extract_utc(cast(trunc(current_date) + 5/24 as timestamp with time zone)) as f
from dual
union all
select sysdate as a,
  current_date as b,
  trunc(current_date) as c,
  trunc(current_date) + 13/24 as d,
  cast(trunc(current_date) + 13/24 as timestamp with time zone) as e,
  sys_extract_utc(cast(trunc(current_date) + 13/24 as timestamp with time zone)) as f
from dual;

A                   B                   C                   D                   E                            F                    
------------------- ------------------- ------------------- ------------------- ---------------------------- ---------------------
2018-08-02 18:56:23 2018-08-02 10:56:23 2018-08-02 00:00:00 2018-08-02 05:00:00 2018-08-02 05:00:00.0 -07:00 2018-08-02 12:00:00.0
2018-08-02 18:56:23 2018-08-02 10:56:23 2018-08-02 00:00:00 2018-08-02 13:00:00 2018-08-02 13:00:00.0 -07:00 2018-08-02 20:00:00.0

答案 1 :(得分:1)

首先,您不必将TIMESTAMP强制转换为CHAR,然后再次转换为TIMESTAMP

假设DATE_TIME_STARTTIMESTAMP,并且时间以UTC给出,则可以使其更简单。当Oracle比较TIMESTAMP WITH TIME ZONE值时,比较总是在UTC时间值自动进行。您的情况就是这样。

SELECT RESOURCE, AVG(SALES) AS SALES
FROM Z_HOURLY_RESOURCE
WHERE FROM_TZ(DATE_TIME_START, 'UTC') 
   BETWEEN TO_TIMESTAMP_TZ('2018-08-02T05:00:00 America/Los_Angeles', 'yyyy-MM-dd"T"HH24:mi:ss TZR')
       AND TO_TIMESTAMP_TZ('2018-08-02T13:00:00 America/Los_Angeles', 'yyyy-MM-dd"T"HH24:mi:ss TZR')

但是,由于功能FROM_TZ(DATE_TIME_START, 'UTC'),性能可能不是最佳的,这取决于您的数据。

如果您需要基于当前时间的条件,它将是这样的:

SELECT RESOURCE, AVG(SALES) AS SALES
FROM Z_HOURLY_RESOURCE
WHERE FROM_TZ(DATE_TIME_START, 'UTC') 
   BETWEEN TRUNC(SYSTIMESTAMP) 
       AND TRUNC(SYSTIMESTAMP) + INTERVAL '1' DAY

以上查询仅说明了时区处理。您不必考虑时区SYSTIMESTAMP,在任何情况下都可以进行比较。