0

ここでの私の要件は、日付型の列から GMT/UTC で時間を取得することです。しかし、キャストを使用して日付をタイムスタンプにキャストすると、セッションのタイムゾーンが GMT に設定されていても、参照として米国/太平洋タイムゾーンが使用されます。したがって、from_tz を使用しない限り、望ましい結果が得られません。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

Tasks テーブルには、task_started という日付型の列があります。この日付フィールドから UTC 時間を取得しようとしています。その一環として、データを挿入しているときにセッションのタイムゾーンを GMT に変更しようとしていたので、タイムスタンプに単純にキャストして戻すことができましたが、これは機能していません。

select task_started from tasks where rownum <2;

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

desc tasks;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
...
 TASK_STARTED                                       DATE
...
4

1 に答える 1

0

sysdateこれは、ロンドン時間のシステムで挿入されたデータを使用したデモであり、現在 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

つまり、どちらの場合も BST 時間です。特定のタイムゾーンに自動的に変換された日付 (またはタイムゾーンなしのタイムスタンプ) を表示するセッションまたはデータベース設定はありません。あなたがそれを言わない限り、データベースはその保存された日付/時刻が何を表しているかを知りません。sysdatecurrent_date、または日付リテラルを使用するかどうかはわかりません。データがテーブルに挿入される時点では、タイム ゾーン情報はまったくありません。

from_tz同等の UTC を取得するには、格納された値が特定のタイム ゾーンを表すことを宣言するために使用する必要があります。次に、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 を使用する必要があります。A を使用することもできますsessiontimezoneが、適切に設定することを忘れないでください。あなたの場合は明らかに、Europe/London の代わりに 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 時刻が表示されます。

于 2016-04-11T11:03:42.403 に答える