PREPARATION
受験対策

オススメ!OSS-DB情報

第17回 日付の計算

数値の四則演算は、直感的な表記を使って、ほとんどのプログラミング言語で同じ形式で記述できますが、日時や期間の計算はそうはいきません。
例えば、aの3倍の値は a * 3 とすれば得られますが、ある日付の3日後、あるいは3ヶ月後の日付を求めたいと思った時、どのような計算式を記述する必要があるかは言語によって異なります。
また、日付というデータ型や日付計算の仕掛けが言語の処理系自体にはなく、ライブラリ関数などの呼び出しによって実現することも多いです。
多くのデータベースでは、+ あるいは - の記号を使って、ある日付の前後の日付を求めることができますが、その差分となる期間の表現方法はデータベースの種類によって異なります。また、RDBMSの種類によっては、関数呼び出しが必要なこともあります。
以下、PostgreSQLを前提に解説します。

まずは、検証用のテーブルを作りましょう。例えば、
create table test_date(id integer, dt1 date, dt2 date);
insert into test_date values(1, '2012-02-28', '2012-03-30');
insert into test_date values(2, '2011-02-28', '2011-03-30');
とします。必要に応じて列や行を自由に追加してください。

日付と数値の足し算、引き算は、数値が日数を表すものと見なされます。例えば、
select id, dt1 + 90, dt2 - 30 from test_date;
とすれば、dt1の90日後、およびdt2の30日前の日付が得られます。

日付と日付の間で引き算をすると、その間の日数が返されます。例えば
select id, dt2 - dt1 from test_date;
とすると、dt1の何日後がdt2になるのかがわかります。

いずれの例でも、うるう年が正しく処理されていることがわかるでしょう。

ある日付の90日後の日付を求めたい、などという場合はこれで良いですが、では3ヶ月後の日付を求めたい、という場合はどうすれば良いでしょうか。
PostgreSQLでは期間をINTERVAL型を使って表します。3ヶ月という定数を表記する方法はいくつかありますが標準的には
INTERVAL '3 MONTH'
と記述します。先頭のINTERVALは、その後の文字列をINTERVAL型として扱うように指示するもので、その後に文字列で期間を記述します。
INTERVAL, MONTHはいずれも大文字でも小文字でも構いませんが、'3 MONTH'の部分は必ず引用符で括らなければなりません。
というわけで、dt1の3ヶ月後、dt2の1ヶ月前の日付を求めるためには、
select id, dt1 + interval '3 month', dt2 - interval '1 month' from
test_date;
とします。

では、2つの日付の間の期間を年月で表すにはどうしたら良いでしょうか。例えば、生年月日と今日の日付から満年齢を求めたい、ということは多いですね。
単純に日付の差分を取ると日数が返りますが、それを365で割り算するとうるう年が考慮されないので、正しい年齢が得られなくなります。
PostgreSQLにはage()という関数があり、これを使うと、2つの日付の間の期間をINTERVAL型にして返してくれます。例えば、
select id, age(current_date, dt1) from test_date;
とすると、dt1と今日の間の期間が年月日を単位にして返されます。満年齢を知りたい時は、このうち年の部分だけが必要ですが、そのためにはextract()(あるいはdate_part())という関数を使います。つまり
select id, extract(year from age(current_date, dt1)) from test_date;
とすると、dt1から今日までの間に何年が経過したかがわかります。

PostgreSQLにおける日付データの表記や計算についての詳細は、マニュアルの以下の節を参照してください。
http://www.postgresql.jp/document/current/html/datatype-datetime.html
http://www.postgresql.jp/document/current/html/functions-datetime.html

日付データの取り扱い、計算方法についてはデータベースの種類によって大きく異なります。
日付と日数の足し算と引き算は + と - を使ってできるものが多いですが、DATEADD, DATE_ADD, ADDDATE などという独自関数を使うものもあります。
日付と日付の引き算による日数計算も同様で、DATEDIFFなどの独自関数を使わないと正しく計算できないものもあります。

期間を定数として表す方法は、データベースの種類による違いが大きく、PostgreSQLでは上で説明したように
INTERVAL '3 MONTH'
とすれば3ヶ月の意味になりますが、Oracleでは
INTERVAL '3' MONTH
MySQLでは
INTERVAL 3 MONTH
と表記します。
引用符の有無と場所が微妙に違うだけですが、違う表記だとエラーになるので注意が必要です。また、MONTHをMONTHSと複数形にしたとき、PostgreSQLやDB2では問題なく処理されますが、OracleやMySQLではエラーになります。

上の例では、3月30日の1ヶ月前の日付を引き算で計算しました。PostgreSQLやMySQLではこの結果が2月末日になりますが、Oracleではエラーとなるので、ADD_MONTHS()という独自関数を使う必要があります。

また、2つの日付の間の期間を年月日で求めるのに使ったAGE()関数はPostgreSQL独自のものですが、同様の機能の関数が他のデータベースにあるとは限らないようです。この場合は、求める機能にあったユーザ関数を作成することになります。

解説:松田神一

LPI-Japan
Platinum Sponsors

関連資格