【问题标题】:Oracle SQL sysdate with timeOracle SQL sysdate 与时间
【发布时间】:2018-08-02 16:44:26
【问题描述】:

我正在使用 Oracle SQL。我正在尝试使用 sysdate with time 来给我查询结果。我在 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') 

【问题讨论】:

  • DATE_TIME_START 是什么数据类型 - 听起来像是代表 UTC 时间的日期或时间戳,对吗?如果您希望查询基于当前日期,您想要什么时间范围(本地 - 那么什么时区;或 UTC)?示例数据和预期结果也可能会有所帮助 - 作为格式化文本,而不是图像。
  • DATE_TIME_START 是一个时间戳 (6)。我希望时间范围是洛杉矶时间当地时间早上 5 点到下午 1 点。
  • 所以该列的值代表洛杉矶的时间?参考当地时间和特定时区有点令人困惑。数据库服务器也在洛杉矶时间吗?
  • 不,服务器在法国,这就是为什么 sysdate 基于 UTC。所以我需要将日期和时间转换为 LA 时间,但要使用时间范围。如果我可以更正我想要实现的日期格式,我的问题中指定的列具有值。如果我运行我示例的代码,它运行良好,结果很好。
  • 为什么服务器在法国这一事实表明sysdate 以UTC 格式返回值? sysdate 取决于操作系统时间和时区,在法国通常是 CET/CEST。

标签: sql oracle timezone


【解决方案1】:

在没有样本数据的情况下很难计算出您需要的内容,但听起来您想将本地会话时区(例如洛杉矶)的时间范围 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))

我使用了&gt;=&lt; 而不是between,假设您真的希望 13:00,这通常是时间范围的情况。如果您确实想准确包含 13:00:00 的数据表单,请将 &lt; 更改为 &lt;=,或返回到 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

【讨论】:

  • 做到了!!!感谢 Alex 的及时回复和详细的演示。再次感谢。
  • 嗨,Alex,我在执行 UNION ALL 时遇到了问题。根据时间范围,我需要轮班 3 个班次 - 早上 5 点到下午 1 点、下午 1 点到晚上 9 点、第二天晚上 9 点到早上 5 点。 +5/24 或 +13/24 的 current_date 和格式以及将其用于其他班次会错误地抛出数据?有什么建议吗?
  • 13/24 到 21/24 应该不是问题,超过午夜只是稍微复杂一些。不过,我不确定您对工会是什么意思。如果您希望在一个查询中所有三个班次,则使用一个查询并将范围包含在分组依据中。不过,您可能需要提出一个新问题来解释您的新问题。
  • 为了应付午夜过后,您可能只需要使用(24+5)/24,就可以到达凌晨 5 点。明天。一个更棘手的问题可能是,如果您仍想显示某些内容,则当当前时间在午夜和凌晨 5 点之间时,与上述查询一样,您将尝试显示尚未开始的班次数据。您可以通过在应用trunc 之前从current_date 中减去5/24 来解决它。
  • 谢谢两位。 +05/24 - +13/24 , +13/24 - +21/24 和 +21/24 - CURRENT_DATE+1 + 05/24
【解决方案2】:

首先,您不必将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 的时区,在任何情况下都可以进行比较。

【讨论】:

  • 感谢 Wernfried。使用最后一个查询,查询运行得更快。但是我有 3 个班次的时间范围,早上 5 点到下午 1 点,下午 1 点到晚上 9 点,第二天晚上 9 点到早上 5 点。这两种方法都行吗?
  • 当然可以使用BETWEEN TRUNC(SYSTIMESTAMP) AND TRUNC(SYSTIMESTAMP) + INTERVAL '1 05:00' DAY TO MINUTE
猜你喜欢
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-14
  • 1970-01-01
相关资源
最近更新 更多