正規表現を使って、日付っぽい文字列をそれらしくdatetimeに押し込める

さくらインターネットのさくらのブログで驚いたのは、エントリーの公開日時を設定する際、ユーザーに日付をテキストで入力させるというところでした。私の常識では、ユーザーに直接入力させるなんて、危険極まりないからしてはならない。2009-03-15 12:15:00と入力してほしいのに、想像を絶するような、ありえない文字列を投げ込まれたりする。ところがさくらのブログでは、ユーザーに文字列として日付時刻を入力させるのです。驚いて、そして今はもうネットでブログなんてやろうというユーザーになると、これくらいの要求には軽く応えられるのだと、そういう時代になったことを理解したのでした。

というわけで、私の作っているK-enq.tdでも、日付時刻の設定は、ユーザーに文字列として入力してもらうことにしました。

で、それを正規表現でばらして、datetimeに押し込んで、datetime型のオブジェクトにしようと思って、試しに正規表現を書いてみました。それが以下のものです。

import re
import datetime

redt = re.compile(u'(\d{4})\D?([01]?\d)\D?([0-3]?\d)\D?([0-2]?\d?)\D?([0-5]?\d?)\D?([0-5]?\d?)')
def strtdatetime(string):
    if isinstance(string, basestring):
        m = redt.match(string)
        if m is None:
            return u''
        else:
            l = [2001, 01, 01, 00, 00, 00]
            for i in range(len(m.groups())):
                try:
                    l[i] = int(m.group(i + 1))
                except ValueError:
                    l[i] = 00
        return datetime.datetime(l[0], l[1], l[2], l[3], l[4], l[5])
    else:
        return u''

最終的に、これはなんらかのクラスのメソッドにする予定ですが、今はまだただの関数です。日付時刻を表現する文字列を受け取って、それをdatetimeオブジェクトにして返します。もし文字列が不正、つまり正規表現にマッチしなかったら、長さ0の文字列を返します。場合によってはdatetime.datetime.today()を返してもいいのかも知れないけど、今作ってるシステムでは、開始日および終了日がブランクになることもあるから、長さ0の文字列を返すようにしています。

これ、実験してみたところ、それっぽく働いてくれて、区切り文字は数字以外ならなんでもいいっていい加減さだから、2009/03/15でも大丈夫。20090315みたいにしても、適当にばらしてくれます。まあ、いい加減なものなので、誤動作誤判定はいくらでもあるでしょうが、それは気にしないことにします。