將日期或時間戳存儲爲字符串不是一個好主意。你應該讓你的列成爲他們將要保存的數據的正確數據類型。除了允許Oracle更有效率之外,它還可以防止您存儲無效數據。
但是,如果你只是想轉換爲字符串像'1965-08-01 00:00:00.0'
到'Tue Aug 01 00:00:00 PDT 2000'
所以他們都在相同的字符串格式,你可以將這些值轉換爲時間戳與to_timestamp()
,指定他們代表了from_tz()
哪個時區,然後將其轉換回以您想要的格式串入。與您的樣本數據建立了一個演示表t
:
update t set str = to_char(from_tz(to_timestamp(str, 'YYYY-MM-DD HH24:MI:SS.FF'),
'America/Los_Angeles'), 'Dy Mon DD HH24:MI:SS TZD YYYY')
where str not like '%PDT%' and str not like '%PST%';
3 rows updated.
select * from t;
STR
----------------------------
Wed Dec 12 00:00:00 PST 1973
Wed May 14 00:00:00 PDT 2003
Mon May 01 00:00:00 PDT 1950
Fri Jul 01 00:00:00 PDT 1977
Sun Feb 01 00:00:00 PST 2015
Wed May 14 00:00:00 PDT 2003
6 rows selected
您需要申請一個過濾器,它忽略了已經在目標格式的任何行,因爲這些會出錯。這裏我排除了任何包含PDT或PST的內容。如果您有其他格式未顯示,則可以使用regexp_like()
查找與特定格式完全匹配的行。
更一般地,任何你的字符串轉換爲實際的時間戳,您可以創建將嘗試各種不同的格式,並返回成功轉換,通過捕獲異常的第一個功能。一個簡單的蠻力方法可能是:
create or replace function my_to_timestamp_tz(p_str varchar2)
return timestamp with time zone as
begin
-- try each expected pattern in turn
begin
return to_timestamp_tz(p_str, 'Dy Mon DD HH24:MI:SS TZD YYYY');
exception
when others then
null;
end;
begin
-- unspecified TZ; this assumes same as server
return to_timestamp_tz(p_str, 'YYYY-MM-DD HH24:MI:SS.FF');
exception
when others then
null;
end;
-- maybe throw an exception if no conversions worked
return null;
end;
/
PDT/PST並不總是被識別;我有兩個DB,我認爲它們是相同的,但是一個允許和其他的拋出「ORA-01857:不是有效的時區」。如果你看到過,你可以解決它通過治療TZD值作爲固定字符串指定它代表區域:
-- if your DB doesn't recognise PDT/PST then force them to a region:
begin
return from_tz(to_timestamp_tz(p_str, 'Dy Mon DD HH24:MI:ss "PDT" YYYY'),
'America/Los_Angeles');
exception
when others then
null;
end;
begin
return from_tz(to_timestamp_tz(p_str, 'Dy Mon DD HH24:MI:ss "PST" YYYY'),
'America/Los_Angeles');
exception
when others then
null;
end;
-- other time zone abbreviations and matching regions if you expect any
使用功能:
with t (str) as (
select '1973-12-12 00:00:00.0' from dual
union all select '2003-05-14 00:00:00.0' from dual
union all select '1950-05-01 00:00:00.0' from dual
union all select 'Fri Jul 01 00:00:00 PDT 1977' from dual
union all select 'Sun Feb 01 00:00:00 PST 2015' from dual
union all select 'Wed May 14 00:00:00 PDT 2003' from dual
)
select str, my_to_timestamp_tz(str) as converted
from t;
STR CONVERTED
---------------------------- ----------------------------------------------------
1973-12-12 00:00:00.0 1973-12-12 00:00:00 Europe/London
2003-05-14 00:00:00.0 2003-05-14 00:00:00 Europe/London
1950-05-01 00:00:00.0 1950-05-01 00:00:00 Europe/London
Fri Jul 01 00:00:00 PDT 1977 1977-07-01 00:00:00 America/Los_Angeles
Sun Feb 01 00:00:00 PST 2015 2015-02-01 00:00:00 America/Los_Angeles
Wed May 14 00:00:00 PDT 2003 2003-05-14 00:00:00 America/Los_Angeles
注意,前三個假設一個時區,因爲我在英國選擇了倫敦。如果這是不會給你正確的結果,你知道那些總是代表一個特定的時間段,你可以通過改變最後一個塊中的函數來完成指定區域:
begin
-- unspecified TZ; assume from a specific region
return from_tz(to_timestamp(p_str, 'YYYY-MM-DD HH24:MI:SS.FF'),
'America/Los_Angeles');
exception
...
這將然後得到:
STR CONVERTED
---------------------------- ----------------------------------------------------
1973-12-12 00:00:00.0 1973-12-12 00:00:00 America/Los_Angeles
2003-05-14 00:00:00.0 2003-05-14 00:00:00 America/Los_Angeles
1950-05-01 00:00:00.0 1950-05-01 00:00:00 America/Los_Angeles
Fri Jul 01 00:00:00 PDT 1977 1977-07-01 00:00:00 America/Los_Angeles
Sun Feb 01 00:00:00 PST 2015 2015-02-01 00:00:00 America/Los_Angeles
Wed May 14 00:00:00 PDT 2003 2003-05-14 00:00:00 America/Los_Angeles
如果你真的想你可以將生成的時間戳轉換回字符串,但我真的建議您將它們保存爲正確的數據類型
這就是爲什麼你不應該存儲日期/時間戳作爲字符串。你只有這兩種格式?你的第一個查詢也會拋出「ORA-01846:不是一週中的有效日子」,而不是關於TZD的事情?你假設前三行是在哪個時區?並且/或者你想要將最後三行轉換爲什麼時區? –
我期待所有那些PST格式不正確 – rohitchandra