如何将带时区的字符串转换为日期

MoG*_*MoG 2 oracle plsql date to-char to-date

如何在 Oracle 中将以下字符串转换为日期

Wed Jan 13 23:01:24 GMT 2016
Run Code Online (Sandbox Code Playgroud)

在下面尝试过,这个获取的日期为

SELECT TO_CHAR(SYSDATE, 'DY MON DD HH24:MM:SS YYYY') FROM dual;

FRI AUG 26 14:08:04 2016
Run Code Online (Sandbox Code Playgroud)

最终,想要这样的东西

SELECT TO_CHAR('Wed Jan 13 23:01:24 GMT 2016', 'DY MON DD HH24:MM:SS ??? YYYY') FROM dual;
Run Code Online (Sandbox Code Playgroud)

Ale*_*ole 5

如果时区始终是公认的缩写,您可以执行以下操作:

select to_timestamp_tz('Wed Jan 13 23:01:24 GMT 2016', 'Dy Mon DD HH24:MI:SS TZD YYYY')
from dual;

TO_TIMESTAMP_TZ('WEDJAN1323:01:24GMT2016','DYMONDDHH24:MI:SSTZDYYYY')
---------------------------------------------------------------------
2016-01-13 23:01:24 EUROPE/LONDON                                    
Run Code Online (Sandbox Code Playgroud)

您不能直接转换为日期,因为to_date(). 如果你有一个固定值——总是格林威治标准时间——你可以通过将其视为文字来忽略它,但你没有。

如果您希望将其作为时间戳或日期,而不是带时区的时间戳,则需要决定如何转换它。您可以假设它是本地时间并通过强制转换基本上忽略时区,或者您可以将其调整为特定时区,例如 UTC。有多种方法,这里有一对带有 CTE 的夫妇来提供您的样本,另一种在另一个区域(好吧,无论如何在夏季,所以您会得到不同的字符串):

with t (str) as (
  select 'Wed Jan 13 23:01:24 GMT 2016' from dual
  union all select 'Fri Aug 26 19:53:27 BST 2016' from dual
)
select to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY') as tstz,
  cast(to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY') as timestamp) as ts,
  cast(to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY') as date) as dt,
  sys_extract_utc(to_timestamp_tz(str, 'Dy Mon DD HH24:MI:SS TZD YYYY')) as tsutc
from t;

TSTZ                              TS                  DT                  TSUTC             
--------------------------------- ------------------- ------------------- -------------------
2016-01-13 23:01:24 EUROPE/LONDON 2016-01-13 23:01:24 2016-01-13 23:01:24 2016-01-13 23:01:24
2016-08-26 19:53:27 EUROPE/LONDON 2016-08-26 19:53:27 2016-08-26 19:53:27 2016-08-26 18:53:27
Run Code Online (Sandbox Code Playgroud)

当然,您如何处理它取决于您真正需要什么。


不幸的是,这并不总是适用于缩写;Oracle 不一定识别您在 Unix date 命令输出中看到的值,并且它识别的值并不总是可用的。更改会话时区可能会破坏它:

alter session set time_zone = 'America/Los_Angeles';
select to_timestamp_tz('Wed Jan 13 23:01:24 GMT 2016', 'Dy Mon DD HH24:MI:SS TZD YYYY')
from dual;

ORA-01857: not a valid time zone
Run Code Online (Sandbox Code Playgroud)

您可以将会话时区更改为可以识别它的时区(欧洲/伦敦),但这是一种黑客行为,无论如何都不适用于所有值。缩写可能意味着不止一件事,这无济于事。

如果您有一个已知预期值的列表,并且知道它们对您真正代表什么,您可以交换一个区域的缩写,但它并没有真正缩放:

select to_timestamp_tz(
    replace(replace('Wed Jan 13 23:01:24 GMT 2016', 'GMT', 'Europe/London'),
      'BST', 'Europe/London'),
    'Dy Mon DD HH24:MI:SS TZR YYYY') from dual;
Run Code Online (Sandbox Code Playgroud)

或者使用多种输出格式:

with t1 (str) as (
  select 'Wed Jan 13 23:01:24 GMT 2016' from dual
  union all select 'Fri Aug 26 19:53:27 BST 2016' from dual
),
t2 (adj_str) as (
  select replace(replace(str, 'GMT', 'Europe/London'), 'BST', 'Europe/London')
  from t1
)
select to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY') as tstz,
  cast(to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY') as timestamp) as ts,
  cast(to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY') as date) as dt,
  sys_extract_utc(to_timestamp_tz(adj_str, 'Dy Mon DD HH24:MI:SS TZR YYYY')) as tsutc
from t2;
Run Code Online (Sandbox Code Playgroud)

您需要对您期望的每个缩写进行嵌套replace调用(或regexp_replace稍微减少重复);或者可以有一个函数来隐藏你的主查询中的混乱。