2020年6月16日火曜日

Oracle APEXアプリケーションのグローバル化(7) - APIを使用したタイムゾーン設定

自動タイムゾーンについて説明したこちらの記事の続きです。夏時間に対応するため、Oracle APEXが提供しているAPIを使ったタイムゾーンの設定をするようにアプリケーションを改変していきます。

自動タイムゾーンをOFFにする


APIの呼び出しでタイムゾーンを設定するので、自動タイムゾーンOFFにします。グローバリゼーション属性の設定になります。


この画面へたどり着くパスはいくつかあります。ひとつ目のパスは、アプリケーション・プロパティの編集です。


共有コンポーネントからもたどり着くことができます。アプリケーション・ロジックに含まれるアプリケーション定義属性を開いてグローバリゼーションを選ぶ、または、グローバリゼーションに含まれるグローバリゼーション属性を選びます。


空白の非モーダル・ダイアログのページを作成する


タイムゾーンをユーザーのプリファレンスのひとつとして設定するページを作成します。ページの作成を開始します。


空白ページをクリックします。


ページ番号名前プリファレンスページ・モード非モーダル・ダイアログとします。オプションとして作成できる静的コンテンツ・リージョンのリージョン1プリファレンスとして作成します。へ進みます。



このページとナビゲーション・メニュー・エントリを関連付けないを選びへ進みます。


作成されるページの確認画面が表示されるので、終了をクリックします。


これで、非モーダル・ダイアログのページが作成されました。

タイムゾーンを設定するページ・アイテムを作成する


タイムゾーンの指定を行うページ・アイテムP7_TIMEZONEを作成します。

名前P7_TIMEZONEタイプ選択リスト(タイムゾーン名の一覧から選択します)、ラベルタイムゾーンとし、選択時のページ・アクションはデフォルトのNoneのままにします。選択時のアクションは後に動的アクションで設定します。選択リストとなるLOVは、タイプSQL問合わせとして、以下のSQLを設定します。
select tzname as d, tzname as r
from v$timezone_names
group by tzname
order by tzname


さらに、詳細の保存されていない変更の警告無視にします。値の変更は動的アクションによって行われるため、ページ上の変更がデータベースに反映されていない、ということは発生しません。ソースの設定ですが、タイププリファレンスとし、プリファレンス名MY_TIMEZONEとします。使用セッション・ステートの既存の値を常に置換セッション・ステートの保持リクエストごと(メモリーのみ)とします。


次に、このページ・アイテムの値が変更されたときに実行される動的アクションを定義します。動的アクションのタイミングは、イベントとしては変更選択タイプアイテム、そしてアイテムP7_TIMEZONEになります。これでP7_TIMEZONEが変更されたときに、アクションが実行されます。


実行されるアクションとして、以下のPL/SQLコードを指定します。APEX_UTIL.SET_SESSION_TIME_ZONEを呼び出すことで、タイムゾーンを設定しています。また、MY_TIMEZONEというプレファレンスに、設定したタイムゾーンを記憶することで新たにサインインした際に、設定済みのタイムゾーンを回復できるようにします。
begin
    apex_util.set_session_time_zone(:P7_TIMEZONE);
    apex_util.set_preference('MY_TIMEZONE', :P7_TIMEZONE, :APP_USER);
end;
アクションPL/SQLコードの実行送信するアイテムとしてP7_TIMEZONEを含めます。


最後にダイアログをクローズするためのボタンを追加します。ボタンを作成し、動作アクション動的アクションで定義します。


動的アクションを作成し、ボタンクリックされたときに、アクションが実行される設定を行います。


実行されるアクションは、ダイアログを閉じるです。


これで、タイムゾーンを設定する非モーダル・ページは完成です。

ナビゲーション・バーへプレファレンスを開くメニューを追加する


共有コンポーネントナビゲーション・バー・リストを開きます。


デスクトップ・ナビゲーション・バーを開きます。


&APP_USER.つまりサインインしたユーザー名をクリックしたときに表示されるメニューとして、プリファレンスのエントリを作成します。エントリの作成をクリックします。


親リスト・エントリ&APP_USER.とします。順序は分割線より上に表示させるため15とし、ターゲットとなるページとして7を指定します。そして、リスト・エントリの作成をクリックします。


追加したメニューがリストに表示されます。


メニューについてはこれで完了です。

サインイン時にプリファレンスからタイムゾーンを回復する


アプリケーション・プロセスとして、以下のコードを認証後に実行することで、プリファレンスMY_TIMEZONEからタイムゾーンの設定を回復します。
declare
   l_my_tz varchar2(40);
begin
    l_my_tz := apex_util.get_preference('MY_TIMEZONE', :APP_USER);
    if l_my_tz is not null then
        apex_util.set_session_time_zone(l_my_tz);
    end if;
end;
共有コンポーネントアプリケーション・プロセスを開きます。


アプリケーション・プロセスの一覧画面から、作成を実行します。


名前タイムゾーンの回復ポイント認証後とします。へ進みます。


最初に示したコードを入力してへ進みます。


 条件タイプは無指定にして(- 条件タイプの選択 - という表示のままにしておく)、プロセスの作成をクリックします。

登録したプロセスがリストの表示されます。


これで、サインイン時にプリファレンスとして設定されているタイムゾーンが回復します。

動作確認をする


アプリケーションを実行して、Datetimesレポートを開きます。その後、右上のユーザー名をクリックし、追加したプリファレンスが含まれるメニューを表示させます。


開いたページでタイムゾーンとしてUS/Easternを選びます。ダイアログは開いたままで構いません。

Datetimesレポートに戻り、変更したタイムゾーンを反映させるため、ブラウザの機能を使ってページの再読み込み(リロード)を行います。タイムゾーン・オフセットがUS/Easternになっていることを確認します。


タイムゾーン・オフセットが-04:00のときのTSLTZ型の表示と比較してみましょう。


ニューヨーク冬以外の時刻はタイムゾーン・オフセットが-04:00でもUS/Easternでも同じ表示です。ニューヨーク冬のみ表示が異なり、TSTZ型の表示と一致するタイムゾーン・オフセットUS/Easternが、オフセットを-05:00と扱っています。つまり夏時間は適切に扱われています。

タイムゾーンがUS/Easternの状態で、2020/12/21 00:00を追加します。ニューヨーク冬2とします。


今度はTSLTZ型、TSTZ型の双方とも、2020/12/21 00:00として時刻が表示されます。


サインアウトして再度サインインしたときに、タイムゾーンがきちんと回復するかどうか試してみてください。回復するはずです。

夏時間を扱う場合は夏時間に対応したタイムゾーンを設定する必要がある、というのが今回のポイントです。