ヘッダーをスキップ

Oracle Applications開発者ガイド
リリース12
E06048-01
目次へ
目次
前のページへ
前へ
次のページへ
次へ

日付の処理

概要

この章では、コーディングにおいて正しく日付を処理するために必要な情報を説明します。

Oracle Applicationsにおける2000年対応

Oracle Applicationsはリリース10.7で2000年対応を導入しました。リリース11、11iおよび12でも、2000年対応をサポートしています。

2000年対応によって、日付がどの世紀の日付であるかについて、決して混乱が生じないようになります。フォーム画面とフォーム・コードに現れるOracle Applicationsの日付値は、コンカレント・プログラムで使用され、データベースにおいて操作され、格納されます。Oracle Applicationsへのカスタム拡張および変更はまた、カスタム・フォーム、表、API、コンカレント・プログラムおよびその他のコードにおいて日付値を使用します。この項では、Oracle Applicationsへのカスタム拡張および変更で使用される日付が2000年対応の要件を満たすようにするための手順を説明します。

既存のコードについては、コードを2000年対応にするために参考にできるチェック・リストをこの項で説明しています。これらのチェック・リストは、Oracle Applications環境を対象にしています。これは、日付をコーディングする際に最もよく見られる間違いをリストしているトラブルシューティング・ガイドです。

2000年対応

Oracleは、英国規格協会(British Standards Institute)による定義のスーパーセットに基づいた2000年対応の定義を使用しています。この定義は、日付の処理において2000年対応を満たす上での5つの要素を次のとおり説明しています。

この項で概説している標準に従うことにより、Oracle Applications環境におけるコーディングで大部分の2000年問題を回避できます。既存のコードをアップグレードする場合は、コードの2000年対応を確保するために提供されているチェック・リストに従ってください。

Oracle Applicationsにおける日付

アプリケーションにおいて日付を格納する方法には、文字列として格納する、またはユリウス日のバイナリとして格納する方法の2通りがあります。日付は、文字列およびユリウス日の両方として、データベース表、CおよびPro*Cのコード、PL/SQLバージョン1、2および8、コンカレント・プログラム、Oracle Reports、Javaコード、フレックスフィールド列、フォーム・フィールド、プロファイル値など、アプリケーションの様々な場所で使用されます。

Oracle Applicationsで日付を使用する方法について議論を続ける前に、いくつかの定義を確立しておくことが有用です。

プラスおよびマイナスの無限大日付

プラスおよびマイナスの無限大日付は、コードにおいて比較値として使用される日付です。これらは、コードの存続期間において通常は有効な日付とならない日付を指定するものです。

Oracle Applicationsは、年を4桁でサポートしている箇所ではどこでも、9999年1月1日をプラスの無限大として、1000年1月1日をマイナスの無限大として使用します。

プラスの無限大について、カスタム・コードにおいてよく見られる不適切な日付は、1999年9月9日や1999年12月31日を選択したものです。

書式マスク

書式マスクは、日付を表示または格納する方法を決定します。書式マスクによって、日付値の日、月、年および時刻を表す方法を指定します。たとえば、1999年3月11日は、11-MAR-1999、03/11/1999または03/11/1999と表すことができます。

異なるマスクが明示的に設定されていないかぎり、デフォルトの書式マスク変数(NLS_DATE_FORMAT)が書式マスクを決定します。Oracle Applicationsは、NLS_DATE_FORMATをDD-MON-RRと設定します。

標準日付書式

日付を文字書式で格納する場合、標準日付書式と呼ばれる1つの標準書式を使用して混乱と非一貫性を防止します。

Oracle Applicationsは、日付が文字列で表される場合にはいつでも、標準日付書式としてYYYY/MM/DD HH24:MI:SS(時刻部分はオプション)を使用します。この書式は、ユーザーの言語とは独立であり、日付のソート順序を保ちます。

Oracle日付とユリウス日

Oracle日付(OraDates)は、紀元前4712年1月1日から西暦4712年12月31日までの範囲です。この日付は7バイトのバイナリ桁で表され、ユリウス日とも呼ばれます。Oracle日付の範囲は3,442,447日にわたります。したがって、紀元前4712年1月1日が第1日、西暦4712年12月31日が第3,442,447日となります。西暦1年1月1日はユリウス日では第1,721,424日です。Oracle日付は、年、月、日および時刻から構成されます。

Oracleデータベースは、その日付列において、またDATEデータ型を使用して日付を格納するときにはOracle日付を使用します。2000年対応が行われており、どのスタイルの日付にも容易にフォーマットできるため、このバイナリ書式で日付を格納することが、通常は最良の選択です。

Oracle日付は、SQL文、PL/SQLコードおよびPro*Cコードで使用されます。Pro*Cコードは、データ型12としてバイナリ配列をバインドしてOracle日付を使用します。Oracle日付はユーザーには表示されません。この書式は内部使用を意図しており、表示は意図していません。

Oracle Applicationsは紀元前の日付をサポートしていないため、ユリウス日が1,721,424より前の日付は使用しません。

明示的書式マスク

アプリケーションにおいて日付値は、日付タイプの列またはフィールドに格納するために、ユリウス日から文字列に、文字列からユリウス日に頻繁に変換する必要があります。たとえば、ファンクションTO_DATEおよびTO_CHARは、これらの変換をSQLとPL/SQLの両方で実行します。

SQLまたはPL/SQLで日付が文字列に変換される場合、次のように書式マスクを明示的に含めることができます。

to_char(my_date,'YYYY/MM/DD') 

開発者が書式マスクを指定していない場合は、システムはデフォルトの暗黙的書式マスクを使用します。

日付タイプの値を変換するときは、希望する書式を必ず明示的に指定します。これによって、正しい日付書式が使用され、状況依存変数による変換の失敗が起こらないようになります。

PL/SQL変数を使用してOracle FormsのDATEまたはDATETIMEフィールドからの値を保持する場合、次の例に示すとおりファンクションNAME_INを使用してその値にアクセスできます。

x_date_example := TO_DATE(NAME_IN('block.datetime_field'),

                                'DD-MON-YYYY HH24:MI:SS');

NAME_INファンクションは、すべての値をCHARとして戻します。したがって、DATEフィールドを扱う場合は、DATE書式からCHARに変換するマスクを明示的に提供する必要があります。ただし、Oracle Formsは日付に対して内部表現と表示表現を持っています。NAME_INを使用している場合は、内部表現にアクセスしています。さらに、NAME_INで日付にアクセスする際に次のマスクのみを使用します。

変数 説明
DATEフィールド: DD-MON-YYYY
DATETIMEフィールド: DD-MON-YYYY HH24:MI:SS

このマスクはDATEからCHARに変換するために内部でのみ使用されます。ユーザーに表示されているものからは影響を受けず、影響することもありません。この理由から、翻訳が重要な場合には使用する日付マスクの問題はありません。

DATEフィールドのマスクがMM/DD/YYYYであり、ユーザーに対して表示される日付が2/13/1995などとなっている場合には、内部的にはマスクDD-MON-YYYYにまだアクセスしています。通常、DATE変数に割り当てれば、内部マスクによって問題が生じることがなくなります。

DATEフィールドをCHAR変数に割り当て、これをCHARとして操作する場合には、翻訳の問題が生じる可能性があります。この場合は、DATEフィールドをまずDATE変数に割り当て、さらにこれをDD/MM/YYYYなどの翻訳可能なマスクを持つCHAR変数に割り当てます。

暗黙的書式マスク

希望する書式マスクを明示的に指定せずに日付タイプの値を文字列に変換する場合、暗黙的書式マスクが適用されます。この暗黙的書式マスクは、NLS_DATE_FORMATなどの環境設定によって決定されます。

to_char(my_date)

Oracle Applicationsの標準では、明示的書式マスクは必須です。

NLS_DATE_FORMAT変数

この環境変数が、暗黙的日付書式を通常決定します。Oracle Toolsでは、NLS_DATE_FORMATを使用して日付を検証、表示および印刷します。これらすべてのケースで、書式マスクを明示的に定義して上書き値を提供する必要があります。

OraDateとバイナリ日付

OraDateおよびバイナリ日付は、ユリウス日を使用してエンコードされています。

フレキシブル日付書式

Oracle Applicationsはフレキシブル日付サポートを提供しています。これによって、ユーザーの希望する書式でフォームの日付を表示できます。フレキシブル日付書式は、ユーザーが希望する方法で日付を表示する機能で、通常はユーザーの言語と地域に基づいて指定します。日付の表示は、世界でいくつかの異なる書式が存在しています。ある国ではDD-MON-YYYYを、また別の場所ではDD/MM/YYYYを使用します。Oracle Applicationsは、複数言語環境で日付を使用する機能も備えています。

アプリケーションを複数言語で稼働している場合には、そのアプリケーションの2人のユーザーが、それぞれ日付値を別の書式で使用することが可能です。フレキシブル日付は、各ユーザーに対し適切な日付値を表示します。

日付コーディング標準

Oracle Applicationsで日付が使用される際に適用される、日付コーディングのいくつかの原則があります。新規コードはすべてこれらの標準に従って作成します。

アプリケーション・フォーム開発時の日付の使用

NLS_DATE_FORMAT

若干の例外を除き、Oracle Toolsでは、NLS_DATE_FORMATを使用して日付を検証、表示および印刷します。これらのケースのすべてにおいて、コードから上書き値を提供できます。たとえば、書式マスクをOracle Formsの日付フィールドに関連付けることができます。この書式マスクは、入力の検証や、フォームでの日付表示に使用されます。

フォームとNLS_DATE_FORMAT

日付コーディング標準に従っている場合には、DD-MON-RRのNLS_DATE_FORMATはDD-MON-RRRRに拡張されます。

関連項目: APP_DATEとFND_DATE:日付変換API

Oracle Formsの日付拡張バージョン

Oracle Formsは、NLS_DATE_FORMATがデフォルトの書式マスクを設定する状況を区別するメカニズムを備えています。これには次のものがあります。

Oracle Formsにおける日付の長さ

日付フィールドの長さはすべて11または20です。プロパティ・クラス(TEXT_ITEM_DATEまたはTEXT_ITEM_DATETIME)がこれを自動的に設定します。

注意:フィールドが適切に設定されていないと、日付が不正に表示される場合があります。たとえば、「最大長」が11ではなく9である場合は、日付はDD-MON-YYYYではなくDD-MON-YYと自動的に表示されます。また、このフィールドにNAME_INファンクションを使用すると、日付拡張バージョンを使用しているかどうか、BUILTIN_DATE_FORMATを何に設定しているかに応じて、DD-MON-YYまたはDD-MON-RRと日付が戻されることになります。

「表示幅」は、インチ単位で表示幅を指定します。DATEフィールドでは1200(1.2インチ)、DATETIMEフィールドでは1700(1.7インチ)となります。

APPCOREライブラリのAPP_DATEルーチンの使用

フォーム・フィールドから日付を取得したり、フォーム・フィールドに日付を配置したりする場合は、適切なAPP_DATEルーチンを使用します。また、文字フィールドで日付を扱う場合はAPP_DATEルーチンを使用する必要があります。

関連項目: APP_DATEとFND_DATE:日付変換API

DECODEおよびNVLでの日付書式

暗黙的変換を避けるため、DECODEおよびNVLを使用する場合は日付書式を常に与えてください。書式を与えない場合は、コードが予期しているDATEタイプではなくCHAR値をファンクションが戻してくる可能性があります。日付書式を適切に与える例を次に示します。

DECODE(char_col,'<NULL>',to_date(null), to_date(char_col,'YYYY/MM/DD'))



NVL(to_date(null),to_date(char_col,'YYYY/MM/DD'))

明示的および暗黙的日付書式

日付を文字列に変換する際は常に明示的に書式を指定してください。NLS_DATE_FORMATのデフォルト値を決して受け入れないでください。変換には把握しにくいものがあります。文字列への変換は次のように暗黙的に行うことが可能です。

select sysdate into :my_char from dual

次の例では、明示的にTO_CHARを使用せずに日付タイプを文字に変換しています。

select to_char(sysdate, 'YYYY/MM/DD HH24:MI:SS') into :my_char

コーディングにおいてはどのようなタイプの暗黙的変換も避けてください。常に書式マスクを制御するようにします。暗黙的マスクの使用は、NLS_DATE_FORMAT変数が変更される場合には問題が発生します。暗黙的変換を使用すると、予期できない、処理を誤らせるコードが作成されます。

日付フィールド間のコピー

ハードコードされている日付値は、フィールドには直接コピーできません。

copy('01-FEB-2007', 'bar.lamb');

たとえばFEBといった月のセグメントは、言語ごとに異なるため、直接コピーすることは実用的でありません。そのかわり、次のようにコールすることが可能です。

app_item.copy_date('01-02-2007', 'bar.lamb');

このルーチンは、次のようにコピーを行います。

copy(to_char(to_date('01-01-2007', 'DD-MM-YYYY'),

             'DD-MON-YYYY'), 'bar.lamb');

NAME_INおよびCOPYファンクションが受け入れる書式は、DD-MON-YYYYのみです。これらのファンクションは何でもCHAR値であるかのように処理するため、日付値はすべてそのマスクにキャストします。

SYSDATEとUSER

Oracle Formsビルトイン・ルーチンであるSYSDATEとUSERのかわりに、次のようにApplicationsファンクションを使用します。

FND_STANDARD.SYSTEM_DATE  return DATE;
FND_STANDARD.USER   return VARCHAR2;

これらのファンクションはビルトインと同様に動作しますが、すでに別の場所でキャッシュされている情報を使用するため、より効率的です。

これらのFND_STANDARDファンクションは、Oracle Forms PL/SQLのコードでのみ使用してください。Oracle Formsビルトインは、SQL文、$$DBDATE$$デフォルトまたはストアド・プロシージャで使用できます。

トラブルシューティング

この項では、最もよく見られる問題のいくつかをリストします。該当する箇所では、これらの2000年対応問題を回避するコードを検証する方法も示します。

問題特定のためのDATECHECKスクリプトの使用

問題を特定するために、オラクル社の2000年Webサイト(www.oracle.com/year2000)で提供しているdatecheckスクリプトをまず実行します。その出力によって、問題の場所と種類の両方が特定されます。各問題についての指示は、次のチェック・リストを参照してください。

2000年問題および関連の問題:

翻訳された日付の問題:

クライアントの日付の問題:

テスト時に検出される問題

テストは、特に1999年12月31日、2000年1月1日、2000年1月3日、2000年2月29日、2000年12月31日、2001年1月1日などの問題のある日付の前後について行うことをお薦めします。

問題が2000年に関連しているかどうかの判定

2000年バグについてオラクル社は、世紀越え、またはうるう年によって生じる不具合と定義しています。2000年バグの特徴は次のとおりです。

日付チェック・リスト

2000年問題

次に2000年問題を示します。

DE-1。TO_DATEとともにDD-MON-YYを使用

TO_DATEの正しい構文は次のとおりです。

my_char_date  varchar2(9);

...

TO_DATE(my_char_date,'DD-MON-RR')

次の構文は使用しないでください。

TO_DATE(my_char_date,'DD-MON-YY') [WRONG]

TO_DATE(my_char_date) [WRONG - NO FORMAT MASK]



Oracle ReportsパラメータとともにDD-MON-YYマスクを使用: レポートにあるDD-MON-YYのマスクが、入ってくる文字列パラメータを誤って変換します。DD-MON-RRまたはDD-MON-RRRRのマスクを使用すると、2000年対応の面から正しい動作をするようになります。たとえば、次のように指定します。

MYREPORT.rex: INPUT_MASK = <<"DD-MON-RR">> MYREPORT.rex: INPUT_MASK = <<"DD-MON-RRRR">> 

うるう年問題: YYをTO_DATEで使用すると、うるう年に特定の問題が生じます。文字の日付値をすべて基準書式に変換することをお薦めしますが、その理由を次の例で示します。このように、2000年問題は把握しにくい問題です。

my_char_date = to_char(to_date(my_char_date,'DD-MON-YY'), 'DD-MON-YY')

この冗長な構文はわかりにくいものですが、文字による日付がDD-MON-YY書式であるかぎり、不正な世紀は即座に切捨てが行われるため、コードは機能するかのように見えます。

しかし、日付が29-FEB-00となると、このコードはエラーとなります。2000年はうるう年ですが、1900年はうるう年ではありません。DD-MON-YYとともに使用されるTO_DATEは、00を1900と解釈し、これによりエラーが発生します。

DE-2。参照日として1999年から2049年の日付を使用

ハードコードされた参照日に対してチェックを行う場合、1999年から2049年の日付は使用しないでください。たとえば、プラスの無限大として不正な日付を使用している次のコードは、1999年12月31日にエラーとなります。

my_date date;

your_date date;

       ...

NVL(my_date,to_date('12/31/1999',DD/MM/YYYY)) =

                NVL(your_date,

                to_date('12/31/1999',DD/MM/YYYY) [WRONG]

そのかわりに、到達することが真に不可能な日付を使用します。

NVL(my_date, to_date('01/01/1000',DD/MM/YYYY)) =

                NVL(your_date, to_date('01/01/1000',DD/MM/YYYY)

DE-3。2桁の年でDD-MON-YYYYを使用

9文字からなる文字列として格納された日付をDD-MON-YYYYなどの11桁のマスクを使用している日付に変換する場合、日付は1世紀に戻ってしまいます。たとえば、次のような場合です。

my_rr_date  varchar2(9);

my_date date;

my_date2 date;

             ...

my_date2 := to_date(my_rr_date,'DD-MON-YYYY') [WRONG]

my_rr_date変数に格納された日付が、ここでmy_date2に1世紀の日付として格納されます。my_rr_dateが30-OCT-99ならば、my_date2は30-OCT-0099となってしまいます。

my_rr_dateが2000年の日付である場合には、コードはこの日付を、存在しない西暦0年の日付に移動してしまいます。Oracle Error ORA-01841がこの種のエラーを警告します。

これらの問題を回避するには、不必要なTO_DATE変換を避けるか、DD-MON-RRマスクを使用して日付を変換します(TO_DATEが必須の場合)。

my_date2 := my_date my_date2 := to_date(my_rr_date,'DD-MON-RR')



暗黙的変換: 日付タイプ値にTO_DATEを実行することによって、この種の思いがけない変換が生じる場合があります。これは、SQLまたはサーバー側PL/SQLでのみ生じます。SQLでは、日付タイプにTO_DATEを実行すると、TO_DATEが文字の引数を必要とするためその値にTO_CHARを暗黙的に実行します。TO_CHARは、9桁の書式マスク(DD-MON-YY)を使用して実行され、これにより前述の問題が引き起こされます。この問題は、Cプログラム、SQL*Forms 2.3コード、Developer 2000の動的SQLなど、サーバー側PL/SQLで発生します。

select to_date(my_date,'DD-MON-YYYY')... [WRONG]

そのかわりに、不必要な変換を次のように避けます。

select my_date...

同様の思いがけない変換は、NVLおよびDECODEを不注意に使用しても起こる場合があります。NVLまたはDECODEが日付のかわりに文字を返す場合、返された値を日付に変換してこのエラーを修正することから、次のような1世紀となってしまうエラーが生じる場合があります。

to_date(DECODE(char_col,'<NULL>',null,sysdate),

        'DD-MON-YYYY') [WRONG]

to_date(NVL(null,sysdate),'DD-MON-YYYY')  [WRONG]

そのかわりに、返される値が日付タイプとなるように指定します。

DECODE(char_col,'<NULL>',to_date(null),sysdate)

NVL( to_date(null),sysdate)

ORA-1841問題: 2000年において、日付が1世紀のものに変換されてしまうことは、そのまま問題を引き起こします。2000年にある日付に対しては、1世紀にはそれに相当する日付がありません(西暦0年は存在しません)。コードによって日付が西暦0年のものに変換された場合、エラー「ORA-01841: (4桁の)年は-4713年から+9999年の範囲にある必要があり、0であってはなりません」が発生します。

比較問題: また、日付値を比較している際に、日付が1世紀のものに変換されると、世紀の境界を超えた比較での問題が引き起こされます。DD-MON-RR書式では01-JAN-99は01-JAN-01より前の日付ですが、日付が思いがけなく1世紀に移動させられていると、01-JAN-0099は01-JAN-0001より後の日付となります。

DE-4。ハードコードされた任意の日付マスクをフォーム・フィールドに関連付け

標準日付フィールドはマスクDD-MON-RRRRを使用しているため、ハードコードされたマスクが関連付けられているOracle Formsのフィールドはすべて不正に動作します。

リリース12では、フレキシブル日付書式によって、環境別に異なる書式を使用することが可能になっています。

DE-5。2桁の年で1950年より前の日付を使用

Oracle Applicationsでは、デフォルト日付マスクとしてDD-MON-RRマスクが使用されています。世紀の情報が欠落している場合、デフォルトのコードが、その日付が1950年から2049年のものであると想定します。

2桁の年で格納された、1950年より前のハードコードされた日付は、誤って解釈されます。1900年から1949年の4桁の年(明示的書式マスクを使用)でハードコードされた日付は、日付が世紀の情報なしに格納(通常、DD-MON-RR文字列で格納されたことを意味)された場合にのみ不正となります。この時点でのほとんどの問題は、Cコードまたはコンカレント・プログラムの引数でのものですが、PL/SQLで生じる場合もあります。

新規のすべてのコードで、標準のマイナスおよびプラスの無限大日付を使用してください。SQLとPL/SQLでは、世紀の情報が失われていないことを確認することも、もちろん必要です。

たとえば、コードの断片to_date('01-JAN-00')は2000年1月1日と解釈されますが、一方、コードの断片to_date('01/01/1000', 'DD/MM/YYYY)はあいまいにはなりません。

翻訳された日付の問題

これらの問題は、複数言語環境で機能する必要のあるすべての日付に影響します。Oracle Applicationsリリース12は複数の言語で実行できます。また、複数の日付書式をサポートしています。

TD-1。ハードコードされた英語の月名

英語の月名は他の言語では機能しません。かわりに数値の月を使用します。

TO_DATE('1000/01/01','YYYY/MM/DD')

次のようにはしないでください。

TO_DATE('01-JAN-1000','DD-MON-YYYY') [WRONG]

TD-2。英語の曜日名または序数でのNEXT_DAY

next_dayコールは、ハードコードされた英語の曜日(MONなど)渡す場合には翻訳できません。ただし、地域によってどの曜日にどの数を割り振るかがまちまちであるため、ハードコードされた序数(1など)で渡すことも不正確です。

現在わかっている日付(たとえば11/3/1997は月曜)を使用して、現在の言語での3文字の曜日が何曜日かを決定して、それを渡します。

next_day(my_date,to_char(to_date('1997/03/11',

'YYYY/MM/DD'),'DY'))

クライアントの日付の問題

次にクライアントの日付の問題を示します。

クライアントの日付の問題 - CD-1。クライアントから日付を取得

これらの問題は、プログラムがデータベースからではなくクライアントのマシン(スマート・クライアント・リリースのPC)から現在の曜日と時間を取得することによって引き起こされます。データベースを使用するようにしてください。PCベンダーとMicrosoft社のいずれも2000年対応を保証していないため、Oracle Applicationsは現在のところサーバーからすべての現在時間を取得しています。

$$DATE$$を使用して現在の日付をFormsのフィールドにデフォルト指定しないでください。クライアント日付が取得されてしまいます。そのかわりに、データベース日付を取得する$$DBDATE$$ビルトインを使用します。さらによい方法としては、FND_STANDARD.SYSTEM_DATEを使用してWHEN-CREATE-RECORDまたはWHEN-NEW- FORM-INSTANCEにおいて日付をプログラム的にデフォルト指定することです。$$DATE$$の使用は、キャラクタ・モードでは問題ではありません(SYSTEM_DATEコールと類似のコードを使用しています)。