2017-02-22 74 views
0

我有以下系統信息:的Oracle SQL:處理與夏令時

我使用Oracle數據庫10g
SysTimeStampUTC
SessionTimeZoneEurope/Athens
dbTimeZone+03:00

所以,我列date_1tbl_1表中,以下日期時間:

date_1 
----------------- 
08.02.2017 10:00 
08.02.2017 11:00 
08.02.2017 12:00 
----------------- 

我想要的結果是這樣的:

date_2 
----------------- 
08.02.2017 13:00 
08.02.2017 14:00 
08.02.2017 15:00 

對於我使用:

SELECT TO_CHAR(date_1 + INTERVAL '3' HOUR, 'DD.MM.YYYY HH24:MI') as date_2 
FROM tbl_1 
WHERE date_1 >= TO_DATE('08.02.2017 10:00','DD.MM.YYYY HH24:MI') 
    AND date_1 <= TO_DATE('08.02.2017 12:00','DD.MM.YYYY HH24:MI') 

當從MarchOctober小時是因爲在上週日從改變我的問題出現March我們有一天23小時,最後一個星期天從October我們有一天25小時。

因爲這一點,我不得不改變我的查詢4次/年(在夏天的時候,在冬天的時候,當我們有23個小時,三月的時候,我們有25個小時,月)

你能推薦在這select查詢解決這個問題?

+0

爲什麼選擇postgresql標籤?你不使用Oracle嗎? – jarlh

+0

「date_1」列的數據類型是什麼,它包含的值名義上包含哪些時區? –

+0

@Alex Poole'date_1'的類型是'DATE',時區是'歐洲/雅典' – BOB

回答

1

如果你有一個普通的日期或時間戳沒有嵌入時區信息,你可以告訴Oracle把它當作一個特定的時間段是the from_tz() function。然後,您可以使用會話時區作爲「本地」或具有特定命名時區的值(現在具有數據類型「區域時間戳」而不是簡單的「時間戳」)將該值轉換爲另一個帶有at time zone datetime expression syntax的區域:

alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS'; 
alter session set nls_timestamp_format='YYYY-MM-DD HH24:MI:SS'; 
alter session set nls_timestamp_tz_format='YYYY-MM-DD HH24:MI:SS TZR'; 
alter session set time_zone = 'America/New_York'; 

with cte (ts) as (
    select timestamp '2017-02-08 12:00:00' from dual 
) 
select ts, 
    from_tz(ts, 'UTC') as ts_utc, 
    from_tz(ts, 'UTC') at local as ts_local, 
    from_tz(ts, 'UTC') at time zone 'Europe/Athens' as ts_athens 
from cte; 

TS     TS_UTC     TS_LOCAL        TS_ATHENS       
------------------- ----------------------- ------------------------------------ --------------------------------- 
2017-02-08 12:00:00 2017-02-08 12:00:00 UTC 2017-02-08 07:00:00 AMERICA/NEW_YORK 2017-02-08 14:00:00 EUROPE/ATHENS 

如果你從一個日起,那麼你必須調用from_tz()之前將其轉換爲一個時間戳:

with cte (dt) as (
    select cast(timestamp '2017-02-08 12:00:00' as date) from dual 
) 
select dt, 
    from_tz(cast(dt as timestamp), 'UTC') as ts_utc, 
    from_tz(cast(dt as timestamp), 'UTC') at local as ts_local, 
    from_tz(cast(dt as timestamp), 'UTC') at time zone 'Europe/Athens' as ts_athens 
from cte; 

DT     TS_UTC     TS_LOCAL        TS_ATHENS       
------------------- ----------------------- ------------------------------------ --------------------------------- 
2017-02-08 12:00:00 2017-02-08 12:00:00 UTC 2017-02-08 07:00:00 AMERICA/NEW_YORK 2017-02-08 14:00:00 EUROPE/ATHENS 

所以你原來date_1值問題的數據類型一樣,在它應該表示的名義時區。如果它是一個;準備好'帶時區的時間戳'或'具有本地時區的時間戳',那麼它已經嵌入了時區信息,因此根本不需要from_tz()部分。如果這是一個日期,您需要將其轉換爲時間戳。

假設date_1存儲爲一個普通的時間戳(也許您的間隔增加暗示,而不是由你使用的列名和過濾器),它是名義上UTC,你可以這樣做:

from_tz(date_1, 'UTC') at time zone 'Europe/Athens' 

。 ..這將給你一個'時區與時區'的結果;或者您可以使用local來依賴您的會話時區。如果`DATE_1存儲爲一個日期,你要補充的轉換時間戳記:

from_tz(cast(date_1 as timestamp), 'UTC') at time zone 'Europe/Athens' 

作爲演示,產生的CTE時間戳(不是日期),包括周圍的一些變化DST今年:

with tbl_1(date_1) as (
    select timestamp '2017-02-08 10:00:00' from dual 
    union all select timestamp '2017-02-08 11:00:00' from dual 
    union all select timestamp '2017-02-08 12:00:00' from dual 
    union all select timestamp '2017-03-23 12:00:00' + numtodsinterval(level, 'day') 
    from dual connect by level <= 4 
) 
select date_1, 
-- cast(from_tz(date_1, 'UTC') at time zone 'Europe/Athens' as timestamp) as date_2 
    to_char(from_tz(date_1, 'UTC') at time zone 'Europe/Athens', 
    'DD.MM.YYYY HH24:MI') as date_2 
from tbl_1 
order by date_1; 

DATE_1    DATE_2   
------------------- ---------------- 
2017-02-08 10:00:00 08.02.2017 12:00 
2017-02-08 11:00:00 08.02.2017 13:00 
2017-02-08 12:00:00 08.02.2017 14:00 
2017-03-24 12:00:00 24.03.2017 14:00 
2017-03-25 12:00:00 25.03.2017 14:00 
2017-03-26 12:00:00 26.03.2017 15:00 
2017-03-27 12:00:00 27.03.2017 15:00 

您可以看到,3月26日時鐘更改後會自動添加額外的小時。但是對於二月份的樣本數據,結果已經過去了一個小時 - 所以您的數據實際上沒有存儲爲UTC(但是是-01:00,並且您可以更改from_tz()調用以反映這一點),或者您的預期結果是錯誤。

+0

謝謝你的時間!你的解釋對我的工作非常有幫助。 – BOB

0

你可以申請的情況下,以選擇:

select date_1 + case 
        when to_char(date_1 ,'MM') <= 3 then 2/24 -- Jan/Feb/Mar 
        when to_char(date_1,'MM') <= 10 then 3/24 -- Apr to Oct 
        else 2/24 -- Nov/Dec 
       end as date_2 
from tbl_1