将字符串时间戳转换为 Oracle 中的本地时区

Converting string timestamp to local-time zone in Oracle

我正在尝试使用 oracle 数据库汇总全球多个移动电话号码的数据使用量,为了获得准确的结果,我的 SQL 查询需要将此字符串时间戳转换为我的本地时区 +03 ,例如转换为 +03 时区后第一个数字 7803128475 的预期时间应该是 20190606085959

我当前的查询不准确

select sum(data_usage) where timestamp between '20190601000000' and '20190630235959';

`+-------------+------------+----------------+----------+
| MSISDN      | DATA_USAGE | TIMESTAMP      | TIMEZONE |
+-------------+------------+----------------+----------+
| 7803128475  |   1223.323 | 20190606135959 | +08:00   |
| 78093678473 |   1323.323 | 20190607071259 | +05:00   |
| 79093648472 |   1423.323 | 20190609090659 | -06:00   |
+-------------+------------+----------------+----------+`

您可以将字符串转换为实时时间戳:

to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS')

然后您可以说明所在的时区:

from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE)

或者您可以组合两个字符串列并将两者一起转换:

to_timestamp_tz(TIMESTAMP || TIMEZONE, 'YYYYMMDDHH24MISSTZH:TZM')

(你的列名很混乱,所以我把它们都写成大写的,以便更清楚地区分它们...)

无论哪种方式,您都可以通过以下方式将其转换为您当地的时区:

from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE) at local

或者更清楚地表明它正在使用会话时区:

from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE) at time zone sessiontimezone

或者如果您真的想要数据库时区:

from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE) at time zone dbtimezone

将您的示例数据作为 CTE 可以为您提供:

alter session set time_zone = 'Asia/Baghdad';

-- CTE for sample data
with your_table (MSISDN, DATA_USAGE, TIMESTAMP, TIMEZONE) as (
  select '7803128475',  1223.323, '20190606135959', '+08:00' from dual
  union all
  select '78093678473', 1323.323, '20190607071259', '+05:00' from dual
  union all
  select '79093648472', 1423.323, '20190609090659', '-06:00' from dual
)
-- example query
select MSISDN, DATA_USAGE, TIMESTAMP, TIMEZONE,
  to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS') as ts,
  from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE) as tstz,
  from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE) at local as local_tstz
from your_table;

MSISDN      DATA_USAGE TIMESTAMP      TIMEZO TS                    TSTZ                         LOCAL_TSTZ                        
----------- ---------- -------------- ------ --------------------- ---------------------------- ----------------------------------
7803128475    1223.323 20190606135959 +08:00 2019-06-06 13:59:59.0 2019-06-06 13:59:59.0 +08:00 2019-06-06 08:59:59.0 ASIA/BAGHDAD
78093678473   1323.323 20190607071259 +05:00 2019-06-07 07:12:59.0 2019-06-07 07:12:59.0 +05:00 2019-06-07 05:12:59.0 ASIA/BAGHDAD
79093648472   1423.323 20190609090659 -06:00 2019-06-09 09:06:59.0 2019-06-09 09:06:59.0 -06:00 2019-06-09 18:06:59.0 ASIA/BAGHDAD

如果您只打算在 where 子句过滤器中使用转换后的时间,那么您根本不需要将其转换为本地时区,只要您说出您要比较的时区即可它与;我会使用 >=< 而不是 between:

select sum(DATA_USAGE)
from your_table
where from_tz(to_timestamp(TIMESTAMP, 'YYYYMMDDHH24MISS'), TIMEZONE)
  >= timestamp '2019-06-01 00:00:00 Asia/Baghdad'
and from_tz(to_timestamp(Timestamp, 'YYYYMMDDHH24MISS'), TIMEZONE)
  < timestamp '2019-07-01 00:00:00 Asia/Baghdad'

SUM(DATA_USAGE)
---------------
       3969.969

警告 该解决方案仅适用于几个 Oracle 11g 版本,请参阅评论。仅供参考。

多一个选项(TO_TIMESTAMP(TIMESTAMP, 'YYYYMMDDHH24MISS') AT TIME ZONE TIMEZONE) AT TIME ZONE sessiontimezone

演示

with yourTable (MSISDN, DATA_USAGE, TIMESTAMP, TIMEZONE) as (
  select '7803128475',  1223.323, '20190606135959', '+08:00' from dual
  union all
  select '78093678473', 1323.323, '20190607071259', '+05:00' from dual
  union all
  select '79093648472', 1423.323, '20190609090659', '-06:00' from dual
)
select (TO_TIMESTAMP(TIMESTAMP, 'YYYYMMDDHH24MISS') AT TIME ZONE TIMEZONE) AT TIME ZONE '+05:00' t2 
from yourTable;


T2
06-JUN-19 10.59.59.000000000 AM +05:00
07-JUN-19 07.12.59.000000000 AM +05:00
09-JUN-19 08.06.59.000000000 PM +05:00