c:\Users\じぶん

技術ネタ半分、日記半分ですかね。

Oracleの日付変換トラブル(その後)

一つ前の記事、Oracleの日付型変換トラブルについて、最後に書いたとおりプログラムを書き換えで凌いだのですが、もともと動いていたプログラムにバグが潜んでいた事に気づいたのでさらに掘り下げます。

環境A(NLS_DATE_FORMATなし…RR-MM-DD変換)では、以下が通ったと書きました。

 hensu := to_date(hiduke,'YYYY/MM/DD');

これはつまり、日付型変数hidukeの中身が「2015/01/01」だとすると

 hensu := to_date('15-01-01','YYYY/MM/DD');

ということになります、これはエラーになりません。 そこで、実際にhensuに入っている値を見てみましょう。 SQL*PLUSで接続して試します。

select to_date('15-01-01','YYYY/MM/DD') from dual;
↓
15-01-01

問題なさそうですが、西暦を全て表示させてみましょう。

select to_char(to_date('15-01-01','YYYY/MM/DD')',YYYY/MM/DD') from dual;
↓
0015/01/01

ん??0015??西暦15年??これは…弥生時代ですね(-_-;) このロジック、先の記事では「通ってた」と書きましたけど、実は2000年前の日付が入っていたようです、これはマズイ。ずっと弥生時代の計算をしていたのでしょうか…。解析すると後続で以下のようにSQL中で変数が使われていました。

where hiduke2 < TO_DATE(hensu)

また日付型から日付型に変換してました(んなアホな…)。これはつまり、

where hiduke2 < TO_DATE(to_char(hensu))

であり、さらに展開すると

where hiduke2 < TO_DATE(to_char(hensu,'RR-MM-DD'))

これをhensuが西暦15年1月1日の弥生時代だとすれば、

where hiduke2 < TO_DATE('15-01-01')

と解釈されます、これは暗黙変換され、実際には

where hiduke2 < TO_DATE('15-01-01','RR-MM-DD')

ですから…

where hiduke < [2015年1月1日]

ですね。つまり、一時的に変数が弥生時代にタイムスリップしましたが、使う段階で現代に戻ってきたわけです。

代入値が西暦15年と気づいたときには背筋がゾッとしましたが、影響はなさそうです。ですが、これは「たまたま」うまく動いているだけで、日付型を日付型に変換している時点でダメダメですねぇ。

ちなみに、しれっと「RR-MM-DD」とか書いてますが、「RR」は2000年問題対応版の年(YYYYやYY)書式で、システム日付が2049年になるまでは、50~99は1950年から1999年を指し、00~49は2000年から2049年を指すと振り分ける機能を持ちます。なので、あまりオススメはしませんが年を2桁で表現したいときはYYではなくRRを使うようにしましょう。(RRRRも通ります)

オラクルマスター教科書 Bronze Oracle Database DBA12c

オラクルマスター教科書 Bronze Oracle Database DBA12c