やっぱり、適当はだめだ

昨日、d:id:imait:20090315:1237122752にて、正規表現を使って適当に日付時刻の文字列をdatetimeに押し込むなんていってましたけど、やっぱり適当、いい加減はだめですね。昨日の例では、0000年0月0日を通してしまうので、ValueErrorを引き起してしまうし、さらに3333年3月33日とかも通してしまうので、当然ValueErrorが出る。いい加減な仕事をしていては駄目だ、本当にそう思いました。

ちゃんとやるなら、正規表現でばらした日付時刻が適切かどうか、きちんと確認すべきなんでしょう。Pythonのドキュメント、http://www.python.jp/doc/release/lib/datetime-datetime.htmlにもありますが、各値が範囲に収まっているか、きちんとチェックする必要がありそうです。

  • MINYEAR <= year <= MAXYEAR
  • 1 <= month <= 12
  • 1 <= day <= 与えられた年と月における日数
  • 0 <= hour < 24
  • 0 <= minute < 60
  • 0 <= second < 60
  • 0 <= microsecond < 1000000

http://www.python.jp/doc/release/lib/datetime-datetime.html

そういえば、日付時刻を扱っているところは他にもあって、strftime('%Y-%m-%d %H:%M:%S')で生成した日付時刻の文字列を、strptime(date_string, '%Y-%m-%d %H:%M:%S')でdatetimeオブジェクトにもどしているのがひとつ、そしてisoformat(' ')で生成したものを、次のようにしてdatetimeにもどしているのがもうひとつ:

cd = re.split('[\-\s:\.]', created_date)
created_date = datetime.datetime(int(cd[0]), \
                                 int(cd[1]), \
                                 int(cd[2]), \
                                 int(cd[3]), \
                                 int(cd[4]), \
                                 int(cd[5]), \
                                 int(cd[6]))

けどこれにも問題がありそうで、isoformatが常に期待どおりの文字列を生成するかどうかわからないという問題があります。私は、isoformat(' ')がYYYY-MM-DD HH:MM:SS.mmmmmmという文字列を生成することを期待していますが、ドキュメントを見ればmicrosecond が 0 の場合には YYYY-MM-DDTHH:MM:SS で表した文字列が返されるとあります。もし万が一、マイクロセカンド単位でジャストのタイミングでdatetimeオブジェクトが作られた場合には、やっぱりYYYY-MM-DD HH:MM:SSになるんでしょうね。でもこれでは困るわけです。

なので、上の例ではリストcdの長さをチェックして、6が返ってくるようなら、cd.append('000000')とするようにした方がいいのかも知れません。

if len(cd) == 6:
    cd.append('000000')

あと気掛りなのは、タイムゾーンがついてたらややこしいかなって。これもちゃんと確認して、末尾に+HH:MMがついてる場合には切り落とすみたいにした方がいいのかもしれません。

具体的にどうするかは、また今度考えます。