2016-04-11 11 views
0

ここでの要件は、日付型の列からGMT/UTCで時刻を取得することです。しかし、キャストを使用して日付をタイムスタンプにキャストすると、セッションタイムゾーンがGMTに設定されていても、米国太平洋のタイムゾーンを参照として使用しています。だからfrom_tzを使わない限り、私は望みの結果を見ていません。 oracle sqlに他のタイムゾーン設定がありますが、これはGMTを参照として常に使用するように変更する必要がありますか?Oracle SQLのタイムゾーンの問題

alter session set time_zone='+00:00'; 
select sessiontimezone from dual; 
select current_timestamp from dual; 
select sys_extract_utc(cast (sysdate as timestamp)) from dual; 
select sys_extract_utc(from_tz(cast (sysdate as timestamp), '-07:00')) from dual; 
select sys_extract_utc(current_timestamp) from dual; 


Session altered. 


SESSIONTIMEZONE 
--------------------------------------------------------------------------- 
+00:00 


CURRENT_TIMESTAMP 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.292173 AM +00:00 


SYS_EXTRACT_UTC(CAST(SYSDATEASTIMESTAMP)) 
--------------------------------------------------------------------------- 
11-APR-16 01.46.42.000000 AM 

SYS_EXTRACT_UTC(FROM_TZ(CAST(SYSDATEASTIMESTAMP),'-07:00')) 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.000000 AM 


SYS_EXTRACT_UTC(CURRENT_TIMESTAMP) 
--------------------------------------------------------------------------- 
11-APR-16 08.46.42.295310 AM 

タスク表には、「タスク開始」という日付型列があります。私は、この日付フィールドからUTC時間を取得しようとしています。その一環として、セッションタイムゾーンをGMTに変更してデータを挿入しようとしていたので、単にタイムスタンプに戻しても動作しません。

select task_started from tasks where rownum <2; 

TASK_STAR 
--------- 
10-APR-16 

desc tasks; 
Name          Null? Type 
----------------------------------------- -------- ---------------------------- 
... 
TASK_STARTED          DATE 
... 
+0

保存された日付(時間付き)と予想される出力の例を挙げることができますか?その列の日付/時刻はどのようなタイムゾーンを表し、どのように知っていますか?そのタイムゾーンを格納している別の列があるか、変換が必要であると想定していますか? –

+0

@AlexPoole私のテーブルには日付のみが格納されているので、これをタイムスタンプに戻しています。私は、テーブルに格納されている日付/時刻は、セッションタイムゾーンを変更したGMTのセッションタイムゾーンを使用していると仮定します。キャスト機能は、アメリカ/パシフィックで時間を戻ってきたので、私は混乱しました。 –

+0

日付の列にはタイムゾーンがありません(ただし、クエリ/クライアントに表示されていなくても常に時間があります)。プレーンタイムスタンプとしてキャストすると、時間は同じままですが、タイムゾーン情報はまだありません。あなたの質問は、日付/時刻をUTCに変換することです。これは、特定のゾーンから保存または提供されていることを意味します。例えば。サーバーのタイムゾーンを意味するsysdateを使用して日付が挿入されていて、それに相当するUTCが必要な場合。本当に必要なものが明確ではないので、データと出力を追加してください。 –

答えて

0

これはそう現在BST(+01:00)上で、ロンドン時間にシステムにsysdateを使用して挿入されたデータを使用してデモです。違いはあなたが西海岸で見るよりも小さいですが、同じことが適用されます。だから、

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'; 
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF3'; 
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZH:TZM'; 

create table tasks (id number, task_started date); 

alter session set time_zone='America/Los_Angeles'; 

insert into tasks (id, task_started) values (1, sysdate); 

select task_started, cast(task_started as timestamp) as ts 
from tasks where rownum < 2; 

TASK_STARTED  TS      
------------------- ----------------------- 
2016-04-11 11:55:59 2016-04-11 11:55:59.000 

alter session set time_zone = 'UTC'; 

select task_started, cast(task_started as timestamp) as ts 
from tasks where rownum < 2; 

TASK_STARTED  TS      
------------------- ----------------------- 
2016-04-11 11:55:59 2016-04-11 11:55:59.000 

sysdateは、データベース・サーバーの時間を使用していますので、あなたのテーブルを模倣、あなたはセッションのタイムゾーンが挿入された値には影響しないことがわかりますが、ないセッション(クライアント)時間(as explained here)どちらの場合もBST時間です。特定のタイムゾーンに自動的に変換された日付(タイムゾーンなしのタイムスタンプ)を示すセッションまたはデータベースの設定はありません。データベースは、あなたがそれを伝えない限り、記憶された日付/時刻が何を表しているかを知らない。 sysdatecurrent_date、または日付リテラルを使用するかどうかはわかりません。データがテーブルに挿入される時点では、タイムゾーン情報はまったくありません。

UTC相当の値を取得するには、格納された値が特定のタイムゾーンを表すことを宣言するには、from_tzを使用する必要があります。 at time zone(タイムゾーン情報を保持します)またはsys_extract_utc(これはありません)を使用して変換することができます。任意に日付にキャストする:

select from_tz(cast(task_started as timestamp), 'Europe/London') as db_tstz, 
    from_tz(cast(task_started as timestamp), 'Europe/London') at time zone 'UTC' as utc_tstz, 
    sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as utc_ts, 
    cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) as utc_date 
from tasks where rownum < 2; 

DB_TSTZ      UTC_TSTZ      UTC_TS     UTC_DATE   
------------------------------ ------------------------------ ----------------------- ------------------- 
2016-04-11 11:55:59.000 +01:00 2016-04-11 10:55:59.000 +00:00 2016-04-11 10:55:59.000 2016-04-11 10:55:59 

私は夏時間のためにタイムゾーンの地域名を使用しています。 dbtimezoneを使用することができますが、それは常に-08:00を使用します。質問に示すように、現時点では-07:00を使用する必要があります。あなたはsessiontimezoneを使用することができましたが、正しく設定することを忘れないでください。明らかにあなたの場合は、あなたのローカル地域を使用します。 America/Los_Angeles、ヨーロッパ/ロンドンの代わりに。

そして、あなたはエポックを得ることができることから、比較の日付から、単純にタイムスタンプ以上を比較することによって間隔を介した:

select sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) 
    - timestamp '1970-01-01 00:00:00' as diff_interval, 
    cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) 
    - date '1970-01-01' as diff_days, 
    86400 * 
    (cast(sys_extract_utc(from_tz(cast(task_started as timestamp), 'Europe/London')) as date) 
     - date '1970-01-01') as epoch 
from tasks where rownum < 2; 

DIFF_INTERVAL DIFF_DAYS  EPOCH 
---------------- --------- ----------- 
16902 10:55:59.0 16902.46 1460372159 

あなたがオンラインコンバータ(多くがある)に1460372159を入れた場合、それが表示されますUTC時間。